mirror of
https://github.com/woodchen-ink/certimate.git
synced 2025-07-18 17:31:55 +08:00
feat: new deployment provider: ctcccloud elb
This commit is contained in:
parent
5d6bc03f21
commit
898311c6e5
@ -46,6 +46,7 @@ import (
|
|||||||
pCTCCCloudAO "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ctcccloud-ao"
|
pCTCCCloudAO "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ctcccloud-ao"
|
||||||
pCTCCCloudCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ctcccloud-cdn"
|
pCTCCCloudCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ctcccloud-cdn"
|
||||||
pCTCCCloudCMS "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ctcccloud-cms"
|
pCTCCCloudCMS "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ctcccloud-cms"
|
||||||
|
pCTCCCloudELB "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ctcccloud-elb"
|
||||||
pCTCCCloudICDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ctcccloud-icdn"
|
pCTCCCloudICDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ctcccloud-icdn"
|
||||||
pCTCCCloudLVDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ctcccloud-lvdn"
|
pCTCCCloudLVDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ctcccloud-lvdn"
|
||||||
pDogeCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/dogecloud-cdn"
|
pDogeCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/dogecloud-cdn"
|
||||||
@ -626,7 +627,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
|
|||||||
return deployer, err
|
return deployer, err
|
||||||
}
|
}
|
||||||
|
|
||||||
case domain.DeploymentProviderTypeCTCCCloudAO, domain.DeploymentProviderTypeCTCCCloudCDN, domain.DeploymentProviderTypeCTCCCloudCMS, domain.DeploymentProviderTypeCTCCCloudICDN, domain.DeploymentProviderTypeCTCCCloudLVDN:
|
case domain.DeploymentProviderTypeCTCCCloudAO, domain.DeploymentProviderTypeCTCCCloudCDN, domain.DeploymentProviderTypeCTCCCloudCMS, domain.DeploymentProviderTypeCTCCCloudELB, domain.DeploymentProviderTypeCTCCCloudICDN, domain.DeploymentProviderTypeCTCCCloudLVDN:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForCTCCCloud{}
|
access := domain.AccessConfigForCTCCCloud{}
|
||||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||||
@ -657,6 +658,17 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
|
|||||||
})
|
})
|
||||||
return deployer, err
|
return deployer, err
|
||||||
|
|
||||||
|
case domain.DeploymentProviderTypeCTCCCloudELB:
|
||||||
|
deployer, err := pCTCCCloudELB.NewDeployer(&pCTCCCloudELB.DeployerConfig{
|
||||||
|
AccessKeyId: access.AccessKeyId,
|
||||||
|
SecretAccessKey: access.SecretAccessKey,
|
||||||
|
RegionId: maputil.GetString(options.ProviderServiceConfig, "regionId"),
|
||||||
|
ResourceType: pCTCCCloudELB.ResourceType(maputil.GetString(options.ProviderServiceConfig, "resourceType")),
|
||||||
|
LoadbalancerId: maputil.GetString(options.ProviderServiceConfig, "loadbalancerId"),
|
||||||
|
ListenerId: maputil.GetString(options.ProviderServiceConfig, "listenerId"),
|
||||||
|
})
|
||||||
|
return deployer, err
|
||||||
|
|
||||||
case domain.DeploymentProviderTypeCTCCCloudICDN:
|
case domain.DeploymentProviderTypeCTCCCloudICDN:
|
||||||
deployer, err := pCTCCCloudICDN.NewDeployer(&pCTCCCloudICDN.DeployerConfig{
|
deployer, err := pCTCCCloudICDN.NewDeployer(&pCTCCCloudICDN.DeployerConfig{
|
||||||
AccessKeyId: access.AccessKeyId,
|
AccessKeyId: access.AccessKeyId,
|
||||||
|
@ -218,7 +218,7 @@ const (
|
|||||||
DeploymentProviderTypeCTCCCloudAO = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-ao")
|
DeploymentProviderTypeCTCCCloudAO = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-ao")
|
||||||
DeploymentProviderTypeCTCCCloudCDN = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-cdn")
|
DeploymentProviderTypeCTCCCloudCDN = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-cdn")
|
||||||
DeploymentProviderTypeCTCCCloudCMS = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-cms")
|
DeploymentProviderTypeCTCCCloudCMS = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-cms")
|
||||||
DeploymentProviderTypeCTCCCloudELB = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-elb") // (预留)
|
DeploymentProviderTypeCTCCCloudELB = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-elb")
|
||||||
DeploymentProviderTypeCTCCCloudICDN = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-icdn")
|
DeploymentProviderTypeCTCCCloudICDN = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-icdn")
|
||||||
DeploymentProviderTypeCTCCCloudLVDN = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-ldvn")
|
DeploymentProviderTypeCTCCCloudLVDN = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-ldvn")
|
||||||
DeploymentProviderTypeDogeCloudCDN = DeploymentProviderType(AccessProviderTypeDogeCloud + "-cdn")
|
DeploymentProviderTypeDogeCloudCDN = DeploymentProviderType(AccessProviderTypeDogeCloud + "-cdn")
|
||||||
|
10
internal/pkg/core/deployer/providers/ctcccloud-elb/consts.go
Normal file
10
internal/pkg/core/deployer/providers/ctcccloud-elb/consts.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package ctcccloudelb
|
||||||
|
|
||||||
|
type ResourceType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// 资源类型:部署到指定负载均衡器。
|
||||||
|
RESOURCE_TYPE_LOADBALANCER = ResourceType("loadbalancer")
|
||||||
|
// 资源类型:部署到指定监听器。
|
||||||
|
RESOURCE_TYPE_LISTENER = ResourceType("listener")
|
||||||
|
)
|
@ -0,0 +1,199 @@
|
|||||||
|
package ctcccloudelb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||||
|
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||||
|
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/ctcccloud-elb"
|
||||||
|
ctyunelb "github.com/usual2970/certimate/internal/pkg/sdk3rd/ctyun/elb"
|
||||||
|
typeutil "github.com/usual2970/certimate/internal/pkg/utils/type"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DeployerConfig struct {
|
||||||
|
// 天翼云 AccessKeyId。
|
||||||
|
AccessKeyId string `json:"accessKeyId"`
|
||||||
|
// 天翼云 SecretAccessKey。
|
||||||
|
SecretAccessKey string `json:"secretAccessKey"`
|
||||||
|
// 天翼云资源池 ID。
|
||||||
|
RegionId string `json:"regionId"`
|
||||||
|
// 部署资源类型。
|
||||||
|
ResourceType ResourceType `json:"resourceType"`
|
||||||
|
// 负载均衡实例 ID。
|
||||||
|
// 部署资源类型为 [RESOURCE_TYPE_LOADBALANCER] 时必填。
|
||||||
|
LoadbalancerId string `json:"loadbalancerId,omitempty"`
|
||||||
|
// 负载均衡监听器 ID。
|
||||||
|
// 部署资源类型为 [RESOURCE_TYPE_LISTENER] 时必填。
|
||||||
|
ListenerId string `json:"listenerId,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DeployerProvider struct {
|
||||||
|
config *DeployerConfig
|
||||||
|
logger *slog.Logger
|
||||||
|
sdkClient *ctyunelb.Client
|
||||||
|
sslUploader uploader.Uploader
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
||||||
|
|
||||||
|
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||||
|
if config == nil {
|
||||||
|
panic("config is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := createSdkClient(config.AccessKeyId, config.SecretAccessKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||||
|
AccessKeyId: config.AccessKeyId,
|
||||||
|
SecretAccessKey: config.SecretAccessKey,
|
||||||
|
RegionId: config.RegionId,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &DeployerProvider{
|
||||||
|
config: config,
|
||||||
|
logger: slog.Default(),
|
||||||
|
sdkClient: client,
|
||||||
|
sslUploader: uploader,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||||
|
if logger == nil {
|
||||||
|
d.logger = slog.New(slog.DiscardHandler)
|
||||||
|
} else {
|
||||||
|
d.logger = logger
|
||||||
|
}
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
|
||||||
|
// 上传证书到 ELB
|
||||||
|
upres, err := d.sslUploader.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 *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId string) error {
|
||||||
|
if d.config.LoadbalancerId == "" {
|
||||||
|
return errors.New("config `loadbalancerId` is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询监听列表
|
||||||
|
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=24&api=5654&data=88&isNormal=1&vid=82
|
||||||
|
listenerIds := make([]string, 0)
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ctx.Err()
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
listListenerReq := &ctyunelb.ListListenerRequest{
|
||||||
|
RegionID: typeutil.ToPtr(d.config.RegionId),
|
||||||
|
LoadBalancerID: typeutil.ToPtr(d.config.LoadbalancerId),
|
||||||
|
}
|
||||||
|
listListenerResp, err := d.sdkClient.ListListener(listListenerReq)
|
||||||
|
d.logger.Debug("sdk request 'elb.ListListener'", slog.Any("request", listListenerReq), slog.Any("response", listListenerResp))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to execute sdk request 'elb.ListListener': %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, listener := range listListenerResp.ReturnObj {
|
||||||
|
if strings.EqualFold(listener.Protocol, "HTTPS") {
|
||||||
|
listenerIds = append(listenerIds, listener.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历更新监听证书
|
||||||
|
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 *DeployerProvider) deployToListener(ctx context.Context, cloudCertId string) error {
|
||||||
|
if d.config.ListenerId == "" {
|
||||||
|
return errors.New("config `listenerId` is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新监听
|
||||||
|
if err := d.updateListenerCertificate(ctx, d.config.ListenerId, cloudCertId); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DeployerProvider) 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{
|
||||||
|
RegionID: typeutil.ToPtr(d.config.RegionId),
|
||||||
|
ListenerID: typeutil.ToPtr(cloudListenerId),
|
||||||
|
CertificateID: typeutil.ToPtr(cloudCertId),
|
||||||
|
}
|
||||||
|
setLoadBalancerHTTPSListenerAttributeResp, err := d.sdkClient.UpdateListener(setLoadBalancerHTTPSListenerAttributeReq)
|
||||||
|
d.logger.Debug("sdk request 'elb.UpdateListener'", slog.Any("request", setLoadBalancerHTTPSListenerAttributeReq), slog.Any("response", setLoadBalancerHTTPSListenerAttributeResp))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to execute sdk request 'elb.UpdateListener': %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createSdkClient(accessKeyId, secretAccessKey string) (*ctyunelb.Client, error) {
|
||||||
|
return ctyunelb.NewClient(accessKeyId, secretAccessKey)
|
||||||
|
}
|
@ -0,0 +1,118 @@
|
|||||||
|
package ctcccloudelb_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ctcccloud-elb"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
fInputCertPath string
|
||||||
|
fInputKeyPath string
|
||||||
|
fAccessKeyId string
|
||||||
|
fSecretAccessKey string
|
||||||
|
fRegionId string
|
||||||
|
fLoadbalancerId string
|
||||||
|
fListenerId string
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
argsPrefix := "CERTIMATE_DEPLOYER_CTCCCLOUDELB_"
|
||||||
|
|
||||||
|
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||||
|
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||||
|
flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "")
|
||||||
|
flag.StringVar(&fSecretAccessKey, argsPrefix+"SECRETACCESSKEY", "", "")
|
||||||
|
flag.StringVar(&fRegionId, argsPrefix+"REGIONID", "", "")
|
||||||
|
flag.StringVar(&fLoadbalancerId, argsPrefix+"LOADBALANCERID", "", "")
|
||||||
|
flag.StringVar(&fListenerId, argsPrefix+"LISTENERID", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Shell command to run this test:
|
||||||
|
|
||||||
|
go test -v ./ctcccloud_elb_test.go -args \
|
||||||
|
--CERTIMATE_DEPLOYER_CTCCCLOUDELB_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||||
|
--CERTIMATE_DEPLOYER_CTCCCLOUDELB_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||||
|
--CERTIMATE_DEPLOYER_CTCCCLOUDELB_ACCESSKEYID="your-access-key-id" \
|
||||||
|
--CERTIMATE_DEPLOYER_CTCCCLOUDELB_SECRETACCESSKEY="your-secret-access-key" \
|
||||||
|
--CERTIMATE_DEPLOYER_CTCCCLOUDELB_REGIONID="your-region-id" \
|
||||||
|
--CERTIMATE_DEPLOYER_CTCCCLOUDELB_LOADBALANCERID="your-elb-instance-id" \
|
||||||
|
--CERTIMATE_DEPLOYER_CTCCCLOUDELB_LISTENERID="your-elb-listener-id"
|
||||||
|
*/
|
||||||
|
func TestDeploy(t *testing.T) {
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
t.Run("Deploy_ToLoadbalancer", func(t *testing.T) {
|
||||||
|
t.Log(strings.Join([]string{
|
||||||
|
"args:",
|
||||||
|
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||||
|
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
||||||
|
fmt.Sprintf("ACCESSKEYID: %v", fAccessKeyId),
|
||||||
|
fmt.Sprintf("SECRETACCESSKEY: %v", fSecretAccessKey),
|
||||||
|
fmt.Sprintf("REGIONID: %v", fRegionId),
|
||||||
|
fmt.Sprintf("LOADBALANCERID: %v", fLoadbalancerId),
|
||||||
|
}, "\n"))
|
||||||
|
|
||||||
|
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||||
|
AccessKeyId: fAccessKeyId,
|
||||||
|
SecretAccessKey: fSecretAccessKey,
|
||||||
|
RegionId: fRegionId,
|
||||||
|
ResourceType: provider.RESOURCE_TYPE_LOADBALANCER,
|
||||||
|
LoadbalancerId: fLoadbalancerId,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("err: %+v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fInputCertData, _ := os.ReadFile(fInputCertPath)
|
||||||
|
fInputKeyData, _ := os.ReadFile(fInputKeyPath)
|
||||||
|
res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("err: %+v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("ok: %v", res)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Deploy_ToListener", func(t *testing.T) {
|
||||||
|
t.Log(strings.Join([]string{
|
||||||
|
"args:",
|
||||||
|
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||||
|
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
||||||
|
fmt.Sprintf("ACCESSKEYID: %v", fAccessKeyId),
|
||||||
|
fmt.Sprintf("SECRETACCESSKEY: %v", fSecretAccessKey),
|
||||||
|
fmt.Sprintf("REGIONID: %v", fRegionId),
|
||||||
|
fmt.Sprintf("LISTENERID: %v", fListenerId),
|
||||||
|
}, "\n"))
|
||||||
|
|
||||||
|
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||||
|
AccessKeyId: fAccessKeyId,
|
||||||
|
SecretAccessKey: fSecretAccessKey,
|
||||||
|
RegionId: fRegionId,
|
||||||
|
ResourceType: provider.RESOURCE_TYPE_LISTENER,
|
||||||
|
ListenerId: fListenerId,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("err: %+v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fInputCertData, _ := os.ReadFile(fInputCertPath)
|
||||||
|
fInputKeyData, _ := os.ReadFile(fInputKeyPath)
|
||||||
|
res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("err: %+v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("ok: %v", res)
|
||||||
|
})
|
||||||
|
}
|
@ -0,0 +1,133 @@
|
|||||||
|
package ctcccloudelb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
|
||||||
|
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||||
|
ctyunelb "github.com/usual2970/certimate/internal/pkg/sdk3rd/ctyun/elb"
|
||||||
|
certutil "github.com/usual2970/certimate/internal/pkg/utils/cert"
|
||||||
|
typeutil "github.com/usual2970/certimate/internal/pkg/utils/type"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UploaderConfig struct {
|
||||||
|
// 天翼云 AccessKeyId。
|
||||||
|
AccessKeyId string `json:"accessKeyId"`
|
||||||
|
// 天翼云 SecretAccessKey。
|
||||||
|
SecretAccessKey string `json:"secretAccessKey"`
|
||||||
|
// 天翼云资源池 ID。
|
||||||
|
RegionId string `json:"regionId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UploaderProvider struct {
|
||||||
|
config *UploaderConfig
|
||||||
|
logger *slog.Logger
|
||||||
|
sdkClient *ctyunelb.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ uploader.Uploader = (*UploaderProvider)(nil)
|
||||||
|
|
||||||
|
func NewUploader(config *UploaderConfig) (*UploaderProvider, error) {
|
||||||
|
if config == nil {
|
||||||
|
panic("config is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := createSdkClient(config.AccessKeyId, config.SecretAccessKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &UploaderProvider{
|
||||||
|
config: config,
|
||||||
|
logger: slog.Default(),
|
||||||
|
sdkClient: client,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UploaderProvider) WithLogger(logger *slog.Logger) uploader.Uploader {
|
||||||
|
if logger == nil {
|
||||||
|
u.logger = slog.New(slog.DiscardHandler)
|
||||||
|
} else {
|
||||||
|
u.logger = logger
|
||||||
|
}
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UploaderProvider) Upload(ctx context.Context, certPEM string, privkeyPEM string) (*uploader.UploadResult, error) {
|
||||||
|
// 解析证书内容
|
||||||
|
certX509, err := certutil.ParseCertificateFromPEM(certPEM)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询证书列表,避免重复上传
|
||||||
|
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=24&api=5692&data=88&isNormal=1&vid=82
|
||||||
|
listCertificateReq := &ctyunelb.ListCertificateRequest{
|
||||||
|
RegionID: typeutil.ToPtr(u.config.RegionId),
|
||||||
|
}
|
||||||
|
listCertificateResp, err := u.sdkClient.ListCertificate(listCertificateReq)
|
||||||
|
u.logger.Debug("sdk request 'elb.ListCertificate'", slog.Any("request", listCertificateReq), slog.Any("response", listCertificateResp))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to execute sdk request 'elb.ListCertificate': %w", err)
|
||||||
|
} else {
|
||||||
|
for _, certRecord := range listCertificateResp.ReturnObj {
|
||||||
|
var isSameCert bool
|
||||||
|
if certRecord.Certificate == certPEM {
|
||||||
|
isSameCert = true
|
||||||
|
} else {
|
||||||
|
oldCertX509, err := certutil.ParseCertificateFromPEM(certRecord.Certificate)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
isSameCert = certutil.EqualCertificate(certX509, oldCertX509)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果已存在相同证书,直接返回
|
||||||
|
if isSameCert {
|
||||||
|
u.logger.Info("ssl certificate already exists")
|
||||||
|
return &uploader.UploadResult{
|
||||||
|
CertId: certRecord.ID,
|
||||||
|
CertName: certRecord.Name,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成新证书名(需符合天翼云命名规则)
|
||||||
|
certName := fmt.Sprintf("certimate-%d", time.Now().UnixMilli())
|
||||||
|
|
||||||
|
// 创建证书
|
||||||
|
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=24&api=5685&data=88&isNormal=1&vid=82
|
||||||
|
createCertificateReq := &ctyunelb.CreateCertificateRequest{
|
||||||
|
ClientToken: typeutil.ToPtr(generateClientToken()),
|
||||||
|
RegionID: typeutil.ToPtr(u.config.RegionId),
|
||||||
|
Name: typeutil.ToPtr(certName),
|
||||||
|
Description: typeutil.ToPtr("upload from certimate"),
|
||||||
|
Type: typeutil.ToPtr("Server"),
|
||||||
|
Certificate: typeutil.ToPtr(certPEM),
|
||||||
|
PrivateKey: typeutil.ToPtr(privkeyPEM),
|
||||||
|
}
|
||||||
|
createCertificateResp, err := u.sdkClient.CreateCertificate(createCertificateReq)
|
||||||
|
u.logger.Debug("sdk request 'elb.CreateCertificate'", slog.Any("request", createCertificateReq), slog.Any("response", createCertificateResp))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to execute sdk request 'elb.CreateCertificate': %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &uploader.UploadResult{
|
||||||
|
CertId: createCertificateResp.ReturnObj.ID,
|
||||||
|
CertName: certName,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createSdkClient(accessKeyId, secretAccessKey string) (*ctyunelb.Client, error) {
|
||||||
|
return ctyunelb.NewClient(accessKeyId, secretAccessKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateClientToken() string {
|
||||||
|
return uuid.New().String()
|
||||||
|
}
|
@ -0,0 +1,77 @@
|
|||||||
|
package ctcccloudelb_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
provider "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/ctcccloud-elb"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
fInputCertPath string
|
||||||
|
fInputKeyPath string
|
||||||
|
fAccessKeyId string
|
||||||
|
fSecretAccessKey string
|
||||||
|
fRegionId string
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
argsPrefix := "CERTIMATE_UPLOADER_CTCCCLOUDELB_"
|
||||||
|
|
||||||
|
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||||
|
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||||
|
flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "")
|
||||||
|
flag.StringVar(&fSecretAccessKey, argsPrefix+"SECRETACCESSKEY", "", "")
|
||||||
|
flag.StringVar(&fRegionId, argsPrefix+"REGIONID", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Shell command to run this test:
|
||||||
|
|
||||||
|
go test -v ./ctcccloud_elb_test.go -args \
|
||||||
|
--CERTIMATE_UPLOADER_CTCCCLOUDELB_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||||
|
--CERTIMATE_UPLOADER_CTCCCLOUDELB_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||||
|
--CERTIMATE_UPLOADER_CTCCCLOUDELB_ACCESSKEYID="your-access-key-id" \
|
||||||
|
--CERTIMATE_UPLOADER_CTCCCLOUDELB_SECRETACCESSKEY="your-secret-access-key" \
|
||||||
|
--CERTIMATE_UPLOADER_CTCCCLOUDELB_REGIONID="your-region-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("ACCESSKEYID: %v", fAccessKeyId),
|
||||||
|
fmt.Sprintf("SECRETACCESSKEY: %v", fSecretAccessKey),
|
||||||
|
fmt.Sprintf("REGIONID: %v", fRegionId),
|
||||||
|
}, "\n"))
|
||||||
|
|
||||||
|
uploader, err := provider.NewUploader(&provider.UploaderConfig{
|
||||||
|
AccessKeyId: fAccessKeyId,
|
||||||
|
SecretAccessKey: fSecretAccessKey,
|
||||||
|
RegionId: fRegionId,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("err: %+v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fInputCertData, _ := os.ReadFile(fInputCertPath)
|
||||||
|
fInputKeyData, _ := os.ReadFile(fInputKeyPath)
|
||||||
|
res, err := uploader.Upload(context.Background(), string(fInputCertData), string(fInputKeyData))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("err: %+v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sres, _ := json.Marshal(res)
|
||||||
|
t.Logf("ok: %s", string(sres))
|
||||||
|
})
|
||||||
|
}
|
45
internal/pkg/sdk3rd/ctyun/elb/api_create_certificate.go
Normal file
45
internal/pkg/sdk3rd/ctyun/elb/api_create_certificate.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package elb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CreateCertificateRequest struct {
|
||||||
|
ClientToken *string `json:"clientToken,omitempty"`
|
||||||
|
RegionID *string `json:"regionID,omitempty"`
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
Description *string `json:"description,omitempty"`
|
||||||
|
Type *string `json:"type,omitempty"`
|
||||||
|
Certificate *string `json:"certificate,omitempty"`
|
||||||
|
PrivateKey *string `json:"privateKey,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateCertificateResponse struct {
|
||||||
|
baseResult
|
||||||
|
|
||||||
|
ReturnObj *struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
} `json:"returnObj,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) CreateCertificate(req *CreateCertificateRequest) (*CreateCertificateResponse, error) {
|
||||||
|
return c.CreateCertificateWithContext(context.Background(), req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) CreateCertificateWithContext(ctx context.Context, req *CreateCertificateRequest) (*CreateCertificateResponse, error) {
|
||||||
|
httpreq, err := c.newRequest(http.MethodPost, "/v4/elb/create-certificate")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
httpreq.SetBody(req)
|
||||||
|
httpreq.SetContext(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
result := &CreateCertificateResponse{}
|
||||||
|
if _, err := c.doRequestWithResult(httpreq, result); err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
56
internal/pkg/sdk3rd/ctyun/elb/api_list_certificate.go
Normal file
56
internal/pkg/sdk3rd/ctyun/elb/api_list_certificate.go
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package elb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ListCertificateRequest struct {
|
||||||
|
ClientToken *string `json:"clientToken,omitempty"`
|
||||||
|
RegionID *string `json:"regionID,omitempty"`
|
||||||
|
IDs *string `json:"IDs,omitempty"`
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
Type *string `json:"type,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListCertificateResponse struct {
|
||||||
|
baseResult
|
||||||
|
|
||||||
|
ReturnObj []*CertificateRecord `json:"returnObj,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListCertificate(req *ListCertificateRequest) (*ListCertificateResponse, error) {
|
||||||
|
return c.ListCertificateWithContext(context.Background(), req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListCertificateWithContext(ctx context.Context, req *ListCertificateRequest) (*ListCertificateResponse, error) {
|
||||||
|
httpreq, err := c.newRequest(http.MethodGet, "/v4/elb/list-certificate")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
if req.ClientToken != nil {
|
||||||
|
httpreq.SetQueryParam("clientToken", *req.ClientToken)
|
||||||
|
}
|
||||||
|
if req.RegionID != nil {
|
||||||
|
httpreq.SetQueryParam("regionID", *req.RegionID)
|
||||||
|
}
|
||||||
|
if req.IDs != nil {
|
||||||
|
httpreq.SetQueryParam("IDs", *req.IDs)
|
||||||
|
}
|
||||||
|
if req.Name != nil {
|
||||||
|
httpreq.SetQueryParam("name", *req.Name)
|
||||||
|
}
|
||||||
|
if req.Type != nil {
|
||||||
|
httpreq.SetQueryParam("type", *req.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
httpreq.SetContext(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
result := &ListCertificateResponse{}
|
||||||
|
if _, err := c.doRequestWithResult(httpreq, result); err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
64
internal/pkg/sdk3rd/ctyun/elb/api_list_listener.go
Normal file
64
internal/pkg/sdk3rd/ctyun/elb/api_list_listener.go
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package elb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ListListenerRequest struct {
|
||||||
|
ClientToken *string `json:"clientToken,omitempty"`
|
||||||
|
RegionID *string `json:"regionID,omitempty"`
|
||||||
|
ProjectID *string `json:"projectID,omitempty"`
|
||||||
|
IDs *string `json:"IDs,omitempty"`
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
LoadBalancerID *string `json:"loadBalancerID,omitempty"`
|
||||||
|
AccessControlID *string `json:"accessControlID,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListListenerResponse struct {
|
||||||
|
baseResult
|
||||||
|
|
||||||
|
ReturnObj []*ListenerRecord `json:"returnObj,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListListener(req *ListListenerRequest) (*ListListenerResponse, error) {
|
||||||
|
return c.ListListenerWithContext(context.Background(), req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListListenerWithContext(ctx context.Context, req *ListListenerRequest) (*ListListenerResponse, error) {
|
||||||
|
httpreq, err := c.newRequest(http.MethodGet, "/v4/elb/list-listener")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
if req.ClientToken != nil {
|
||||||
|
httpreq.SetQueryParam("clientToken", *req.ClientToken)
|
||||||
|
}
|
||||||
|
if req.RegionID != nil {
|
||||||
|
httpreq.SetQueryParam("regionID", *req.RegionID)
|
||||||
|
}
|
||||||
|
if req.ProjectID != nil {
|
||||||
|
httpreq.SetQueryParam("projectID", *req.ProjectID)
|
||||||
|
}
|
||||||
|
if req.IDs != nil {
|
||||||
|
httpreq.SetQueryParam("IDs", *req.IDs)
|
||||||
|
}
|
||||||
|
if req.Name != nil {
|
||||||
|
httpreq.SetQueryParam("name", *req.Name)
|
||||||
|
}
|
||||||
|
if req.LoadBalancerID != nil {
|
||||||
|
httpreq.SetQueryParam("loadBalancerID", *req.LoadBalancerID)
|
||||||
|
}
|
||||||
|
if req.LoadBalancerID != nil {
|
||||||
|
httpreq.SetQueryParam("accessControlID", *req.AccessControlID)
|
||||||
|
}
|
||||||
|
|
||||||
|
httpreq.SetContext(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
result := &ListListenerResponse{}
|
||||||
|
if _, err := c.doRequestWithResult(httpreq, result); err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
48
internal/pkg/sdk3rd/ctyun/elb/api_show_listener.go
Normal file
48
internal/pkg/sdk3rd/ctyun/elb/api_show_listener.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package elb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ShowListenerRequest struct {
|
||||||
|
ClientToken *string `json:"clientToken,omitempty"`
|
||||||
|
RegionID *string `json:"regionID,omitempty"`
|
||||||
|
ListenerID *string `json:"listenerID,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ShowListenerResponse struct {
|
||||||
|
baseResult
|
||||||
|
|
||||||
|
ReturnObj []*ListenerRecord `json:"returnObj,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ShowListener(req *ShowListenerRequest) (*ShowListenerResponse, error) {
|
||||||
|
return c.ShowListenerWithContext(context.Background(), req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ShowListenerWithContext(ctx context.Context, req *ShowListenerRequest) (*ShowListenerResponse, error) {
|
||||||
|
httpreq, err := c.newRequest(http.MethodGet, "/v4/elb/show-listener")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
if req.ClientToken != nil {
|
||||||
|
httpreq.SetQueryParam("clientToken", *req.ClientToken)
|
||||||
|
}
|
||||||
|
if req.RegionID != nil {
|
||||||
|
httpreq.SetQueryParam("regionID", *req.RegionID)
|
||||||
|
}
|
||||||
|
if req.ListenerID != nil {
|
||||||
|
httpreq.SetQueryParam("listenerID", *req.ListenerID)
|
||||||
|
}
|
||||||
|
|
||||||
|
httpreq.SetContext(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
result := &ShowListenerResponse{}
|
||||||
|
if _, err := c.doRequestWithResult(httpreq, result); err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
44
internal/pkg/sdk3rd/ctyun/elb/api_update_listener.go
Normal file
44
internal/pkg/sdk3rd/ctyun/elb/api_update_listener.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package elb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UpdateListenerRequest struct {
|
||||||
|
ClientToken *string `json:"clientToken,omitempty"`
|
||||||
|
RegionID *string `json:"regionID,omitempty"`
|
||||||
|
ListenerID *string `json:"listenerID,omitempty"`
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
Description *string `json:"description,omitempty"`
|
||||||
|
CertificateID *string `json:"certificateID,omitempty"`
|
||||||
|
CaEnabled *bool `json:"caEnabled,omitempty"`
|
||||||
|
ClientCertificateID *string `json:"clientCertificateID,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateListenerResponse struct {
|
||||||
|
baseResult
|
||||||
|
|
||||||
|
ReturnObj []*ListenerRecord `json:"returnObj,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) UpdateListener(req *UpdateListenerRequest) (*UpdateListenerResponse, error) {
|
||||||
|
return c.UpdateListenerWithContext(context.Background(), req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) UpdateListenerWithContext(ctx context.Context, req *UpdateListenerRequest) (*UpdateListenerResponse, error) {
|
||||||
|
httpreq, err := c.newRequest(http.MethodPost, "/v4/elb/update-listener")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
httpreq.SetBody(req)
|
||||||
|
httpreq.SetContext(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
result := &UpdateListenerResponse{}
|
||||||
|
if _, err := c.doRequestWithResult(httpreq, result); err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
50
internal/pkg/sdk3rd/ctyun/elb/client.go
Normal file
50
internal/pkg/sdk3rd/ctyun/elb/client.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package elb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-resty/resty/v2"
|
||||||
|
"github.com/usual2970/certimate/internal/pkg/sdk3rd/ctyun/openapi"
|
||||||
|
)
|
||||||
|
|
||||||
|
const endpoint = "https://ctelb-global.ctapi.ctyun.cn"
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
client *openapi.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClient(accessKeyId, secretAccessKey string) (*Client, error) {
|
||||||
|
client, err := openapi.NewClient(endpoint, accessKeyId, secretAccessKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Client{client: client}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) SetTimeout(timeout time.Duration) *Client {
|
||||||
|
c.client.SetTimeout(timeout)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) newRequest(method string, path string) (*resty.Request, error) {
|
||||||
|
return c.client.NewRequest(method, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) doRequest(request *resty.Request) (*resty.Response, error) {
|
||||||
|
return c.client.DoRequest(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) doRequestWithResult(request *resty.Request, result baseResultInterface) (*resty.Response, error) {
|
||||||
|
response, err := c.client.DoRequestWithResult(request, result)
|
||||||
|
if err == nil {
|
||||||
|
statusCode := result.GetStatusCode()
|
||||||
|
errorCode := result.GetError()
|
||||||
|
if (statusCode != "" && statusCode != "200" && statusCode != "800") || (errorCode != "" && errorCode != "SUCCESS") {
|
||||||
|
return response, fmt.Errorf("sdkerr: api error, code='%s', message='%s', errorCode='%s', description='%s'", statusCode, result.GetMessage(), result.GetMessage(), result.GetDescription())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return response, err
|
||||||
|
}
|
104
internal/pkg/sdk3rd/ctyun/elb/types.go
Normal file
104
internal/pkg/sdk3rd/ctyun/elb/types.go
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
package elb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type baseResultInterface interface {
|
||||||
|
GetStatusCode() string
|
||||||
|
GetMessage() string
|
||||||
|
GetError() string
|
||||||
|
GetDescription() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type baseResult struct {
|
||||||
|
StatusCode json.RawMessage `json:"statusCode,omitempty"`
|
||||||
|
Message *string `json:"message,omitempty"`
|
||||||
|
Error *string `json:"error,omitempty"`
|
||||||
|
Description *string `json:"description,omitempty"`
|
||||||
|
RequestId *string `json:"requestId,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *baseResult) GetStatusCode() string {
|
||||||
|
if r.StatusCode == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder := json.NewDecoder(bytes.NewReader(r.StatusCode))
|
||||||
|
token, err := decoder.Token()
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
switch t := token.(type) {
|
||||||
|
case string:
|
||||||
|
return t
|
||||||
|
case float64:
|
||||||
|
return strconv.FormatFloat(t, 'f', -1, 64)
|
||||||
|
case json.Number:
|
||||||
|
return t.String()
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *baseResult) GetMessage() string {
|
||||||
|
if r.Message == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return *r.Message
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *baseResult) GetError() string {
|
||||||
|
if r.Error == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return *r.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *baseResult) GetDescription() string {
|
||||||
|
if r.Description == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return *r.Description
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ baseResultInterface = (*baseResult)(nil)
|
||||||
|
|
||||||
|
type CertificateRecord struct {
|
||||||
|
ID string `json:"ID"`
|
||||||
|
RegionID string `json:"regionID"`
|
||||||
|
AzName string `json:"azName"`
|
||||||
|
ProjectID string `json:"projectID"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Certificate string `json:"certificate"`
|
||||||
|
PrivateKey string `json:"privateKey"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
CreatedTime string `json:"createdTime"`
|
||||||
|
UpdatedTime string `json:"updatedTime"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListenerRecord struct {
|
||||||
|
ID string `json:"ID"`
|
||||||
|
RegionID string `json:"regionID"`
|
||||||
|
AzName string `json:"azName"`
|
||||||
|
ProjectID string `json:"projectID"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
LoadBalancerID string `json:"loadBalancerID"`
|
||||||
|
Protocol string `json:"protocol"`
|
||||||
|
ProtocolPort int32 `json:"protocolPort"`
|
||||||
|
CertificateID string `json:"certificateID,omitempty"`
|
||||||
|
CaEnabled bool `json:"caEnabled"`
|
||||||
|
ClientCertificateID string `json:"clientCertificateID,omitempty"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
CreatedTime string `json:"createdTime"`
|
||||||
|
UpdatedTime string `json:"updatedTime"`
|
||||||
|
}
|
@ -50,6 +50,7 @@ import DeployNodeConfigFormBytePlusCDNConfig from "./DeployNodeConfigFormBytePlu
|
|||||||
import DeployNodeConfigFormCdnflyConfig from "./DeployNodeConfigFormCdnflyConfig";
|
import DeployNodeConfigFormCdnflyConfig from "./DeployNodeConfigFormCdnflyConfig";
|
||||||
import DeployNodeConfigFormCTCCCloudAOConfig from "./DeployNodeConfigFormCTCCCloudAOConfig";
|
import DeployNodeConfigFormCTCCCloudAOConfig from "./DeployNodeConfigFormCTCCCloudAOConfig";
|
||||||
import DeployNodeConfigFormCTCCCloudCDNConfig from "./DeployNodeConfigFormCTCCCloudCDNConfig";
|
import DeployNodeConfigFormCTCCCloudCDNConfig from "./DeployNodeConfigFormCTCCCloudCDNConfig";
|
||||||
|
import DeployNodeConfigFormCTCCCloudELBConfig from "./DeployNodeConfigFormCTCCCloudELBConfig";
|
||||||
import DeployNodeConfigFormCTCCCloudICDNConfig from "./DeployNodeConfigFormCTCCCloudICDNConfig";
|
import DeployNodeConfigFormCTCCCloudICDNConfig from "./DeployNodeConfigFormCTCCCloudICDNConfig";
|
||||||
import DeployNodeConfigFormCTCCCloudLVDNConfig from "./DeployNodeConfigFormCTCCCloudLVDNConfig";
|
import DeployNodeConfigFormCTCCCloudLVDNConfig from "./DeployNodeConfigFormCTCCCloudLVDNConfig";
|
||||||
import DeployNodeConfigFormDogeCloudCDNConfig from "./DeployNodeConfigFormDogeCloudCDNConfig";
|
import DeployNodeConfigFormDogeCloudCDNConfig from "./DeployNodeConfigFormDogeCloudCDNConfig";
|
||||||
@ -273,6 +274,8 @@ const DeployNodeConfigForm = forwardRef<DeployNodeConfigFormInstance, DeployNode
|
|||||||
return <DeployNodeConfigFormCTCCCloudAOConfig {...nestedFormProps} />;
|
return <DeployNodeConfigFormCTCCCloudAOConfig {...nestedFormProps} />;
|
||||||
case DEPLOYMENT_PROVIDERS.CTCCCLOUD_CDN:
|
case DEPLOYMENT_PROVIDERS.CTCCCLOUD_CDN:
|
||||||
return <DeployNodeConfigFormCTCCCloudCDNConfig {...nestedFormProps} />;
|
return <DeployNodeConfigFormCTCCCloudCDNConfig {...nestedFormProps} />;
|
||||||
|
case DEPLOYMENT_PROVIDERS.CTCCCLOUD_ELB:
|
||||||
|
return <DeployNodeConfigFormCTCCCloudELBConfig {...nestedFormProps} />;
|
||||||
case DEPLOYMENT_PROVIDERS.CTCCCLOUD_ICDN:
|
case DEPLOYMENT_PROVIDERS.CTCCCLOUD_ICDN:
|
||||||
return <DeployNodeConfigFormCTCCCloudICDNConfig {...nestedFormProps} />;
|
return <DeployNodeConfigFormCTCCCloudICDNConfig {...nestedFormProps} />;
|
||||||
case DEPLOYMENT_PROVIDERS.CTCCCLOUD_LVDN:
|
case DEPLOYMENT_PROVIDERS.CTCCCLOUD_LVDN:
|
||||||
|
@ -0,0 +1,121 @@
|
|||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { Form, type FormInstance, Input, Select } from "antd";
|
||||||
|
import { createSchemaFieldRule } from "antd-zod";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import Show from "@/components/Show";
|
||||||
|
|
||||||
|
type DeployNodeConfigFormCTCCCloudELBConfigFieldValues = Nullish<{
|
||||||
|
regionId: string;
|
||||||
|
resourceType: string;
|
||||||
|
loadbalancerId?: string;
|
||||||
|
listenerId?: string;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export type DeployNodeConfigFormCTCCCloudELBConfigProps = {
|
||||||
|
form: FormInstance;
|
||||||
|
formName: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
initialValues?: DeployNodeConfigFormCTCCCloudELBConfigFieldValues;
|
||||||
|
onValuesChange?: (values: DeployNodeConfigFormCTCCCloudELBConfigFieldValues) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const RESOURCE_TYPE_LOADBALANCER = "loadbalancer" as const;
|
||||||
|
const RESOURCE_TYPE_LISTENER = "listener" as const;
|
||||||
|
|
||||||
|
const initFormModel = (): DeployNodeConfigFormCTCCCloudELBConfigFieldValues => {
|
||||||
|
return {
|
||||||
|
resourceType: RESOURCE_TYPE_LISTENER,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const DeployNodeConfigFormCTCCCloudELBConfig = ({
|
||||||
|
form: formInst,
|
||||||
|
formName,
|
||||||
|
disabled,
|
||||||
|
initialValues,
|
||||||
|
onValuesChange,
|
||||||
|
}: DeployNodeConfigFormCTCCCloudELBConfigProps) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const formSchema = z.object({
|
||||||
|
resourceType: z.union([z.literal(RESOURCE_TYPE_LOADBALANCER), z.literal(RESOURCE_TYPE_LISTENER)], {
|
||||||
|
message: t("workflow_node.deploy.form.ctcccloud_elb_resource_type.placeholder"),
|
||||||
|
}),
|
||||||
|
regionId: z
|
||||||
|
.string({ message: t("workflow_node.deploy.form.ctcccloud_elb_region_id.placeholder") })
|
||||||
|
.nonempty(t("workflow_node.deploy.form.ctcccloud_elb_region_id.placeholder")),
|
||||||
|
loadbalancerId: z
|
||||||
|
.string()
|
||||||
|
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||||
|
.nullish()
|
||||||
|
.refine((v) => fieldResourceType !== RESOURCE_TYPE_LOADBALANCER || !!v?.trim(), t("workflow_node.deploy.form.ctcccloud_elb_loadbalancer_id.placeholder")),
|
||||||
|
listenerId: z
|
||||||
|
.string()
|
||||||
|
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||||
|
.nullish()
|
||||||
|
.refine((v) => fieldResourceType !== RESOURCE_TYPE_LISTENER || !!v?.trim(), t("workflow_node.deploy.form.ctcccloud_elb_listener_id.placeholder")),
|
||||||
|
});
|
||||||
|
const formRule = createSchemaFieldRule(formSchema);
|
||||||
|
|
||||||
|
const fieldResourceType = Form.useWatch("resourceType", formInst);
|
||||||
|
|
||||||
|
const handleFormChange = (_: unknown, values: z.infer<typeof formSchema>) => {
|
||||||
|
onValuesChange?.(values);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form
|
||||||
|
form={formInst}
|
||||||
|
disabled={disabled}
|
||||||
|
initialValues={initialValues ?? initFormModel()}
|
||||||
|
layout="vertical"
|
||||||
|
name={formName}
|
||||||
|
onValuesChange={handleFormChange}
|
||||||
|
>
|
||||||
|
<Form.Item name="resourceType" label={t("workflow_node.deploy.form.ctcccloud_elb_resource_type.label")} rules={[formRule]}>
|
||||||
|
<Select placeholder={t("workflow_node.deploy.form.ctcccloud_elb_resource_type.placeholder")}>
|
||||||
|
<Select.Option key={RESOURCE_TYPE_LOADBALANCER} value={RESOURCE_TYPE_LOADBALANCER}>
|
||||||
|
{t("workflow_node.deploy.form.ctcccloud_elb_resource_type.option.loadbalancer.label")}
|
||||||
|
</Select.Option>
|
||||||
|
<Select.Option key={RESOURCE_TYPE_LISTENER} value={RESOURCE_TYPE_LISTENER}>
|
||||||
|
{t("workflow_node.deploy.form.ctcccloud_elb_resource_type.option.listener.label")}
|
||||||
|
</Select.Option>
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="regionId"
|
||||||
|
label={t("workflow_node.deploy.form.ctcccloud_elb_region_id.label")}
|
||||||
|
rules={[formRule]}
|
||||||
|
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.ctcccloud_elb_region_id.tooltip") }}></span>}
|
||||||
|
>
|
||||||
|
<Input placeholder={t("workflow_node.deploy.form.ctcccloud_elb_region_id.placeholder")} />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Show when={fieldResourceType === RESOURCE_TYPE_LOADBALANCER}>
|
||||||
|
<Form.Item
|
||||||
|
name="loadbalancerId"
|
||||||
|
label={t("workflow_node.deploy.form.ctcccloud_elb_loadbalancer_id.label")}
|
||||||
|
rules={[formRule]}
|
||||||
|
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.ctcccloud_elb_loadbalancer_id.tooltip") }}></span>}
|
||||||
|
>
|
||||||
|
<Input placeholder={t("workflow_node.deploy.form.ctcccloud_elb_loadbalancer_id.placeholder")} />
|
||||||
|
</Form.Item>
|
||||||
|
</Show>
|
||||||
|
|
||||||
|
<Show when={fieldResourceType === RESOURCE_TYPE_LISTENER}>
|
||||||
|
<Form.Item
|
||||||
|
name="listenerId"
|
||||||
|
label={t("workflow_node.deploy.form.ctcccloud_elb_listener_id.label")}
|
||||||
|
rules={[formRule]}
|
||||||
|
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.ctcccloud_elb_listener_id.tooltip") }}></span>}
|
||||||
|
>
|
||||||
|
<Input placeholder={t("workflow_node.deploy.form.ctcccloud_elb_listener_id.placeholder")} />
|
||||||
|
</Form.Item>
|
||||||
|
</Show>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DeployNodeConfigFormCTCCCloudELBConfig;
|
@ -416,6 +416,7 @@ export const DEPLOYMENT_PROVIDERS = Object.freeze({
|
|||||||
CTCCCLOUD_AO: `${ACCESS_PROVIDERS.CTCCCLOUD}-ao`,
|
CTCCCLOUD_AO: `${ACCESS_PROVIDERS.CTCCCLOUD}-ao`,
|
||||||
CTCCCLOUD_CDN: `${ACCESS_PROVIDERS.CTCCCLOUD}-cdn`,
|
CTCCCLOUD_CDN: `${ACCESS_PROVIDERS.CTCCCLOUD}-cdn`,
|
||||||
CTCCCLOUD_CMS: `${ACCESS_PROVIDERS.CTCCCLOUD}-cms`,
|
CTCCCLOUD_CMS: `${ACCESS_PROVIDERS.CTCCCLOUD}-cms`,
|
||||||
|
CTCCCLOUD_ELB: `${ACCESS_PROVIDERS.CTCCCLOUD}-elb`,
|
||||||
CTCCCLOUD_ICDN: `${ACCESS_PROVIDERS.CTCCCLOUD}-icdn`,
|
CTCCCLOUD_ICDN: `${ACCESS_PROVIDERS.CTCCCLOUD}-icdn`,
|
||||||
CTCCCLOUD_LVDN: `${ACCESS_PROVIDERS.CTCCCLOUD}-lvdn`,
|
CTCCCLOUD_LVDN: `${ACCESS_PROVIDERS.CTCCCLOUD}-lvdn`,
|
||||||
DOGECLOUD_CDN: `${ACCESS_PROVIDERS.DOGECLOUD}-cdn`,
|
DOGECLOUD_CDN: `${ACCESS_PROVIDERS.DOGECLOUD}-cdn`,
|
||||||
@ -578,6 +579,7 @@ export const deploymentProvidersMap: Map<DeploymentProvider["type"] | string, De
|
|||||||
[DEPLOYMENT_PROVIDERS.CTCCCLOUD_CDN, "provider.ctcccloud.cdn", DEPLOYMENT_CATEGORIES.CDN],
|
[DEPLOYMENT_PROVIDERS.CTCCCLOUD_CDN, "provider.ctcccloud.cdn", DEPLOYMENT_CATEGORIES.CDN],
|
||||||
[DEPLOYMENT_PROVIDERS.CTCCCLOUD_ICDN, "provider.ctcccloud.icdn", DEPLOYMENT_CATEGORIES.CDN],
|
[DEPLOYMENT_PROVIDERS.CTCCCLOUD_ICDN, "provider.ctcccloud.icdn", DEPLOYMENT_CATEGORIES.CDN],
|
||||||
[DEPLOYMENT_PROVIDERS.CTCCCLOUD_AO, "provider.ctcccloud.ao", DEPLOYMENT_CATEGORIES.CDN],
|
[DEPLOYMENT_PROVIDERS.CTCCCLOUD_AO, "provider.ctcccloud.ao", DEPLOYMENT_CATEGORIES.CDN],
|
||||||
|
[DEPLOYMENT_PROVIDERS.CTCCCLOUD_ELB, "provider.ctcccloud.elb", DEPLOYMENT_CATEGORIES.LOADBALANCE],
|
||||||
[DEPLOYMENT_PROVIDERS.CTCCCLOUD_LVDN, "provider.ctcccloud.lvdn", DEPLOYMENT_CATEGORIES.AV],
|
[DEPLOYMENT_PROVIDERS.CTCCCLOUD_LVDN, "provider.ctcccloud.lvdn", DEPLOYMENT_CATEGORIES.AV],
|
||||||
[DEPLOYMENT_PROVIDERS.CTCCCLOUD_CMS, "provider.ctcccloud.cms_upload", DEPLOYMENT_CATEGORIES.SSL],
|
[DEPLOYMENT_PROVIDERS.CTCCCLOUD_CMS, "provider.ctcccloud.cms_upload", DEPLOYMENT_CATEGORIES.SSL],
|
||||||
[DEPLOYMENT_PROVIDERS.RAINYUN_RCDN, "provider.rainyun.rcdn", DEPLOYMENT_CATEGORIES.CDN],
|
[DEPLOYMENT_PROVIDERS.RAINYUN_RCDN, "provider.rainyun.rcdn", DEPLOYMENT_CATEGORIES.CDN],
|
||||||
|
@ -404,6 +404,20 @@
|
|||||||
"workflow_node.deploy.form.ctcccloud_cdn_domain.label": "CTCC StateCloud CDN domain",
|
"workflow_node.deploy.form.ctcccloud_cdn_domain.label": "CTCC StateCloud CDN domain",
|
||||||
"workflow_node.deploy.form.ctcccloud_cdn_domain.placeholder": "Please enter CTCC StateCloud CDN domain name",
|
"workflow_node.deploy.form.ctcccloud_cdn_domain.placeholder": "Please enter CTCC StateCloud CDN domain name",
|
||||||
"workflow_node.deploy.form.ctcccloud_cdn_domain.tooltip": "For more information, see <a href=\"https://cdn-console.ctyun.cn\" target=\"_blank\">https://cdn-console.ctyun.cn</a>",
|
"workflow_node.deploy.form.ctcccloud_cdn_domain.tooltip": "For more information, see <a href=\"https://cdn-console.ctyun.cn\" target=\"_blank\">https://cdn-console.ctyun.cn</a>",
|
||||||
|
"workflow_node.deploy.form.ctcccloud_elb_resource_type.label": "Resource type",
|
||||||
|
"workflow_node.deploy.form.ctcccloud_elb_resource_type.placeholder": "Please select resource type",
|
||||||
|
"workflow_node.deploy.form.ctcccloud_elb_resource_type.option.certificate.label": "ELB certificate",
|
||||||
|
"workflow_node.deploy.form.ctcccloud_elb_resource_type.option.loadbalancer.label": "ELB load balancer",
|
||||||
|
"workflow_node.deploy.form.ctcccloud_elb_resource_type.option.listener.label": "ELB listener",
|
||||||
|
"workflow_node.deploy.form.ctcccloud_elb_region_id.label": "CTCC StateCloud ELB region ID",
|
||||||
|
"workflow_node.deploy.form.ctcccloud_elb_region_id.placeholder": "Please enter CTCC StateCloud ELB region ID",
|
||||||
|
"workflow_node.deploy.form.ctcccloud_elb_region_id.tooltip": "For more information, see <a href=\"https://www.ctyun.cn/document/10026755/10196575\" target=\"_blank\">https://www.ctyun.cn/document/10026755/10196575</a>",
|
||||||
|
"workflow_node.deploy.form.ctcccloud_elb_loadbalancer_id.label": "CTCC StateCloud ELB load balancer ID",
|
||||||
|
"workflow_node.deploy.form.ctcccloud_elb_loadbalancer_id.placeholder": "Please enter CTCC StateCloud ELB load balancer ID",
|
||||||
|
"workflow_node.deploy.form.ctcccloud_elb_loadbalancer_id.tooltip": "For more information, see <a href=\"https://console.ctyun.cn/network/index/#/elb/elbList\" target=\"_blank\">https://console.ctyun.cn/network/index/#/elb/elbList</a>",
|
||||||
|
"workflow_node.deploy.form.ctcccloud_elb_listener_id.label": "CTCC StateCloud ELB listener ID",
|
||||||
|
"workflow_node.deploy.form.ctcccloud_elb_listener_id.placeholder": "Please enter CTCC StateCloud ELB listener ID",
|
||||||
|
"workflow_node.deploy.form.ctcccloud_elb_listener_id.tooltip": "For more information, see <a href=\"https://console.ctyun.cn/network/index/#/elb/elbList\" target=\"_blank\">https://console.ctyun.cn/network/index/#/elb/elbList</a>",
|
||||||
"workflow_node.deploy.form.ctcccloud_icdn_domain.label": "CTCC StateCloud ICDN domain",
|
"workflow_node.deploy.form.ctcccloud_icdn_domain.label": "CTCC StateCloud ICDN domain",
|
||||||
"workflow_node.deploy.form.ctcccloud_icdn_domain.placeholder": "Please enter CTCC StateCloud ICDN domain name",
|
"workflow_node.deploy.form.ctcccloud_icdn_domain.placeholder": "Please enter CTCC StateCloud ICDN domain name",
|
||||||
"workflow_node.deploy.form.ctcccloud_icdn_domain.tooltip": "For more information, see <a href=\"https://cdn-console.ctyun.cn\" target=\"_blank\">https://cdn-console.ctyun.cn</a>",
|
"workflow_node.deploy.form.ctcccloud_icdn_domain.tooltip": "For more information, see <a href=\"https://cdn-console.ctyun.cn\" target=\"_blank\">https://cdn-console.ctyun.cn</a>",
|
||||||
|
@ -403,6 +403,19 @@
|
|||||||
"workflow_node.deploy.form.ctcccloud_cdn_domain.label": "天翼云 CDN 加速域名",
|
"workflow_node.deploy.form.ctcccloud_cdn_domain.label": "天翼云 CDN 加速域名",
|
||||||
"workflow_node.deploy.form.ctcccloud_cdn_domain.placeholder": "请输入天翼云 CDN 加速域名(支持泛域名)",
|
"workflow_node.deploy.form.ctcccloud_cdn_domain.placeholder": "请输入天翼云 CDN 加速域名(支持泛域名)",
|
||||||
"workflow_node.deploy.form.ctcccloud_cdn_domain.tooltip": "这是什么?请参阅 <a href=\"https://cdn-console.ctyun.cn\" target=\"_blank\">https://cdn-console.ctyun.cn</a>",
|
"workflow_node.deploy.form.ctcccloud_cdn_domain.tooltip": "这是什么?请参阅 <a href=\"https://cdn-console.ctyun.cn\" target=\"_blank\">https://cdn-console.ctyun.cn</a>",
|
||||||
|
"workflow_node.deploy.form.ctcccloud_elb_resource_type.label": "证书部署方式",
|
||||||
|
"workflow_node.deploy.form.ctcccloud_elb_resource_type.placeholder": "请选择证书部署方式",
|
||||||
|
"workflow_node.deploy.form.ctcccloud_elb_resource_type.option.loadbalancer.label": "替换指定负载均衡器下的全部 HTTPS 监听器的证书",
|
||||||
|
"workflow_node.deploy.form.ctcccloud_elb_resource_type.option.listener.label": "替换指定监听器的证书",
|
||||||
|
"workflow_node.deploy.form.ctcccloud_elb_region_id.label": "天翼云 ELB 资源池 ID",
|
||||||
|
"workflow_node.deploy.form.ctcccloud_elb_region_id.placeholder": "请输入天翼云 ELB 资源池 ID",
|
||||||
|
"workflow_node.deploy.form.ctcccloud_elb_region_id.tooltip": "这是什么?请参阅 <a href=\"https://www.ctyun.cn/document/10026755/10196575\" target=\"_blank\">https://www.ctyun.cn/document/10026755/10196575</a>",
|
||||||
|
"workflow_node.deploy.form.ctcccloud_elb_loadbalancer_id.label": "天翼云 ELB 负载均衡器 ID",
|
||||||
|
"workflow_node.deploy.form.ctcccloud_elb_loadbalancer_id.placeholder": "请输入天翼云 ELB 负载均衡器 ID",
|
||||||
|
"workflow_node.deploy.form.ctcccloud_elb_loadbalancer_id.tooltip": "这是什么?请参阅 <a href=\"https://console.ctyun.cn/network/index/#/elb/elbList\" target=\"_blank\">https://console.ctyun.cn/network/index/#/elb/elbList</a>",
|
||||||
|
"workflow_node.deploy.form.ctcccloud_elb_listener_id.label": "天翼云 ELB 监听器 ID",
|
||||||
|
"workflow_node.deploy.form.ctcccloud_elb_listener_id.placeholder": "请输入天翼云 ELB 监听器 ID",
|
||||||
|
"workflow_node.deploy.form.ctcccloud_elb_listener_id.tooltip": "这是什么?请参阅 <a href=\"https://console.ctyun.cn/network/index/#/elb/elbList\" target=\"_blank\">https://console.ctyun.cn/network/index/#/elb/elbList</a>",
|
||||||
"workflow_node.deploy.form.ctcccloud_icdn_domain.label": "天翼云 ICDN 加速域名",
|
"workflow_node.deploy.form.ctcccloud_icdn_domain.label": "天翼云 ICDN 加速域名",
|
||||||
"workflow_node.deploy.form.ctcccloud_icdn_domain.placeholder": "请输入天翼云 ICDN 加速域名(支持泛域名)",
|
"workflow_node.deploy.form.ctcccloud_icdn_domain.placeholder": "请输入天翼云 ICDN 加速域名(支持泛域名)",
|
||||||
"workflow_node.deploy.form.ctcccloud_icdn_domain.tooltip": "这是什么?请参阅 <a href=\"https://cdn-console.ctyun.cn\" target=\"_blank\">https://cdn-console.ctyun.cn</a>",
|
"workflow_node.deploy.form.ctcccloud_icdn_domain.tooltip": "这是什么?请参阅 <a href=\"https://cdn-console.ctyun.cn\" target=\"_blank\">https://cdn-console.ctyun.cn</a>",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user