feat(provider): new deployment provider: cmcccloud vlb

This commit is contained in:
Fu Diwei
2026-06-22 16:32:18 +08:00
committed by RHQYZ
parent 9eba19978d
commit 33c871b3ed
19 changed files with 1244 additions and 15 deletions
+6 -1
View File
@@ -88,7 +88,8 @@ require (
gitlab.ecloud.com/ecloud/ecloudsdkcloudcore v1.0.0
gitlab.ecloud.com/ecloud/ecloudsdkclouddns v1.0.1
gitlab.ecloud.com/ecloud/ecloudsdkcmcdn v1.0.0
gitlab.ecloud.com/ecloud/ecloudsdkcore v1.0.2
gitlab.ecloud.com/ecloud/ecloudsdkcore v1.0.6
gitlab.ecloud.com/ecloud/ecloudsdkvlb v1.0.7
golang.org/x/crypto v0.52.0
golang.org/x/oauth2 v0.36.0
golang.org/x/sync v0.20.0
@@ -297,3 +298,7 @@ replace gitlab.ecloud.com/ecloud/ecloudsdkclouddns v1.0.1 => ./pkg/sdk3rd-forked
replace gitlab.ecloud.com/ecloud/ecloudsdkcmcdn v1.0.0 => ./pkg/sdk3rd-forked/gitlab.ecloud.com/ecloud/ecloudsdkcmcdn@v1.0.0
replace gitlab.ecloud.com/ecloud/ecloudsdkcore v1.0.2 => ./pkg/sdk3rd-forked/gitlab.ecloud.com/ecloud/ecloudsdkcore@v1.0.2
replace gitlab.ecloud.com/ecloud/ecloudsdkcore v1.0.6 => ./pkg/sdk3rd-forked/gitlab.ecloud.com/ecloud/ecloudsdkcore@v1.0.6
replace gitlab.ecloud.com/ecloud/ecloudsdkvlb v1.0.7 => ./pkg/sdk3rd-forked/gitlab.ecloud.com/ecloud/ecloudsdkvlb@v1.0.7
@@ -0,0 +1,30 @@
package deployers
import (
"fmt"
"github.com/certimate-go/certimate/internal/domain"
"github.com/certimate-go/certimate/pkg/core"
dplyimpl "github.com/certimate-go/certimate/pkg/core/deployer/providers/cmcccloud-vlb"
xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
)
func init() {
Registries.MustRegister(domain.DeploymentProviderTypeCMCCCloudVLB, func(options *ProviderFactoryOptions) (core.Deployer, error) {
credentials := domain.AccessConfigForCMCCCloud{}
if err := xmaps.Populate(options.ProviderAccessConfig, &credentials); err != nil {
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
}
provider, err := dplyimpl.NewDeployer(&dplyimpl.DeployerConfig{
AccessKeyId: credentials.AccessKeyId,
AccessKeySecret: credentials.AccessKeySecret,
PoolId: xmaps.GetString(options.ProviderExtendedConfig, "poolId"),
DeployTarget: xmaps.GetString(options.ProviderExtendedConfig, "deployTarget"),
LoadbalancerId: xmaps.GetString(options.ProviderExtendedConfig, "loadbalancerId"),
ListenerId: xmaps.GetString(options.ProviderExtendedConfig, "listenerId"),
Domain: xmaps.GetString(options.ProviderExtendedConfig, "domain"),
})
return provider, err
})
}
+1
View File
@@ -358,6 +358,7 @@ const (
DeploymentProviderTypeCdnfly = DeploymentProviderType(AccessProviderTypeCdnfly)
DeploymentProviderTypeCloudflareSSL = DeploymentProviderType(AccessProviderTypeCloudflare + "-ssl")
DeploymentProviderTypeCMCCCloudCDN = DeploymentProviderType(AccessProviderTypeCMCCCloud + "-cdn")
DeploymentProviderTypeCMCCCloudVLB = DeploymentProviderType(AccessProviderTypeCMCCCloud + "-vlb")
DeploymentProviderTypeCPanel = DeploymentProviderType(AccessProviderTypeCPanel)
DeploymentProviderTypeCTCCCloudAO = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-ao")
DeploymentProviderTypeCTCCCloudCDN = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-cdn")
@@ -35,9 +35,9 @@ type Config struct {
AccessKey string
SecretKey string
TTL int
PropagationTimeout time.Duration
PollingInterval time.Duration
TTL int
ReadTimeout int
ConnectTimeout int
}
@@ -52,11 +52,11 @@ type DNSProvider struct {
func NewDefaultConfig() *Config {
return &Config{
ReadTimeout: env.GetOrDefaultInt(EnvReadTimeout, 30),
ConnectTimeout: env.GetOrDefaultInt(EnvConnectTimeout, 30),
TTL: env.GetOrDefaultInt(EnvTTL, 600),
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 10*time.Minute),
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
ReadTimeout: env.GetOrDefaultInt(EnvReadTimeout, 30),
ConnectTimeout: env.GetOrDefaultInt(EnvConnectTimeout, 30),
}
}
@@ -79,10 +79,8 @@ func NewDNSProviderConfig(cfg *Config) (*DNSProvider, error) {
}
client := ecloudsdkclouddns.NewClient(&config.Config{
AccessKey: cfg.AccessKey,
SecretKey: cfg.SecretKey,
// 资源池常量见: https://ecloud.10086.cn/op-help-center/doc/article/54462
// 默认全局
AccessKey: cfg.AccessKey,
SecretKey: cfg.SecretKey,
PoolId: "CIDC-CORE-00",
ReadTimeOut: cfg.ReadTimeout,
ConnectTimeout: cfg.ConnectTimeout,
@@ -92,7 +92,7 @@ func (c *Certmgr) Upload(ctx context.Context, certPEM, privkeyPEM string) (*Uplo
// 对比证书内容
getCertDetailResp, err := c.sdkClient.GetCertRawData(certItem.CertId)
c.logger.Debug("sdk request 'cert.GetCertRawData'", slog.Any("certId", certItem.CertId), slog.Any("response", getCertDetailResp))
c.logger.Debug("sdk request 'cert.GetCertRawData'", slog.String("params.certId", certItem.CertId), slog.Any("response", getCertDetailResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'cert.GetCertRawData': %w", err)
} else {
@@ -0,0 +1,156 @@
package cmcccloudvlb
import (
"context"
"fmt"
"log/slog"
"time"
"github.com/samber/lo"
"gitlab.ecloud.com/ecloud/ecloudsdkcore/config"
"gitlab.ecloud.com/ecloud/ecloudsdkvlb/model"
"github.com/certimate-go/certimate/pkg/sdk3rd-trimmed/gitlab.ecloud.com/ecloud/ecloudsdkvlb"
"github.com/certimate-go/certimate/pkg/core"
xcert "github.com/certimate-go/certimate/pkg/utils/cert"
)
type (
Provider = core.Certmgr
UploadResult = core.CertmgrUploadResult
ReplaceResult = core.CertmgrReplaceResult
)
type CertmgrConfig struct {
// 移动云 AccessKeyId。
AccessKeyId string `json:"accessKeyId"`
// 移动云 AccessKeySecret。
AccessKeySecret string `json:"accessKeySecret"`
// 移动云资源池 ID。
PoolId string `json:"poolId"`
// 是否是 SNI 证书。
IsSNI bool `json:"isSni,omitempty"`
}
type Certmgr struct {
config *CertmgrConfig
logger *slog.Logger
sdkClient *ecloudsdkvlb.Client
}
var _ Provider = (*Certmgr)(nil)
func NewCertmgr(config *CertmgrConfig) (*Certmgr, error) {
if config == nil {
return nil, fmt.Errorf("the configuration of the certmgr provider is nil")
}
client, err := createSDKClient(config.AccessKeyId, config.AccessKeySecret, config.PoolId)
if err != nil {
return nil, fmt.Errorf("could not create client: %w", err)
}
return &Certmgr{
config: config,
logger: slog.Default(),
sdkClient: client,
}, nil
}
func (c *Certmgr) SetLogger(logger *slog.Logger) {
if logger == nil {
c.logger = slog.New(slog.DiscardHandler)
} else {
c.logger = logger
}
}
func (c *Certmgr) Upload(ctx context.Context, certPEM, privkeyPEM string) (*UploadResult, error) {
// 解析证书内容
certX509, err := xcert.ParseCertificateFromPEM(certPEM)
if err != nil {
return nil, err
}
// 查询弹性负载均衡证书列表,避免重复上传
// REF: https://ecloud.10086.cn/op-help-center/doc/article/97613
// REF: https://ecloud.10086.cn/op-help-center/doc/article/97399
listLoadbalanceCertificationResp, err := c.sdkClient.ListLoadbalanceCertificationResp()
c.logger.Debug("sdk request 'vlb.ListLoadbalanceCertification'", slog.Any("response", listLoadbalanceCertificationResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'vlb.ListLoadbalanceCertification': %w", err)
} else {
if listLoadbalanceCertificationResp.Body != nil && listLoadbalanceCertificationResp.Body.Content != nil {
for _, certItem := range *listLoadbalanceCertificationResp.Body.Content {
// 对比证书有效期
oldCertNotAfter, _ := time.Parse(time.DateTime, lo.FromPtr(certItem.ExpirationTime))
if !certX509.NotAfter.Equal(oldCertNotAfter) {
continue
}
// 对比证书内容
getLoadbalanceCertificationDetailReq := &model.GetLoadbalanceCertificationDetailRespRequest{
&model.GetLoadbalanceCertificationDetailRespPath{
ContainerUuid: certItem.Id,
},
}
getLoadbalanceCertificationDetailResp, err := c.sdkClient.GetLoadbalanceCertificationDetailResp(getLoadbalanceCertificationDetailReq)
c.logger.Debug("sdk request 'vlb.GetLoadbalanceCertificationDetail'", slog.Any("request", getLoadbalanceCertificationDetailReq), slog.Any("response", getLoadbalanceCertificationDetailResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'vlb.GetLoadbalanceCertificationDetail': %w", err)
} else {
if !xcert.EqualCertificatesFromPEM(certPEM, lo.FromPtr(getLoadbalanceCertificationDetailResp.Body.PublicKey)) {
continue
}
}
// 如果以上信息都一致,则视为已存在相同证书,直接返回
c.logger.Info("ssl certificate already exists")
return &UploadResult{
CertId: lo.FromPtr(certItem.Id),
CertName: lo.FromPtr(certItem.Name),
}, nil
}
}
}
// 生成新证书名(需符合移动云命名规则)
certName := fmt.Sprintf("certimate_%d", time.Now().UnixMilli())
// 创建弹性负载均衡证书
// REF: https://ecloud.10086.cn/op-help-center/doc/article/97397
createLoadbalanceCertificationReq := &model.CreateLoadbalanceCertificationRequest{
&model.CreateLoadbalanceCertificationBody{
Name: lo.ToPtr(certName),
Type: lo.ToPtr(lo.Ternary(c.config.IsSNI, model.CreateLoadbalanceCertificationBodyTypeEnumSni, model.CreateLoadbalanceCertificationBodyTypeEnumServer)),
Description: lo.ToPtr("upload from certimate"),
PublicKey: lo.ToPtr(certPEM),
PrivateKey: lo.ToPtr(privkeyPEM),
},
}
createLoadbalanceCertificationResp, err := c.sdkClient.CreateLoadbalanceCertification(createLoadbalanceCertificationReq)
c.logger.Debug("sdk request 'vlb.CreateLoadbalanceCertification'", slog.Any("request", createLoadbalanceCertificationReq), slog.Any("response", createLoadbalanceCertificationResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'vlb.CreateLoadbalanceCertification': %w", err)
}
return &UploadResult{
CertId: lo.FromPtr(createLoadbalanceCertificationResp.Body),
CertName: certName,
}, nil
}
func (c *Certmgr) Replace(ctx context.Context, certIdOrName string, certPEM, privkeyPEM string) (*ReplaceResult, error) {
return nil, core.ErrUnsupported
}
func createSDKClient(accessKeyId, accessKeySecret, poolId string) (*ecloudsdkvlb.Client, error) {
client := ecloudsdkvlb.NewClient(&config.Config{
AccessKey: &accessKeyId,
SecretKey: &accessKeySecret,
RegionId: &poolId,
})
return client, nil
}
@@ -0,0 +1,53 @@
package cmcccloudvlb_test
import (
"testing"
"github.com/certimate-go/certimate/pkg/core/certmgr/internal/tester"
impl "github.com/certimate-go/certimate/pkg/core/certmgr/providers/cmcccloud-vlb"
)
var (
fp = tester.Args("CMCCCLOUDVLB_")
fTestCertPath string
fTestKeyPath string
fAccessKeyId string
fAccessKeySecret string
fPoolId string
)
func init() {
fp.DefineString(&fTestCertPath, "TESTCERTPATH")
fp.DefineString(&fTestKeyPath, "TESTKEYPATH")
fp.DefineString(&fAccessKeyId, "ACCESSKEYID")
fp.DefineString(&fAccessKeySecret, "ACCESSKEYSECRET")
fp.DefineString(&fPoolId, "POOLID")
}
/*
Shell command to run this test:
go test -v ./cmcccloud_vlb_test.go -args \
--CMCCCLOUDVLB_TESTCERTPATH="/path/to/your-test-cert.pem" \
--CMCCCLOUDVLB_TESTKEYPATH="/path/to/your-test-key.pem" \
--CMCCCLOUDVLB_ACCESSKEYID="your-access-key-id" \
--CMCCCLOUDVLB_ACCESSKEYSECRET="your-access-key-secret" \
--CMCCCLOUDVLB_POOLID="CIDC-RP-29"
*/
func TestProvider(t *testing.T) {
fp.Parse()
t.Run("Upload", func(t *testing.T) {
provider, err := impl.NewCertmgr(&impl.CertmgrConfig{
AccessKeyId: fAccessKeyId,
AccessKeySecret: fAccessKeySecret,
PoolId: fPoolId,
})
if err != nil {
t.Errorf("err: %+v", err)
return
}
tester.TestUpload(t, provider, tester.TestUploadArgs{CertPath: fTestCertPath, KeyPath: fTestKeyPath})
})
}
@@ -0,0 +1,310 @@
package cmcccloudvlb
import (
"context"
"errors"
"fmt"
"log/slog"
"github.com/samber/lo"
"gitlab.ecloud.com/ecloud/ecloudsdkcore/config"
"gitlab.ecloud.com/ecloud/ecloudsdkvlb/model"
"github.com/certimate-go/certimate/pkg/sdk3rd-trimmed/gitlab.ecloud.com/ecloud/ecloudsdkvlb"
"github.com/certimate-go/certimate/pkg/core"
cmgrimpl "github.com/certimate-go/certimate/pkg/core/certmgr/providers/cmcccloud-vlb"
)
type (
Provider = core.Deployer
DeployResult = core.DeployerDeployResult
)
type DeployerConfig struct {
// 移动云 AccessKeyId。
AccessKeyId string `json:"accessKeyId"`
// 移动云 AccessKeySecret。
AccessKeySecret string `json:"accessKeySecret"`
// 移动云资源池 ID。
PoolId string `json:"poolId"`
// 部署目标。
DeployTarget string `json:"deployTarget"`
// 负载均衡实例 ID。
// 部署目标为 [DEPLOY_TARGET_LOADBALANCER] 时必填。
LoadbalancerId string `json:"loadbalancerId,omitempty"`
// 负载均衡监听器 ID。
// 部署目标为 [DEPLOY_TARGET_LISTENER] 时必填。
ListenerId string `json:"listenerId,omitempty"`
// SNI 域名(支持泛域名)。
// 部署目标为 [DEPLOY_TARGET_LOADBALANCER]、[DEPLOY_TARGET_LISTENER] 时选填。
Domain string `json:"domain,omitempty"`
}
type Deployer struct {
config *DeployerConfig
logger *slog.Logger
sdkClient *ecloudsdkvlb.Client
sdkCertmgr core.Certmgr
}
var _ Provider = (*Deployer)(nil)
func NewDeployer(config *DeployerConfig) (*Deployer, error) {
if config == nil {
return nil, fmt.Errorf("the configuration of the deployer provider is nil")
}
client, err := createSDKClient(config.AccessKeyId, config.AccessKeySecret, config.PoolId)
if err != nil {
return nil, fmt.Errorf("could not create client: %w", err)
}
pcertmgr, err := cmgrimpl.NewCertmgr(&cmgrimpl.CertmgrConfig{
AccessKeyId: config.AccessKeyId,
AccessKeySecret: config.AccessKeySecret,
PoolId: config.PoolId,
IsSNI: config.Domain != "",
})
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) (*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.DeployTarget {
case DEPLOY_TARGET_LOADBALANCER:
if err := d.deployToLoadbalancer(ctx, upres.CertId); err != nil {
return nil, err
}
case DEPLOY_TARGET_LISTENER:
if err := d.deployToListener(ctx, upres.CertId); err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("unsupported deploy target '%s'", d.config.DeployTarget)
}
return &DeployResult{}, nil
}
func (d *Deployer) deployToLoadbalancer(ctx context.Context, cloudCertId string) error {
if d.config.LoadbalancerId == "" {
return fmt.Errorf("config `loadbalancerId` is required")
}
// 查询 HTTPS 监听器列表
// REF: https://ecloud.10086.cn/op-help-center/doc/article/97026
listenerIds := make([]string, 0)
listLoadBalanceHTTPSListenerPage := 1
listLoadBalanceHTTPSListenerPageSize := 10
for {
select {
case <-ctx.Done():
return ctx.Err()
default:
}
listLoadBalanceHTTPSListenerReq := &model.ListLoadBalanceHTTPSListenerRequest{
ListLoadBalanceHTTPSListenerPath: &model.ListLoadBalanceHTTPSListenerPath{
LoadBalanceId: lo.ToPtr(d.config.LoadbalancerId),
},
ListLoadBalanceHTTPSListenerQuery: &model.ListLoadBalanceHTTPSListenerQuery{
Page: lo.ToPtr(int32(listLoadBalanceHTTPSListenerPage)),
PageSize: lo.ToPtr(int32(listLoadBalanceHTTPSListenerPageSize)),
},
}
listLoadBalanceHTTPSListenerResp, err := d.sdkClient.ListLoadBalanceHTTPSListener(listLoadBalanceHTTPSListenerReq)
d.logger.Debug("sdk request 'vlb.ListLoadBalanceHTTPSListener'", slog.Any("request", listLoadBalanceHTTPSListenerReq), slog.Any("response", listLoadBalanceHTTPSListenerResp))
if err != nil {
return fmt.Errorf("failed to execute sdk request 'vlb.ListLoadBalanceHTTPSListener': %w", err)
}
if listLoadBalanceHTTPSListenerResp.Body == nil || listLoadBalanceHTTPSListenerResp.Body.Content == nil {
break
}
for _, listener := range *listLoadBalanceHTTPSListenerResp.Body.Content {
listenerIds = append(listenerIds, lo.FromPtr(listener.Id))
}
if len(*listLoadBalanceHTTPSListenerResp.Body.Content) < listLoadBalanceHTTPSListenerPageSize {
break
}
listLoadBalanceHTTPSListenerPage++
}
// 遍历更新监听证书
if len(listenerIds) == 0 {
d.logger.Info("no elb 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, 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.ListenerId == "" {
return fmt.Errorf("config `listenerId` is required")
}
// 更新监听
if err := d.updateListenerCertificate(ctx, d.config.ListenerId, cloudCertId); err != nil {
return err
}
return nil
}
func (d *Deployer) updateListenerCertificate(ctx context.Context, cloudListenerId string, cloudCertId string) error {
// 查询 HTTPS 监听器信息
// REF: https://ecloud.10086.cn/op-help-center/doc/article/97026
var listenerInfo *model.ListLoadBalanceHTTPSListenerResponseContent
listLoadBalanceHTTPSListenerPage := 1
listLoadBalanceHTTPSListenerPageSize := 10
for {
select {
case <-ctx.Done():
return ctx.Err()
default:
}
listLoadBalanceHTTPSListenerReq := &model.ListLoadBalanceHTTPSListenerRequest{
ListLoadBalanceHTTPSListenerPath: &model.ListLoadBalanceHTTPSListenerPath{
LoadBalanceId: lo.ToPtr(d.config.LoadbalancerId),
},
ListLoadBalanceHTTPSListenerQuery: &model.ListLoadBalanceHTTPSListenerQuery{
Page: lo.ToPtr(int32(listLoadBalanceHTTPSListenerPage)),
PageSize: lo.ToPtr(int32(listLoadBalanceHTTPSListenerPageSize)),
},
}
listLoadBalanceHTTPSListenerResp, err := d.sdkClient.ListLoadBalanceHTTPSListener(listLoadBalanceHTTPSListenerReq)
d.logger.Debug("sdk request 'vlb.ListLoadBalanceHTTPSListener'", slog.Any("request", listLoadBalanceHTTPSListenerReq), slog.Any("response", listLoadBalanceHTTPSListenerResp))
if err != nil {
return fmt.Errorf("failed to execute sdk request 'vlb.ListLoadBalanceHTTPSListener': %w", err)
}
if listLoadBalanceHTTPSListenerResp.Body == nil || listLoadBalanceHTTPSListenerResp.Body.Content == nil {
break
}
for _, listener := range *listLoadBalanceHTTPSListenerResp.Body.Content {
if lo.FromPtr(listener.Id) == cloudListenerId {
listenerInfo = &listener
break
}
}
if len(*listLoadBalanceHTTPSListenerResp.Body.Content) < listLoadBalanceHTTPSListenerPageSize {
break
}
listLoadBalanceHTTPSListenerPage++
}
if listenerInfo == nil {
return fmt.Errorf("could not find listener '%s'", cloudListenerId)
}
if d.config.Domain == "" {
// 未指定 SNI,只需部署到默认证书
if lo.FromPtr(listenerInfo.DefaultTlsContainerId) == cloudCertId {
d.logger.Info("ssl certificate already deployed")
return nil
}
// 修改 HTTPS 监听器
// REF: https://ecloud.10086.cn/op-help-center/doc/article/97024
updateListenerReq := &model.UpdateListenerRequest{
&model.UpdateListenerBody{
Id: lo.ToPtr(cloudListenerId),
DefaultTlsContainerId: lo.ToPtr(cloudCertId),
},
}
updateListenerResp, err := d.sdkClient.UpdateListener(updateListenerReq)
d.logger.Debug("sdk request 'vlb.UpdateListener'", slog.Any("request", updateListenerReq), slog.Any("response", updateListenerResp))
if err != nil {
return fmt.Errorf("failed to execute sdk request 'vlb.UpdateListener': %w", err)
}
} else {
// 指定 SNI,需部署到 SNI 证书
if lo.Contains(listenerInfo.SniContainerIdList, cloudCertId) {
d.logger.Info("ssl certificate already deployed")
return nil
}
// 修改 HTTPS 监听器
// REF: https://ecloud.10086.cn/op-help-center/doc/article/97024
updateListenerReq := &model.UpdateListenerRequest{
&model.UpdateListenerBody{
Id: lo.ToPtr(cloudListenerId),
SniUp: lo.ToPtr(true),
SniContainerIds: append(listenerInfo.SniContainerIdList, cloudCertId),
},
}
updateListenerResp, err := d.sdkClient.UpdateListener(updateListenerReq)
d.logger.Debug("sdk request 'vlb.UpdateListener'", slog.Any("request", updateListenerReq), slog.Any("response", updateListenerResp))
if err != nil {
return fmt.Errorf("failed to execute sdk request 'vlb.UpdateListener': %w", err)
}
}
return nil
}
func createSDKClient(accessKeyId, accessKeySecret, poolId string) (*ecloudsdkvlb.Client, error) {
client := ecloudsdkvlb.NewClient(&config.Config{
AccessKey: &accessKeyId,
SecretKey: &accessKeySecret,
PoolId: &poolId,
})
return client, nil
}
@@ -0,0 +1,77 @@
package cmcccloudvlb_test
import (
"testing"
"github.com/certimate-go/certimate/pkg/core/deployer/internal/tester"
impl "github.com/certimate-go/certimate/pkg/core/deployer/providers/cmcccloud-vlb"
)
var (
fp = tester.Args("CMCCCLOUDVLB_")
fTestCertPath string
fTestKeyPath string
fAccessKeyId string
fAccessKeySecret string
fPoolId string
fLoadbalancerId string
fListenerId string
)
func init() {
fp.DefineString(&fTestCertPath, "TESTCERTPATH")
fp.DefineString(&fTestKeyPath, "TESTKEYPATH")
fp.DefineString(&fAccessKeyId, "ACCESSKEYID")
fp.DefineString(&fAccessKeySecret, "ACCESSKEYSECRET")
fp.DefineString(&fPoolId, "POOLID")
fp.DefineString(&fLoadbalancerId, "LOADBALANCERID")
fp.DefineString(&fListenerId, "LISTENERID")
}
/*
Shell command to run this test:
go test -v ./cmcccloud_vlb_test.go -args \
--CMCCCLOUDVLB_TESTCERTPATH="/path/to/your-test-cert.pem" \
--CMCCCLOUDVLB_TESTKEYPATH="/path/to/your-test-key.pem" \
--CMCCCLOUDVLB_ACCESSKEYID="your-access-key-id" \
--CMCCCLOUDVLB_ACCESSKEYSECRET="your-access-key-secret" \
--CMCCCLOUDVLB_POOLID="CIDC-RP-29" \
--CMCCCLOUDVLB_LOADBALANCERID="your-vlb-instance-id" \
--CMCCCLOUDVLB_LISTENERID="your-vlb-listener-id"
*/
func TestProvider(t *testing.T) {
fp.Parse()
t.Run("Deploy_ToLoadbalancer", func(t *testing.T) {
provider, err := impl.NewDeployer(&impl.DeployerConfig{
AccessKeyId: fAccessKeyId,
AccessKeySecret: fAccessKeySecret,
PoolId: fPoolId,
DeployTarget: impl.DEPLOY_TARGET_LOADBALANCER,
LoadbalancerId: fLoadbalancerId,
})
if err != nil {
t.Errorf("err: %+v", err)
return
}
tester.TestDeploy(t, provider, tester.TestDeployArgs{CertPath: fTestCertPath, KeyPath: fTestKeyPath})
})
t.Run("Deploy_ToListener", func(t *testing.T) {
provider, err := impl.NewDeployer(&impl.DeployerConfig{
AccessKeyId: fAccessKeyId,
AccessKeySecret: fAccessKeySecret,
PoolId: fPoolId,
DeployTarget: impl.DEPLOY_TARGET_LISTENER,
ListenerId: fListenerId,
})
if err != nil {
t.Errorf("err: %+v", err)
return
}
tester.TestDeploy(t, provider, tester.TestDeployArgs{CertPath: fTestCertPath, KeyPath: fTestKeyPath})
})
}
@@ -0,0 +1,8 @@
package cmcccloudvlb
const (
// 部署目标:部署到指定负载均衡器。
DEPLOY_TARGET_LOADBALANCER = "loadbalancer"
// 部署目标:部署到指定监听器。
DEPLOY_TARGET_LISTENER = "listener"
)
@@ -178,13 +178,13 @@ func (d *Deployer) deployToListener(ctx context.Context, cloudCertId string) err
func (d *Deployer) updateListenerCertificate(ctx context.Context, cloudListenerId string, cloudCertId string) error {
// 更新监听器
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=24&api=5652&data=88&isNormal=1&vid=82
setLoadBalancerHTTPSListenerAttributeReq := &ctyunelb.UpdateListenerRequest{
updateListenerReq := &ctyunelb.UpdateListenerRequest{
RegionID: lo.ToPtr(d.config.RegionId),
ListenerID: lo.ToPtr(cloudListenerId),
CertificateID: lo.ToPtr(cloudCertId),
}
setLoadBalancerHTTPSListenerAttributeResp, err := d.sdkClient.UpdateListenerWithContext(ctx, setLoadBalancerHTTPSListenerAttributeReq)
d.logger.Debug("sdk request 'elb.UpdateListener'", slog.Any("request", setLoadBalancerHTTPSListenerAttributeReq), slog.Any("response", setLoadBalancerHTTPSListenerAttributeResp))
updateListenerResp, err := d.sdkClient.UpdateListenerWithContext(ctx, updateListenerReq)
d.logger.Debug("sdk request 'elb.UpdateListener'", slog.Any("request", updateListenerReq), slog.Any("response", updateListenerResp))
if err != nil {
return fmt.Errorf("failed to execute sdk request 'elb.UpdateListener': %w", err)
}
@@ -0,0 +1,373 @@
package ecloudsdkvlb
import (
"gitlab.ecloud.com/ecloud/ecloudsdkcore"
"gitlab.ecloud.com/ecloud/ecloudsdkcore/config"
"gitlab.ecloud.com/ecloud/ecloudsdkcore/param"
"gitlab.ecloud.com/ecloud/ecloudsdkcore/region"
"gitlab.ecloud.com/ecloud/ecloudsdkcore/request"
"gitlab.ecloud.com/ecloud/ecloudsdkcore/utils"
"gitlab.ecloud.com/ecloud/ecloudsdkvlb/model"
)
type Client struct {
apiClient *ecloudsdkcore.APIClient
config *config.Config
httpRequest *request.HttpRequest
allRegions []region.Region
}
func NewClient(config *config.Config) *Client {
httpRequest := request.DefaultHttpRequest()
httpRequest.Product = product
httpRequest.Version = version
httpRequest.SdkVersion = sdkVersion
ecloudsdkcore.InitConfig(config)
apiClient := ecloudsdkcore.DefaultApiClient(config, httpRequest)
client := &Client{
apiClient: apiClient,
config: config,
httpRequest: httpRequest,
}
client.allRegions = client.initRegions()
client.setEndpoint(config, httpRequest)
return client
}
const (
product string = "vlb"
version = "v1"
sdkVersion = "1.0.7"
)
func (c *Client) initRegions() []region.Region {
var regions []region.Region
regions = append(regions, region.Region{
RegionId: utils.String("cn-jiangsu-1"),
PoolId: utils.String("CIDC-RP-25"),
Endpoint: utils.String("https://api-wuxi-1.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-guangdong-1"),
PoolId: utils.String("CIDC-RP-26"),
Endpoint: utils.String("https://api-dongguan-1.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-sichuan-1"),
PoolId: utils.String("CIDC-RP-27"),
Endpoint: utils.String("https://api-yaan-1.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-henan-1"),
PoolId: utils.String("CIDC-RP-28"),
Endpoint: utils.String("https://api-zhengzhou-1.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-beijing-1"),
PoolId: utils.String("CIDC-RP-29"),
Endpoint: utils.String("https://api-beijing-2.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-hunan-1"),
PoolId: utils.String("CIDC-RP-30"),
Endpoint: utils.String("https://api-zhuzhou-1.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-shandong-1"),
PoolId: utils.String("CIDC-RP-31"),
Endpoint: utils.String("https://api-jinan-1.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-shaanxi-1"),
PoolId: utils.String("CIDC-RP-32"),
Endpoint: utils.String("https://api-xian-1.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-shanghai-1"),
PoolId: utils.String("CIDC-RP-33"),
Endpoint: utils.String("https://api-shanghai-1.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-chongqing-1"),
PoolId: utils.String("CIDC-RP-34"),
Endpoint: utils.String("https://api-chongqing-1.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-zhejiang-1"),
PoolId: utils.String("CIDC-RP-35"),
Endpoint: utils.String("https://api-ningbo-1.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-tianjin-1"),
PoolId: utils.String("CIDC-RP-36"),
Endpoint: utils.String("https://api-tianjin-1.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-jilin-1"),
PoolId: utils.String("CIDC-RP-37"),
Endpoint: utils.String("https://api-jilin-1.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-hubei-1"),
PoolId: utils.String("CIDC-RP-38"),
Endpoint: utils.String("https://api-hubei-1.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-jiangxi-1"),
PoolId: utils.String("CIDC-RP-39"),
Endpoint: utils.String("https://api-jiangxi-1.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-gansu-1"),
PoolId: utils.String("CIDC-RP-40"),
Endpoint: utils.String("https://api-gansu-1.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-shangxi-1"),
PoolId: utils.String("CIDC-RP-41"),
Endpoint: utils.String("https://api-shanxi-1.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-liaoning-1"),
PoolId: utils.String("CIDC-RP-42"),
Endpoint: utils.String("https://api-liaoning-1.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-yunnan-1"),
PoolId: utils.String("CIDC-RP-43"),
Endpoint: utils.String("https://api-yunnan-2.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-hebei-1"),
PoolId: utils.String("CIDC-RP-44"),
Endpoint: utils.String("https://api-hebei-1.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-fujian-1"),
PoolId: utils.String("CIDC-RP-45"),
Endpoint: utils.String("https://api-fujian-1.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-guangxi-1"),
PoolId: utils.String("CIDC-RP-46"),
Endpoint: utils.String("https://api-guangxi-1.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-anhui-1"),
PoolId: utils.String("CIDC-RP-47"),
Endpoint: utils.String("https://api-anhui-1.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-neimenggu-1"),
PoolId: utils.String("CIDC-RP-48"),
Endpoint: utils.String("https://api-huhehaote-1.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-guzhou-1"),
PoolId: utils.String("CIDC-RP-49"),
Endpoint: utils.String("https://api-guiyang-1.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-hainan-1"),
PoolId: utils.String("CIDC-RP-53"),
Endpoint: utils.String("https://api-hainan-1.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-xinjiang-1"),
PoolId: utils.String("CIDC-RP-54"),
Endpoint: utils.String("https://api-xinjiang-1.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-heilongjiang-1"),
PoolId: utils.String("CIDC-RP-55"),
Endpoint: utils.String("https://api-heilongjiang-1.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-ningxia-1"),
PoolId: utils.String("CIDC-RP-60"),
Endpoint: utils.String("https://api-ningxia-1.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-qinghai-1"),
PoolId: utils.String("CIDC-RP-61"),
Endpoint: utils.String("https://api-qinghai-1.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-xizang-1"),
PoolId: utils.String("CIDC-RP-62"),
Endpoint: utils.String("https://api-xizang-1.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-hubei-2"),
PoolId: utils.String("CIDC-RP-64"),
Endpoint: utils.String("https://api-wuhan-1.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-xizang-2"),
PoolId: utils.String("CIDC-RP-68"),
Endpoint: utils.String("https://api-xizang-2.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-qinghai-2"),
PoolId: utils.String("CIDC-RP-69"),
Endpoint: utils.String("https://api-qinghai-2.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String("cn-ningxia-2"),
PoolId: utils.String("CIDC-RP-71"),
Endpoint: utils.String("https://api-ningxia-2.cmecloud.cn:8443"),
})
regions = append(regions, region.Region{
RegionId: utils.String(""),
PoolId: utils.String("CIDC-CORE-00"),
Endpoint: utils.String("https://ecloud.10086.cn"),
})
return regions
}
func (c *Client) setEndpoint(config *config.Config, httpRequest *request.HttpRequest) {
if utils.IsUnSet(config.RegionId) && utils.IsUnSet(config.PoolId) {
httpRequest.Endpoint = utils.DefaultEndpoint
} else if utils.IsSet(config.RegionId) {
c.findAndSetEndpointByRegionId(config.RegionId, httpRequest)
} else {
c.findAndSetEndpointByPoolId(config.PoolId, httpRequest)
}
}
func (c *Client) findAndSetEndpointByRegionId(regionId *string, httpRequest *request.HttpRequest) {
for _, r := range c.allRegions {
if utils.StringValue(r.RegionId) == utils.StringValue(regionId) {
endpoint := r.Endpoint
if utils.IsUnSet(endpoint) {
httpRequest.Endpoint = utils.DefaultEndpoint
} else {
httpRequest.Endpoint = *endpoint
}
break
}
}
}
func (c *Client) findAndSetEndpointByPoolId(poolId *string, httpRequest *request.HttpRequest) {
for _, r := range c.allRegions {
if utils.StringValue(r.PoolId) == utils.StringValue(poolId) {
endpoint := r.Endpoint
if utils.IsUnSet(endpoint) {
httpRequest.Endpoint = utils.DefaultEndpoint
} else {
httpRequest.Endpoint = *endpoint
}
break
}
}
}
func (c *Client) CreateLoadbalanceCertification(request *model.CreateLoadbalanceCertificationRequest) (*model.CreateLoadbalanceCertificationResponse, error) {
return c.CreateLoadbalanceCertificationWithConfig(request, nil)
}
func (c *Client) CreateLoadbalanceCertificationWithConfig(request *model.CreateLoadbalanceCertificationRequest, runtimeConfig *config.RuntimeConfig) (*model.CreateLoadbalanceCertificationResponse, error) {
params := param.NewParamsBuilder().
Action("createLoadbalanceCertification").
Uri("/acl/v3/certification").
GatewayUri("/api/openapi-vlb/lb-console/acl/v3/certification").
Protocol("http").
ContentType("application/json").
Method("POST").
Request(request).
Build()
returnValue := &model.CreateLoadbalanceCertificationResponse{}
if _, err := c.apiClient.Excute(params, runtimeConfig, returnValue); err != nil {
return nil, err
} else {
return returnValue, nil
}
}
func (c *Client) GetLoadbalanceCertificationDetailResp(request *model.GetLoadbalanceCertificationDetailRespRequest) (*model.GetLoadbalanceCertificationDetailRespResponse, error) {
return c.GetLoadbalanceCertificationDetailRespWithConfig(request, nil)
}
func (c *Client) GetLoadbalanceCertificationDetailRespWithConfig(request *model.GetLoadbalanceCertificationDetailRespRequest, runtimeConfig *config.RuntimeConfig) (*model.GetLoadbalanceCertificationDetailRespResponse, error) {
params := param.NewParamsBuilder().
Action("getLoadbalanceCertificationDetailResp").
Uri("/acl/v3/certification/{containerUuid}").
GatewayUri("/api/openapi-vlb/lb-console/acl/v3/certification/{containerUuid}").
Protocol("http").
ContentType("application/json").
Method("GET").
Request(request).
Build()
returnValue := &model.GetLoadbalanceCertificationDetailRespResponse{}
if _, err := c.apiClient.Excute(params, runtimeConfig, returnValue); err != nil {
return nil, err
} else {
return returnValue, nil
}
}
func (c *Client) ListLoadbalanceCertificationResp() (*model.ListLoadbalanceCertificationRespResponse, error) {
return c.ListLoadbalanceCertificationRespWithConfig(nil)
}
func (c *Client) ListLoadbalanceCertificationRespWithConfig(runtimeConfig *config.RuntimeConfig) (*model.ListLoadbalanceCertificationRespResponse, error) {
params := param.NewParamsBuilder().
Action("listLoadbalanceCertificationResp").
Uri("/acl/v3/certification").
GatewayUri("/api/openapi-vlb/lb-console/acl/v3/certification").
Protocol("http").
ContentType("application/json").
Method("GET").
Build()
returnValue := &model.ListLoadbalanceCertificationRespResponse{}
if _, err := c.apiClient.Excute(params, runtimeConfig, returnValue); err != nil {
return nil, err
} else {
return returnValue, nil
}
}
func (c *Client) ListLoadBalanceHTTPSListener(request *model.ListLoadBalanceHTTPSListenerRequest) (*model.ListLoadBalanceHTTPSListenerResponse, error) {
return c.ListLoadBalanceHTTPSListenerWithConfig(request, nil)
}
func (c *Client) ListLoadBalanceHTTPSListenerWithConfig(request *model.ListLoadBalanceHTTPSListenerRequest, runtimeConfig *config.RuntimeConfig) (*model.ListLoadBalanceHTTPSListenerResponse, error) {
params := param.NewParamsBuilder().
Action("listLoadBalanceHTTPSListener").
Uri("/protocol/v3/listener/{loadBalanceId}/listeners/https").
GatewayUri("/api/openapi-vlb/lb-console/protocol/v3/listener/{loadBalanceId}/listeners/https").
Protocol("http").
ContentType("application/json").
Method("GET").
Request(request).
Build()
returnValue := &model.ListLoadBalanceHTTPSListenerResponse{}
if _, err := c.apiClient.Excute(params, runtimeConfig, returnValue); err != nil {
return nil, err
} else {
return returnValue, nil
}
}
func (c *Client) UpdateListener(request *model.UpdateListenerRequest) (*model.UpdateListenerResponse, error) {
return c.UpdateListenerWithConfig(request, nil)
}
func (c *Client) UpdateListenerWithConfig(request *model.UpdateListenerRequest, runtimeConfig *config.RuntimeConfig) (*model.UpdateListenerResponse, error) {
params := param.NewParamsBuilder().
Action("updateListener").
Uri("/acl/v3/listener").
GatewayUri("/api/openapi-vlb/lb-console/acl/v3/listener").
Protocol("http").
ContentType("application/json").
Method("PUT").
Request(request).
Build()
returnValue := &model.UpdateListenerResponse{}
if _, err := c.apiClient.Excute(params, runtimeConfig, returnValue); err != nil {
return nil, err
} else {
return returnValue, nil
}
}
@@ -52,6 +52,7 @@ import BizDeployNodeConfigFieldsProviderBytePlusTOS from "./BizDeployNodeConfigF
import BizDeployNodeConfigFieldsProviderCdnfly from "./BizDeployNodeConfigFieldsProviderCdnfly";
import BizDeployNodeConfigFieldsProviderCloudflareSSL from "./BizDeployNodeConfigFieldsProviderCloudflareSSL";
import BizDeployNodeConfigFieldsProviderCMCCCloudCDN from "./BizDeployNodeConfigFieldsProviderCMCCCloudCDN";
import BizDeployNodeConfigFieldsProviderCMCCCloudVLB from "./BizDeployNodeConfigFieldsProviderCMCCCloudVLB";
import BizDeployNodeConfigFieldsProviderCPanel from "./BizDeployNodeConfigFieldsProviderCPanel";
import BizDeployNodeConfigFieldsProviderCTCCCloudAO from "./BizDeployNodeConfigFieldsProviderCTCCCloudAO";
import BizDeployNodeConfigFieldsProviderCTCCCloudCDN from "./BizDeployNodeConfigFieldsProviderCTCCCloudCDN";
@@ -197,6 +198,7 @@ const providerComponentMap: Partial<Record<DeploymentProviderType, React.Compone
[DEPLOYMENT_PROVIDERS.CDNFLY]: BizDeployNodeConfigFieldsProviderCdnfly,
[DEPLOYMENT_PROVIDERS.CLOUDFLARE_SSL]: BizDeployNodeConfigFieldsProviderCloudflareSSL,
[DEPLOYMENT_PROVIDERS.CMCCCLOUD_CDN]: BizDeployNodeConfigFieldsProviderCMCCCloudCDN,
[DEPLOYMENT_PROVIDERS.CMCCCLOUD_VLB]: BizDeployNodeConfigFieldsProviderCMCCCloudVLB,
[DEPLOYMENT_PROVIDERS.CPANEL]: BizDeployNodeConfigFieldsProviderCPanel,
[DEPLOYMENT_PROVIDERS.CTCCCLOUD_AO]: BizDeployNodeConfigFieldsProviderCTCCCloudAO,
[DEPLOYMENT_PROVIDERS.CTCCCLOUD_CDN]: BizDeployNodeConfigFieldsProviderCTCCCloudCDN,
@@ -0,0 +1,155 @@
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 { isDomain } from "@/utils/validator";
import { useFormNestedFieldsContext } from "./_context";
const DEPLOY_TARGET_LOADBALANCER = "loadbalancer" as const;
const DEPLOY_TARGET_LISTENER = "listener" as const;
const BizDeployNodeConfigFieldsProviderCMCCCloudVLB = () => {
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, "deployTarget"], formInst);
return (
<>
<Form.Item
name={[parentNamePath, "poolId"]}
initialValue={initialValues.poolId}
label={t("workflow_node.deploy.form.cmcccloud_vlb_pool_id.label")}
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.cmcccloud_vlb_pool_id.tooltip") }}></span>}
>
<Input placeholder={t("workflow_node.deploy.form.cmcccloud_vlb_pool_id.placeholder")} />
</Form.Item>
<Form.Item
name={[parentNamePath, "deployTarget"]}
initialValue={initialValues.deployTarget}
label={t("workflow_node.deploy.form.shared_deploy_target.label")}
rules={[formRule]}
>
<Select
options={[DEPLOY_TARGET_LOADBALANCER, DEPLOY_TARGET_LISTENER].map((s) => ({
label: t(`workflow_node.deploy.form.cmcccloud_vlb_deploy_target.option.${s}.label`),
value: s,
}))}
placeholder={t("workflow_node.deploy.form.shared_deploy_target.placeholder")}
/>
</Form.Item>
<Show when={fieldResourceType === DEPLOY_TARGET_LOADBALANCER}>
<Form.Item
name={[parentNamePath, "loadbalancerId"]}
initialValue={initialValues.loadbalancerId}
label={t("workflow_node.deploy.form.cmcccloud_vlb_loadbalancer_id.label")}
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.cmcccloud_vlb_loadbalancer_id.tooltip") }}></span>}
>
<Input placeholder={t("workflow_node.deploy.form.cmcccloud_vlb_loadbalancer_id.placeholder")} />
</Form.Item>
</Show>
<Show when={fieldResourceType === DEPLOY_TARGET_LISTENER}>
<Form.Item
name={[parentNamePath, "listenerId"]}
initialValue={initialValues.listenerId}
label={t("workflow_node.deploy.form.cmcccloud_vlb_listener_id.label")}
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.cmcccloud_vlb_listener_id.tooltip") }}></span>}
>
<Input placeholder={t("workflow_node.deploy.form.cmcccloud_vlb_listener_id.placeholder")} />
</Form.Item>
</Show>
<Show when={fieldResourceType === DEPLOY_TARGET_LOADBALANCER || fieldResourceType === DEPLOY_TARGET_LISTENER}>
<Form.Item
name={[parentNamePath, "domain"]}
initialValue={initialValues.domain}
label={t("workflow_node.deploy.form.cmcccloud_vlb_snidomain.label")}
extra={t("workflow_node.deploy.form.cmcccloud_vlb_snidomain.help")}
rules={[formRule]}
>
<Input allowClear placeholder={t("workflow_node.deploy.form.cmcccloud_vlb_snidomain.placeholder")} />
</Form.Item>
</Show>
</>
);
};
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
return {
poolId: "",
deployTarget: DEPLOY_TARGET_LISTENER,
};
};
const getSchema = ({ i18n = getI18n() }: { i18n?: ReturnType<typeof getI18n> }) => {
const { t } = i18n;
return z
.object({
poolId: z.string().nonempty(),
deployTarget: z.enum([DEPLOY_TARGET_LOADBALANCER, DEPLOY_TARGET_LISTENER]),
loadbalancerId: z.string().nullish(),
listenerId: z.string().nullish(),
domain: z
.string()
.nullish()
.refine((v) => {
if (!v) return true;
return isDomain(v, { allowWildcard: true });
}, t("common.errmsg.domain_invalid")),
})
.superRefine((values, ctx) => {
switch (values.deployTarget) {
case DEPLOY_TARGET_LOADBALANCER:
{
const scLoadbalancerId = z.string().nonempty();
const spLoadbalancerId = scLoadbalancerId.safeParse(values.loadbalancerId);
if (!spLoadbalancerId.success) {
ctx.addIssue({
code: "custom",
message: z.treeifyError(spLoadbalancerId.error).errors.join(),
path: ["loadbalancerId"],
});
}
}
break;
case DEPLOY_TARGET_LISTENER:
{
const scListenerId = z.string().nonempty();
const spListenerId = scListenerId.safeParse(values.listenerId);
if (!spListenerId.success) {
ctx.addIssue({
code: "custom",
message: z.treeifyError(spListenerId.error).errors.join(),
path: ["listenerId"],
});
}
}
break;
}
});
};
const _default = Object.assign(BizDeployNodeConfigFieldsProviderCMCCCloudVLB, {
getInitialValues,
getSchema,
});
export default _default;
+2
View File
@@ -644,6 +644,7 @@ export const DEPLOYMENT_PROVIDERS = Object.freeze({
CDNFLY: `${ACCESS_PROVIDERS.CDNFLY}`,
CLOUDFLARE_SSL: `${ACCESS_PROVIDERS.CLOUDFLARE}-ssl`,
CMCCCLOUD_CDN: `${ACCESS_PROVIDERS.CMCCCLOUD}-cdn`,
CMCCCLOUD_VLB: `${ACCESS_PROVIDERS.CMCCCLOUD}-vlb`,
CPANEL: `${ACCESS_PROVIDERS.CPANEL}`,
CTCCCLOUD_AO: `${ACCESS_PROVIDERS.CTCCCLOUD}-ao`,
CTCCCLOUD_CDN: `${ACCESS_PROVIDERS.CTCCCLOUD}-cdn`,
@@ -863,6 +864,7 @@ export const deploymentProvidersMap: Map<DeploymentProvider["type"] | string, De
[DEPLOYMENT_PROVIDERS.BAIDUCLOUD_APPBLB, "provider.baiducloud_appblb", DEPLOYMENT_CATEGORIES.LOADBALANCE],
[DEPLOYMENT_PROVIDERS.BAIDUCLOUD_CERT, "provider.baiducloud_cert_upload", DEPLOYMENT_CATEGORIES.SSL],
[DEPLOYMENT_PROVIDERS.CMCCCLOUD_CDN, "provider.cmcccloud_cdn", DEPLOYMENT_CATEGORIES.CDN],
[DEPLOYMENT_PROVIDERS.CMCCCLOUD_VLB, "provider.cmcccloud_vlb", 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],
@@ -110,6 +110,7 @@
"cmcccloud": "China Mobile ECloud",
"cmcccloud_cdn": "China Mobile ECloud - CDN (Content Delivery Network)",
"cmcccloud_dns": "China Mobile ECloud - DNS",
"cmcccloud_vlb": "China Mobile ECloud - VLB (Virtual Load Balancer)",
"conohavps": "ConoHa VPS",
"constellix": "Constellix",
"cpanel": "cPanel",
@@ -1432,6 +1432,36 @@
"label": "CMCC ECloud CDN domain",
"placeholder": "Please enter CMCC ECloud CDN domain name"
},
"cmcccloud_vlb_pool_id": {
"label": "CMCC ECloud pool ID",
"placeholder": "Please enter CMCC ECloud VLB pool ID (e.g. CIDC-RP-29)",
"tooltip": "For more information, see <a href=\"https://ecloud.10086.cn/op-help-center/doc/article/54462\" target=\"_blank\">https://ecloud.10086.cn/op-help-center/doc/article/54462</a>"
},
"cmcccloud_vlb_deploy_target": {
"option": {
"loadbalancer": {
"label": "VLB load balancer"
},
"listener": {
"label": "VLB listener"
}
}
},
"cmcccloud_vlb_loadbalancer_id": {
"label": "CMCC ECloud VLB load balancer ID",
"placeholder": "Please enter CMCC ECloud VLB load balancer ID",
"tooltip": "For more information, see <a href=\"https://ecloud.10086.cn/api/page/lb-console-manage-web/CIDC-RP-29/elb/instancelist\" target=\"_blank\">https://ecloud.10086.cn/api/page/lb-console-manage-web/CIDC-RP-29/elb/instancelist</a>"
},
"cmcccloud_vlb_listener_id": {
"label": "CMCC ECloud VLB listener ID",
"placeholder": "Please enter CMCC ECloud VLB listener ID",
"tooltip": "For more information, see <a href=\"https://ecloud.10086.cn/api/page/lb-console-manage-web/CIDC-RP-29/elb/instancelist\" target=\"_blank\">https://ecloud.10086.cn/api/page/lb-console-manage-web/CIDC-RP-29/elb/instancelist</a>"
},
"cmcccloud_vlb_snidomain": {
"label": "CMCC ECloud VLB SNI domain (Optional)",
"placeholder": "Please enter CMCC ECloud VLB SNI domain name",
"help": "Notes: Leave it blank to set the default certificate; otherwise, to set the extension one for SNI."
},
"cpanel_deploy_target": {
"option": {
"website": {
@@ -1458,9 +1488,6 @@
},
"ctcccloud_elb_deploy_target": {
"option": {
"certificate": {
"label": "ELB certificate"
},
"loadbalancer": {
"label": "ELB load balancer"
},
@@ -110,6 +110,7 @@
"cmcccloud": "移动云",
"cmcccloud_cdn": "移动云 - 内容分发网络 CDN",
"cmcccloud_dns": "移动云 - 云解析 DNS",
"cmcccloud_vlb": "移动云 - 弹性负载均衡 VLB",
"conohavps": "ConoHa VPS",
"constellix": "Constellix",
"cpanel": "cPanel",
@@ -1431,6 +1431,36 @@
"label": "移动云 CDN 加速域名",
"placeholder": "请输入移动云 CDN 加速域名"
},
"cmcccloud_vlb_pool_id": {
"label": "移动云资源池 ID",
"placeholder": "请输入移动云 VLB 资源池 ID(例如:CIDC-RP-29)",
"tooltip": "这是什么?请参阅 <a href=\"https://ecloud.10086.cn/op-help-center/doc/article/54462\" target=\"_blank\">https://ecloud.10086.cn/op-help-center/doc/article/54462</a>"
},
"cmcccloud_vlb_deploy_target": {
"option": {
"loadbalancer": {
"label": "部署到指定负载均衡器下的全部 HTTPS 监听器"
},
"listener": {
"label": "部署到指定 HTTPS 监听器"
}
}
},
"cmcccloud_vlb_loadbalancer_id": {
"label": "移动云 VLB 负载均衡器 ID",
"placeholder": "请输入移动云 VLB 负载均衡器 ID",
"tooltip": "这是什么?请参阅 <a href=\"https://ecloud.10086.cn/api/page/lb-console-manage-web/CIDC-RP-29/elb/instancelist\" target=\"_blank\">https://ecloud.10086.cn/api/page/lb-console-manage-web/CIDC-RP-29/elb/instancelist</a>"
},
"cmcccloud_vlb_listener_id": {
"label": "移动云 VLB 监听器 ID",
"placeholder": "请输入移动云 VLB 监听器 ID",
"tooltip": "这是什么?请参阅 <a href=\"https://ecloud.10086.cn/api/page/lb-console-manage-web/CIDC-RP-29/elb/instancelist\" target=\"_blank\">https://ecloud.10086.cn/api/page/lb-console-manage-web/CIDC-RP-29/elb/instancelist</a>"
},
"cmcccloud_vlb_snidomain": {
"label": "移动云 VLB 扩展域名(可选)",
"placeholder": "请输入移动云 VLB 扩展域名",
"help": "提示:不填写时,将替换监听器的默认证书;否则,将替换扩展域名证书。"
},
"cpanel_deploy_target": {
"option": {
"website": {