mirror of
https://github.com/certimate-go/certimate.git
synced 2026-07-20 21:01:41 +08:00
feat(provider): new deployment provider: cmcccloud cdn
This commit is contained in:
parent
c277955e4d
commit
9eba19978d
13
go.mod
13
go.mod
@ -85,8 +85,10 @@ require (
|
||||
github.com/xhit/go-str2duration/v2 v2.1.0
|
||||
github.com/yunify/qingcloud-sdk-go v2.0.0-alpha.38+incompatible
|
||||
github.com/zenlayer/zenlayercloud-sdk-go v0.2.39
|
||||
gitlab.ecloud.com/ecloud/ecloudsdkcloudcore v1.0.0
|
||||
gitlab.ecloud.com/ecloud/ecloudsdkclouddns v1.0.1
|
||||
gitlab.ecloud.com/ecloud/ecloudsdkcore v1.0.0
|
||||
gitlab.ecloud.com/ecloud/ecloudsdkcmcdn v1.0.0
|
||||
gitlab.ecloud.com/ecloud/ecloudsdkcore v1.0.2
|
||||
golang.org/x/crypto v0.52.0
|
||||
golang.org/x/oauth2 v0.36.0
|
||||
golang.org/x/sync v0.20.0
|
||||
@ -288,5 +290,10 @@ require (
|
||||
modernc.org/sqlite v1.52.0 // indirect
|
||||
)
|
||||
|
||||
replace gitlab.ecloud.com/ecloud/ecloudsdkcore v1.0.0 => ./pkg/sdk3rd-forked/gitlab.ecloud.com/ecloud/ecloudsdkcore@v1.0.0
|
||||
replace gitlab.ecloud.com/ecloud/ecloudsdkclouddns v1.0.1 => ./pkg/sdk3rd-forked/gitlab.ecloud.com/ecloud/ecloudsdkclouddns@v1.0.1
|
||||
replace gitlab.ecloud.com/ecloud/ecloudsdkcloudcore v1.0.0 => ./pkg/sdk3rd-forked/gitlab.ecloud.com/ecloud/ecloudsdkcloudcore@v1.0.0+compact
|
||||
|
||||
replace gitlab.ecloud.com/ecloud/ecloudsdkclouddns v1.0.1 => ./pkg/sdk3rd-forked/gitlab.ecloud.com/ecloud/ecloudsdkclouddns@v1.0.1+compact
|
||||
|
||||
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
|
||||
|
||||
27
internal/certmgmt/deployers/sp_cmcccloud_cdn.go
Normal file
27
internal/certmgmt/deployers/sp_cmcccloud_cdn.go
Normal file
@ -0,0 +1,27 @@
|
||||
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-cdn"
|
||||
xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Registries.MustRegister(domain.DeploymentProviderTypeCMCCCloudCDN, 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,
|
||||
DomainMatchPattern: xmaps.GetString(options.ProviderExtendedConfig, "domainMatchPattern"),
|
||||
Domain: xmaps.GetString(options.ProviderExtendedConfig, "domain"),
|
||||
})
|
||||
return provider, err
|
||||
})
|
||||
}
|
||||
@ -357,6 +357,7 @@ const (
|
||||
DeploymentProviderTypeCacheFly = DeploymentProviderType(AccessProviderTypeCacheFly)
|
||||
DeploymentProviderTypeCdnfly = DeploymentProviderType(AccessProviderTypeCdnfly)
|
||||
DeploymentProviderTypeCloudflareSSL = DeploymentProviderType(AccessProviderTypeCloudflare + "-ssl")
|
||||
DeploymentProviderTypeCMCCCloudCDN = DeploymentProviderType(AccessProviderTypeCMCCCloud + "-cdn")
|
||||
DeploymentProviderTypeCPanel = DeploymentProviderType(AccessProviderTypeCPanel)
|
||||
DeploymentProviderTypeCTCCCloudAO = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-ao")
|
||||
DeploymentProviderTypeCTCCCloudCDN = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-cdn")
|
||||
|
||||
@ -10,8 +10,8 @@ import (
|
||||
"github.com/go-acme/lego/v5/challenge/dns01"
|
||||
"github.com/go-acme/lego/v5/platform/env"
|
||||
"github.com/samber/lo"
|
||||
"gitlab.ecloud.com/ecloud/ecloudsdkcloudcore/config"
|
||||
"gitlab.ecloud.com/ecloud/ecloudsdkclouddns/model"
|
||||
"gitlab.ecloud.com/ecloud/ecloudsdkcore/config"
|
||||
|
||||
"github.com/certimate-go/certimate/pkg/sdk3rd-trimmed/gitlab.ecloud.com/ecloud/ecloudsdkclouddns"
|
||||
)
|
||||
|
||||
287
pkg/core/deployer/providers/cmcccloud-cdn/cmcccloud_cdn.go
Normal file
287
pkg/core/deployer/providers/cmcccloud-cdn/cmcccloud_cdn.go
Normal file
@ -0,0 +1,287 @@
|
||||
package cmcccloudcdn
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
"github.com/samber/lo"
|
||||
"gitlab.ecloud.com/ecloud/ecloudsdkcmcdn/model"
|
||||
"gitlab.ecloud.com/ecloud/ecloudsdkcore/config"
|
||||
|
||||
"github.com/certimate-go/certimate/pkg/sdk3rd-trimmed/gitlab.ecloud.com/ecloud/ecloudsdkcmcdn"
|
||||
|
||||
"github.com/certimate-go/certimate/pkg/core"
|
||||
xcert "github.com/certimate-go/certimate/pkg/utils/cert"
|
||||
xcerthostname "github.com/certimate-go/certimate/pkg/utils/cert/hostname"
|
||||
)
|
||||
|
||||
type (
|
||||
Provider = core.Deployer
|
||||
DeployResult = core.DeployerDeployResult
|
||||
)
|
||||
|
||||
type DeployerConfig struct {
|
||||
// 移动云 AccessKeyId。
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 移动云 AccessKeySecret。
|
||||
AccessKeySecret string `json:"accessKeySecret"`
|
||||
// 域名匹配模式。
|
||||
// 零值时默认值 [DOMAIN_MATCH_PATTERN_EXACT]。
|
||||
DomainMatchPattern string `json:"domainMatchPattern,omitempty"`
|
||||
// 加速域名(不支持泛域名)。
|
||||
Domain string `json:"domain"`
|
||||
}
|
||||
|
||||
type Deployer struct {
|
||||
config *DeployerConfig
|
||||
logger *slog.Logger
|
||||
sdkClient *ecloudsdkcmcdn.Client
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create client: %w", err)
|
||||
}
|
||||
|
||||
return &Deployer{
|
||||
config: config,
|
||||
logger: slog.Default(),
|
||||
sdkClient: client,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Deployer) SetLogger(logger *slog.Logger) {
|
||||
if logger == nil {
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*DeployResult, error) {
|
||||
// 获取待部署的域名列表
|
||||
var domainIds []int32
|
||||
switch d.config.DomainMatchPattern {
|
||||
case "", DOMAIN_MATCH_PATTERN_EXACT:
|
||||
{
|
||||
if d.config.Domain == "" {
|
||||
return nil, fmt.Errorf("config `domain` is required")
|
||||
}
|
||||
|
||||
domainCandidates, err := d.getAllDomains(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
domains := lo.Filter(domainCandidates, func(domainItem *model.DescribeUserDomainsResponseList, _ int) bool {
|
||||
return d.config.Domain == lo.FromPtr(domainItem.DomainName)
|
||||
})
|
||||
if len(domains) == 0 {
|
||||
return nil, fmt.Errorf("could not find domain")
|
||||
}
|
||||
|
||||
domainIds = lo.Map(domains, func(domainItem *model.DescribeUserDomainsResponseList, _ int) int32 {
|
||||
return lo.FromPtr(domainItem.DomainId)
|
||||
})
|
||||
}
|
||||
|
||||
case DOMAIN_MATCH_PATTERN_WILDCARD:
|
||||
{
|
||||
if d.config.Domain == "" {
|
||||
return nil, fmt.Errorf("config `domain` is required")
|
||||
}
|
||||
|
||||
domainCandidates, err := d.getAllDomains(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
domains := lo.Filter(domainCandidates, func(domainItem *model.DescribeUserDomainsResponseList, _ int) bool {
|
||||
return xcerthostname.IsMatch(d.config.Domain, lo.FromPtr(domainItem.DomainName))
|
||||
})
|
||||
if len(domains) == 0 {
|
||||
return nil, fmt.Errorf("could not find any domains matched by wildcard")
|
||||
}
|
||||
|
||||
domainIds = lo.Map(domains, func(domainItem *model.DescribeUserDomainsResponseList, _ int) int32 {
|
||||
return lo.FromPtr(domainItem.DomainId)
|
||||
})
|
||||
}
|
||||
|
||||
case DOMAIN_MATCH_PATTERN_CERTSAN:
|
||||
{
|
||||
domainCandidates, err := d.getAllDomains(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
domains := lo.Filter(domainCandidates, func(domainItem *model.DescribeUserDomainsResponseList, _ int) bool {
|
||||
return xcerthostname.IsMatchByCertificatePEM(certPEM, lo.FromPtr(domainItem.DomainName))
|
||||
})
|
||||
if len(domains) == 0 {
|
||||
return nil, fmt.Errorf("could not find any domains matched by certificate")
|
||||
}
|
||||
|
||||
domainIds = lo.Map(domains, func(domainItem *model.DescribeUserDomainsResponseList, _ int) int32 {
|
||||
return lo.FromPtr(domainItem.DomainId)
|
||||
})
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported domain match pattern: '%s'", d.config.DomainMatchPattern)
|
||||
}
|
||||
|
||||
// 遍历更新域名证书
|
||||
if len(domainIds) == 0 {
|
||||
d.logger.Info("no cdn domains to deploy")
|
||||
} else {
|
||||
d.logger.Info("found cdn domains to deploy", slog.Any("domainIds", domainIds))
|
||||
var errs []error
|
||||
|
||||
for _, domainId := range domainIds {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
if err := d.updateDomainCertificate(ctx, domainId, certPEM, privkeyPEM); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
return nil, errors.Join(errs...)
|
||||
}
|
||||
}
|
||||
|
||||
return &DeployResult{}, nil
|
||||
}
|
||||
|
||||
func (d *Deployer) getAllDomains(ctx context.Context) ([]*model.DescribeUserDomainsResponseList, error) {
|
||||
domains := make([]*model.DescribeUserDomainsResponseList, 0)
|
||||
|
||||
// 查询域名列表
|
||||
// REF: https://ecloud.10086.cn/op-help-center/doc/article/71517
|
||||
describeUserDomainsPage := 1
|
||||
describeUserDomainsPageSize := 10
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
describeUserDomainsReq := &model.DescribeUserDomainsRequest{
|
||||
&model.DescribeUserDomainsQuery{
|
||||
Page: lo.ToPtr(fmt.Sprintf("%d", describeUserDomainsPage)),
|
||||
PageSize: lo.ToPtr(fmt.Sprintf("%d", describeUserDomainsPageSize)),
|
||||
},
|
||||
}
|
||||
describeUserDomainsResp, err := d.sdkClient.DescribeUserDomains(describeUserDomainsReq)
|
||||
d.logger.Debug("sdk request 'ecdn.DescribeUserDomains'", slog.Any("request", describeUserDomainsReq), slog.Any("response", describeUserDomainsResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'ecdn.DescribeUserDomains': %w", err)
|
||||
}
|
||||
|
||||
if describeUserDomainsResp.Body == nil || describeUserDomainsResp.Body.List == nil {
|
||||
break
|
||||
}
|
||||
|
||||
ignoredStatuses := []string{"ADD_AUDITING", "ADD_OPENING", "PAUSE_AUDITING", "PAUSE_HANDLING", "OFFLINE_AUDITING", "OFFLINE_HANDLING", "OFFLINE", "AUDIT_FAIL", "ADD_FAIL", "OFFLINE_FAIL"}
|
||||
for _, domainItem := range *describeUserDomainsResp.Body.List {
|
||||
if lo.FromPtr(domainItem.Deleted) {
|
||||
continue
|
||||
}
|
||||
if lo.Contains(ignoredStatuses, string(lo.FromPtr(domainItem.DomainStatus))) {
|
||||
continue
|
||||
}
|
||||
|
||||
domains = append(domains, &domainItem)
|
||||
}
|
||||
|
||||
if len(*describeUserDomainsResp.Body.List) < describeUserDomainsPageSize {
|
||||
break
|
||||
}
|
||||
|
||||
describeUserDomainsPage++
|
||||
}
|
||||
|
||||
return domains, nil
|
||||
}
|
||||
|
||||
func (d *Deployer) updateDomainCertificate(ctx context.Context, cloudDomainId int32, certPEM, privkeyPEM string) error {
|
||||
// 查询域名详情
|
||||
// REF: https://ecloud.10086.cn/op-help-center/doc/article/71520
|
||||
describeCdnDomainDetailReq := &model.DescribeCdnDomainDetailRequest{
|
||||
&model.DescribeCdnDomainDetailPath{
|
||||
DomainId: lo.ToPtr(fmt.Sprintf("%d", cloudDomainId)),
|
||||
},
|
||||
}
|
||||
describeCdnDomainDetailResp, err := d.sdkClient.DescribeCdnDomainDetail(describeCdnDomainDetailReq)
|
||||
d.logger.Debug("sdk request 'ecdn.DescribeCdnDomainDetail'", slog.Any("request", describeCdnDomainDetailReq), slog.Any("response", describeCdnDomainDetailResp))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'ecdn.DescribeCdnDomainDetail': %w", err)
|
||||
}
|
||||
|
||||
// 查询证书详情,避免重复上传
|
||||
// REF: https://ecloud.10086.cn/op-help-center/doc/article/71524
|
||||
if lo.FromPtr(describeCdnDomainDetailResp.Body.CrtUniqueId) != "" {
|
||||
describeCdnCertificateDetailReq := &model.DescribeCdnCertificateDetailRequest{
|
||||
&model.DescribeCdnCertificateDetailPath{
|
||||
UniqueId: describeCdnDomainDetailResp.Body.CrtUniqueId,
|
||||
},
|
||||
}
|
||||
describeCdnCertificateDetailResp, err := d.sdkClient.DescribeCdnCertificateDetail(describeCdnCertificateDetailReq)
|
||||
d.logger.Debug("sdk request 'ecdn.DescribeCdnCertificateDetail'", slog.Any("request", describeCdnCertificateDetailReq), slog.Any("response", describeCdnCertificateDetailResp))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'ecdn.DescribeCdnCertificateDetail': %w", err)
|
||||
} else {
|
||||
if xcert.EqualCertificatesFromPEM(certPEM, lo.FromPtr(describeCdnCertificateDetailResp.Body.Certificate)) {
|
||||
d.logger.Info("ssl certificate already deployed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 添加域名证书
|
||||
addDomainServerCertificateReq := &model.AddDomainServerCertificateRequest{
|
||||
&model.AddDomainServerCertificateBody{
|
||||
DomainId: lo.ToPtr(cloudDomainId),
|
||||
CrtName: lo.ToPtr(fmt.Sprintf("certimate-%d", time.Now().UnixMilli())),
|
||||
Certificate: lo.ToPtr(certPEM),
|
||||
PrivateKey: lo.ToPtr(privkeyPEM),
|
||||
},
|
||||
}
|
||||
addDomainServerCertificateResp, err := d.sdkClient.AddDomainServerCertificate(addDomainServerCertificateReq)
|
||||
d.logger.Debug("sdk request 'ecdn.AddDomainServerCertificate'", slog.Any("request", addDomainServerCertificateReq), slog.Any("response", addDomainServerCertificateResp))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'ecdn.AddDomainServerCertificate': %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createSDKClient(accessKeyId, accessKeySecret string) (*ecloudsdkcmcdn.Client, error) {
|
||||
ak := accessKeyId
|
||||
sk := accessKeySecret
|
||||
|
||||
// 资源池一览 https://ecloud.10086.cn/op-help-center/doc/article/54462
|
||||
poolId := "CIDC-CORE-00"
|
||||
|
||||
client := ecloudsdkcmcdn.NewClient(&config.Config{
|
||||
AccessKey: &ak,
|
||||
SecretKey: &sk,
|
||||
PoolId: &poolId,
|
||||
})
|
||||
|
||||
return client, nil
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
package cmcccloudcdn_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/certimate-go/certimate/pkg/core/deployer/internal/tester"
|
||||
impl "github.com/certimate-go/certimate/pkg/core/deployer/providers/cmcccloud-cdn"
|
||||
)
|
||||
|
||||
var (
|
||||
fp = tester.Args("CMCCCLOUDCDN_")
|
||||
fTestCertPath string
|
||||
fTestKeyPath string
|
||||
fAccessKeyId string
|
||||
fAccessKeySecret string
|
||||
fDomain string
|
||||
)
|
||||
|
||||
func init() {
|
||||
fp.DefineString(&fTestCertPath, "TESTCERTPATH")
|
||||
fp.DefineString(&fTestKeyPath, "TESTKEYPATH")
|
||||
fp.DefineString(&fAccessKeyId, "ACCESSKEYID")
|
||||
fp.DefineString(&fAccessKeySecret, "ACCESSKEYSECRET")
|
||||
fp.DefineString(&fDomain, "DOMAIN")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -v ./cmcccloud_cdn_test.go -args \
|
||||
--CMCCCLOUDCDN_TESTCERTPATH="/path/to/your-test-cert.pem" \
|
||||
--CMCCCLOUDCDN_TESTKEYPATH="/path/to/your-test-key.pem" \
|
||||
--CMCCCLOUDCDN_ACCESSKEYID="your-access-key-id" \
|
||||
--CMCCCLOUDCDN_ACCESSKEYSECRET="your-access-key-secret" \
|
||||
--CMCCCLOUDCDN_DOMAIN="example.com"
|
||||
*/
|
||||
func TestProvider(t *testing.T) {
|
||||
fp.Parse()
|
||||
|
||||
t.Run("Deploy", func(t *testing.T) {
|
||||
provider, err := impl.NewDeployer(&impl.DeployerConfig{
|
||||
AccessKeyId: fAccessKeyId,
|
||||
AccessKeySecret: fAccessKeySecret,
|
||||
DomainMatchPattern: impl.DOMAIN_MATCH_PATTERN_EXACT,
|
||||
Domain: fDomain,
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("err: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
tester.TestDeploy(t, provider, tester.TestDeployArgs{CertPath: fTestCertPath, KeyPath: fTestKeyPath})
|
||||
})
|
||||
}
|
||||
10
pkg/core/deployer/providers/cmcccloud-cdn/consts.go
Normal file
10
pkg/core/deployer/providers/cmcccloud-cdn/consts.go
Normal file
@ -0,0 +1,10 @@
|
||||
package cmcccloudcdn
|
||||
|
||||
const (
|
||||
// 匹配模式:精确匹配。
|
||||
DOMAIN_MATCH_PATTERN_EXACT = "exact"
|
||||
// 匹配模式:通配符匹配。
|
||||
DOMAIN_MATCH_PATTERN_WILDCARD = "wildcard"
|
||||
// 匹配模式:证书 SAN 匹配。
|
||||
DOMAIN_MATCH_PATTERN_CERTSAN = "certsan"
|
||||
)
|
||||
@ -1 +1 @@
|
||||
Subproject commit 0c5c8fe9448323c68fd25d5dfe0e2471e0209400
|
||||
Subproject commit ad2925860f15794f131bff0aef60d738100d1a93
|
||||
@ -1,22 +1,22 @@
|
||||
package ecloudsdkclouddns
|
||||
|
||||
import (
|
||||
"gitlab.ecloud.com/ecloud/ecloudsdkcloudcore"
|
||||
"gitlab.ecloud.com/ecloud/ecloudsdkcloudcore/config"
|
||||
"gitlab.ecloud.com/ecloud/ecloudsdkclouddns/model"
|
||||
"gitlab.ecloud.com/ecloud/ecloudsdkcore"
|
||||
"gitlab.ecloud.com/ecloud/ecloudsdkcore/config"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
APIClient *ecloudsdkcore.APIClient
|
||||
APIClient *ecloudsdkcloudcore.APIClient
|
||||
config *config.Config
|
||||
httpRequest *ecloudsdkcore.HttpRequest
|
||||
httpRequest *ecloudsdkcloudcore.HttpRequest
|
||||
}
|
||||
|
||||
func NewClient(config *config.Config) *Client {
|
||||
client := &Client{}
|
||||
client.config = config
|
||||
apiClient := ecloudsdkcore.NewAPIClient()
|
||||
httpRequest := ecloudsdkcore.NewDefaultHttpRequest()
|
||||
apiClient := ecloudsdkcloudcore.NewAPIClient()
|
||||
httpRequest := ecloudsdkcloudcore.NewDefaultHttpRequest()
|
||||
httpRequest.Product = product
|
||||
httpRequest.Version = version
|
||||
httpRequest.SdkVersion = sdkVersion
|
||||
|
||||
@ -0,0 +1,179 @@
|
||||
package ecloudsdkcmcdn
|
||||
|
||||
import (
|
||||
"gitlab.ecloud.com/ecloud/ecloudsdkcmcdn/model"
|
||||
"gitlab.ecloud.com/ecloud/ecloudsdkcore"
|
||||
"gitlab.ecloud.com/ecloud/ecloudsdkcore/config"
|
||||
"gitlab.ecloud.com/ecloud/ecloudsdkcore/param"
|
||||
"gitlab.ecloud.com/ecloud/ecloudsdkcore/request"
|
||||
"gitlab.ecloud.com/ecloud/ecloudsdkcore/utils"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
apiClient *ecloudsdkcore.APIClient
|
||||
config *config.Config
|
||||
httpRequest *request.HttpRequest
|
||||
allRegions map[string]string
|
||||
}
|
||||
|
||||
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 = "CM-CDN"
|
||||
version = "v1"
|
||||
sdkVersion = "1.0.0"
|
||||
)
|
||||
|
||||
func (c *Client) initRegions() map[string]string {
|
||||
m := map[string]string{
|
||||
"CIDC-RP-04": "https://console-yunnan-1.cmecloud.cn:8443",
|
||||
"CIDC-RP-16": "https://console-qinghai-1.cmecloud.cn:8443",
|
||||
"CIDC-RP-25": "https://console-wuxi-1.cmecloud.cn:8443",
|
||||
"CIDC-RP-26": "https://console-dongguan-1.cmecloud.cn:8443",
|
||||
"CIDC-RP-27": "https://console-yaan-1.cmecloud.cn:8443",
|
||||
"CIDC-RP-28": "https://console-zhengzhou-1.cmecloud.cn:8443",
|
||||
"CIDC-RP-29": "https://console-beijing-2.cmecloud.cn:8443",
|
||||
"CIDC-RP-30": "https://console-zhuzhou-1.cmecloud.cn:8443",
|
||||
"CIDC-RP-31": "https://console-jinan-1.cmecloud.cn:8443",
|
||||
"CIDC-RP-32": "https://console-xian-1.cmecloud.cn:8443",
|
||||
"CIDC-RP-33": "https://console-shanghai-1.cmecloud.cn:8443",
|
||||
"CIDC-RP-34": "https://console-chongqing-1.cmecloud.cn:8443",
|
||||
"CIDC-RP-35": "https://console-ningbo-1.cmecloud.cn:8443",
|
||||
"CIDC-RP-36": "https://console-tianjin-1.cmecloud.cn:8443",
|
||||
"CIDC-RP-37": "https://console-jilin-1.cmecloud.cn:8443",
|
||||
"CIDC-RP-38": "https://console-hubei-1.cmecloud.cn:8443",
|
||||
"CIDC-RP-39": "https://console-jiangxi-1.cmecloud.cn:8443",
|
||||
"CIDC-RP-40": "https://console-gansu-1.cmecloud.cn:8443",
|
||||
"CIDC-RP-41": "https://console-shanxi-1.cmecloud.cn:8443",
|
||||
"CIDC-RP-42": "https://console-liaoning-1.cmecloud.cn:8443",
|
||||
"CIDC-RP-43": "https://console-yunnan-2.cmecloud.cn:8443",
|
||||
"CIDC-RP-44": "https://console-hebei-1.cmecloud.cn:8443",
|
||||
"CIDC-RP-45": "https://console-fujian-1.cmecloud.cn:8443",
|
||||
"CIDC-RP-46": "https://console-guangxi-1.cmecloud.cn:8443",
|
||||
"CIDC-RP-47": "https://console-anhui-1.cmecloud.cn:8443",
|
||||
"CIDC-RP-48": "https://console-huhehaote-1.cmecloud.cn:8443",
|
||||
"CIDC-RP-49": "https://console-guiyang-1.cmecloud.cn:8443",
|
||||
"CIDC-CORE-00": "https://ecloud.10086.cn",
|
||||
"CIDC-RP-53": "https://console-hainan-1.cmecloud.cn:8443",
|
||||
"CIDC-RP-54": "https://console-xinjiang-1.cmecloud.cn:8443",
|
||||
"CIDC-RP-55": "http://console-heilongjiang-1.cmecloud.cn:18080",
|
||||
"CIDC-BRP-25": "",
|
||||
"CIDC-RP-60": "",
|
||||
"CIDC-RP-61": "",
|
||||
"CIDC-RP-62": "",
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func (c *Client) setEndpoint(config *config.Config, httpRequest *request.HttpRequest) {
|
||||
if utils.IsUnSet(config.PoolId) {
|
||||
httpRequest.Endpoint = utils.DefaultEndpoint
|
||||
return
|
||||
}
|
||||
endpoint := c.allRegions[*config.PoolId]
|
||||
if utils.IsUnSet(endpoint) {
|
||||
httpRequest.Endpoint = utils.DefaultEndpoint
|
||||
return
|
||||
}
|
||||
httpRequest.Endpoint = endpoint
|
||||
}
|
||||
|
||||
func (c *Client) DescribeCdnCertificateDetail(request *model.DescribeCdnCertificateDetailRequest) (*model.DescribeCdnCertificateDetailResponse, error) {
|
||||
return c.DescribeCdnCertificateDetailWithConfig(request, nil)
|
||||
}
|
||||
|
||||
func (c *Client) DescribeCdnCertificateDetailWithConfig(request *model.DescribeCdnCertificateDetailRequest, runtimeConfig *config.RuntimeConfig) (*model.DescribeCdnCertificateDetailResponse, error) {
|
||||
params := param.NewParamsBuilder().
|
||||
Action("describeCdnCertificateDetail").
|
||||
Uri("/domainManager/openapi/certificate/describeCdnCertificateDetail/{uniqueId}").
|
||||
GatewayUri("/api/openapi-ecdn/domainManager/openapi/certificate/describeCdnCertificateDetail/{uniqueId}").
|
||||
Protocol("https").
|
||||
Method("GET").
|
||||
Request(request).
|
||||
Build()
|
||||
returnValue := &model.DescribeCdnCertificateDetailResponse{}
|
||||
if _, err := c.apiClient.Excute(params, runtimeConfig, returnValue); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return returnValue, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) DescribeCdnDomainDetail(request *model.DescribeCdnDomainDetailRequest) (*model.DescribeCdnDomainDetailResponse, error) {
|
||||
return c.DescribeCdnDomainDetailWithConfig(request, nil)
|
||||
}
|
||||
|
||||
func (c *Client) DescribeCdnDomainDetailWithConfig(request *model.DescribeCdnDomainDetailRequest, runtimeConfig *config.RuntimeConfig) (*model.DescribeCdnDomainDetailResponse, error) {
|
||||
params := param.NewParamsBuilder().
|
||||
Action("describeCdnDomainDetail").
|
||||
Uri("/domainManager/openapi/domain/describeCdnDomainDetail/{domainId}").
|
||||
GatewayUri("/api/openapi-ecdn/domainManager/openapi/domain/describeCdnDomainDetail/{domainId}").
|
||||
Protocol("https").
|
||||
Method("GET").
|
||||
Request(request).
|
||||
Build()
|
||||
returnValue := &model.DescribeCdnDomainDetailResponse{}
|
||||
if _, err := c.apiClient.Excute(params, runtimeConfig, returnValue); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return returnValue, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) DescribeUserDomains(request *model.DescribeUserDomainsRequest) (*model.DescribeUserDomainsResponse, error) {
|
||||
return c.DescribeUserDomainsWithConfig(request, nil)
|
||||
}
|
||||
|
||||
func (c *Client) DescribeUserDomainsWithConfig(request *model.DescribeUserDomainsRequest, runtimeConfig *config.RuntimeConfig) (*model.DescribeUserDomainsResponse, error) {
|
||||
params := param.NewParamsBuilder().
|
||||
Action("describeUserDomains").
|
||||
Uri("/domainManager/openapi/domain/describeUserDomains").
|
||||
GatewayUri("/api/openapi-ecdn/domainManager/openapi/domain/describeUserDomains").
|
||||
Protocol("https").
|
||||
Method("GET").
|
||||
Request(request).
|
||||
Build()
|
||||
returnValue := &model.DescribeUserDomainsResponse{}
|
||||
if _, err := c.apiClient.Excute(params, runtimeConfig, returnValue); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return returnValue, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) AddDomainServerCertificate(request *model.AddDomainServerCertificateRequest) (*model.AddDomainServerCertificateResponse, error) {
|
||||
return c.AddDomainServerCertificateWithConfig(request, nil)
|
||||
}
|
||||
|
||||
func (c *Client) AddDomainServerCertificateWithConfig(request *model.AddDomainServerCertificateRequest, runtimeConfig *config.RuntimeConfig) (*model.AddDomainServerCertificateResponse, error) {
|
||||
params := param.NewParamsBuilder().
|
||||
Action("addDomainServerCertificate").
|
||||
Uri("/domainManager/openapi/certificate/addDomainServerCertificate").
|
||||
GatewayUri("/api/openapi-ecdn/domainManager/openapi/certificate/addDomainServerCertificate").
|
||||
Protocol("https").
|
||||
ContentType("application/json").
|
||||
Method("POST").
|
||||
Request(request).
|
||||
Build()
|
||||
returnValue := &model.AddDomainServerCertificateResponse{}
|
||||
if _, err := c.apiClient.Excute(params, runtimeConfig, returnValue); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return returnValue, nil
|
||||
}
|
||||
}
|
||||
@ -51,6 +51,7 @@ import BizDeployNodeConfigFieldsProviderBytePlusMediaLive from "./BizDeployNodeC
|
||||
import BizDeployNodeConfigFieldsProviderBytePlusTOS from "./BizDeployNodeConfigFieldsProviderBytePlusTOS";
|
||||
import BizDeployNodeConfigFieldsProviderCdnfly from "./BizDeployNodeConfigFieldsProviderCdnfly";
|
||||
import BizDeployNodeConfigFieldsProviderCloudflareSSL from "./BizDeployNodeConfigFieldsProviderCloudflareSSL";
|
||||
import BizDeployNodeConfigFieldsProviderCMCCCloudCDN from "./BizDeployNodeConfigFieldsProviderCMCCCloudCDN";
|
||||
import BizDeployNodeConfigFieldsProviderCPanel from "./BizDeployNodeConfigFieldsProviderCPanel";
|
||||
import BizDeployNodeConfigFieldsProviderCTCCCloudAO from "./BizDeployNodeConfigFieldsProviderCTCCCloudAO";
|
||||
import BizDeployNodeConfigFieldsProviderCTCCCloudCDN from "./BizDeployNodeConfigFieldsProviderCTCCCloudCDN";
|
||||
@ -195,6 +196,7 @@ const providerComponentMap: Partial<Record<DeploymentProviderType, React.Compone
|
||||
[DEPLOYMENT_PROVIDERS.BYTEPLUS_TOS]: BizDeployNodeConfigFieldsProviderBytePlusTOS,
|
||||
[DEPLOYMENT_PROVIDERS.CDNFLY]: BizDeployNodeConfigFieldsProviderCdnfly,
|
||||
[DEPLOYMENT_PROVIDERS.CLOUDFLARE_SSL]: BizDeployNodeConfigFieldsProviderCloudflareSSL,
|
||||
[DEPLOYMENT_PROVIDERS.CMCCCLOUD_CDN]: BizDeployNodeConfigFieldsProviderCMCCCloudCDN,
|
||||
[DEPLOYMENT_PROVIDERS.CPANEL]: BizDeployNodeConfigFieldsProviderCPanel,
|
||||
[DEPLOYMENT_PROVIDERS.CTCCCLOUD_AO]: BizDeployNodeConfigFieldsProviderCTCCCloudAO,
|
||||
[DEPLOYMENT_PROVIDERS.CTCCCLOUD_CDN]: BizDeployNodeConfigFieldsProviderCTCCCloudCDN,
|
||||
|
||||
@ -0,0 +1,120 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input, Radio } 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 DOMAIN_MATCH_PATTERN_EXACT = "exact" as const;
|
||||
const DOMAIN_MATCH_PATTERN_WILDCARD = "wildcard" as const;
|
||||
const DOMAIN_MATCH_PATTERN_CERTSAN = "certsan" as const;
|
||||
|
||||
const BizDeployNodeConfigFieldsProviderCMCCCloudCDN = () => {
|
||||
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 fieldDomainMatchPattern = Form.useWatch([parentNamePath, "domainMatchPattern"], { form: formInst, preserve: true });
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domainMatchPattern"]}
|
||||
initialValue={initialValues.domainMatchPattern}
|
||||
label={t("workflow_node.deploy.form.shared_domain_match_pattern.label")}
|
||||
extra={
|
||||
fieldDomainMatchPattern === DOMAIN_MATCH_PATTERN_EXACT ? (
|
||||
<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.shared_domain_match_pattern.option.exact.help.wildcard") }}></span>
|
||||
) : (
|
||||
void 0
|
||||
)
|
||||
}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Radio.Group
|
||||
options={[DOMAIN_MATCH_PATTERN_EXACT, DOMAIN_MATCH_PATTERN_WILDCARD, DOMAIN_MATCH_PATTERN_CERTSAN].map((s) => ({
|
||||
label: t(`workflow_node.deploy.form.shared_domain_match_pattern.option.${s}.label`),
|
||||
value: s,
|
||||
}))}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Show when={fieldDomainMatchPattern !== DOMAIN_MATCH_PATTERN_CERTSAN}>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domain"]}
|
||||
initialValue={initialValues.domain}
|
||||
label={t("workflow_node.deploy.form.cmcccloud_cdn_domain.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.cmcccloud_cdn_domain.placeholder")} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
domainMatchPattern: DOMAIN_MATCH_PATTERN_EXACT,
|
||||
domain: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n?: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z
|
||||
.object({
|
||||
domainMatchPattern: z.string().nonempty().default(DOMAIN_MATCH_PATTERN_EXACT),
|
||||
domain: z.string().nullish(),
|
||||
})
|
||||
.superRefine((values, ctx) => {
|
||||
if (values.domainMatchPattern) {
|
||||
switch (values.domainMatchPattern) {
|
||||
case DOMAIN_MATCH_PATTERN_EXACT:
|
||||
{
|
||||
const scDomain = z.string().refine((v) => isDomain(v), t("common.errmsg.domain_invalid"));
|
||||
const spDomain = scDomain.safeParse(values.domain);
|
||||
if (!spDomain.success) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: z.treeifyError(spDomain.error).errors.join(),
|
||||
path: ["domain"],
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DOMAIN_MATCH_PATTERN_WILDCARD:
|
||||
{
|
||||
const scDomain = z.string().refine((v) => isDomain(v, { allowWildcard: true }), t("common.errmsg.domain_invalid"));
|
||||
const spDomain = scDomain.safeParse(values.domain);
|
||||
if (!spDomain.success) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: z.treeifyError(spDomain.error).errors.join(),
|
||||
path: ["domain"],
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFieldsProviderCMCCCloudCDN, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
@ -181,6 +181,7 @@ export const accessProvidersMap: Map<AccessProvider["type"] | string, AccessProv
|
||||
[ACCESS_PROVIDERS.GOOGLECLOUD, "provider.googlecloud", "/imgs/providers/google.svg", [ACCESS_USAGES.DNS, ACCESS_USAGES.HOSTING]],
|
||||
[ACCESS_PROVIDERS.LINODE, "provider.linode", "/imgs/providers/linode.svg", [ACCESS_USAGES.DNS, ACCESS_USAGES.HOSTING]],
|
||||
[ACCESS_PROVIDERS.BAIDUCLOUD, "provider.baiducloud", "/imgs/providers/baiducloud.svg", [ACCESS_USAGES.DNS, ACCESS_USAGES.HOSTING]],
|
||||
[ACCESS_PROVIDERS.CMCCCLOUD, "provider.cmcccloud", "/imgs/providers/cmcccloud.svg", [ACCESS_USAGES.DNS, ACCESS_USAGES.HOSTING]],
|
||||
[ACCESS_PROVIDERS.CTCCCLOUD, "provider.ctcccloud", "/imgs/providers/ctcccloud.svg", [ACCESS_USAGES.DNS, ACCESS_USAGES.HOSTING]],
|
||||
[ACCESS_PROVIDERS.JDCLOUD, "provider.jdcloud", "/imgs/providers/jdcloud.svg", [ACCESS_USAGES.DNS, ACCESS_USAGES.HOSTING]],
|
||||
[ACCESS_PROVIDERS.QINGCLOUD, "provider.qingcloud", "/imgs/providers/qingcloud.svg", [ACCESS_USAGES.DNS, ACCESS_USAGES.HOSTING]],
|
||||
@ -252,7 +253,6 @@ export const accessProvidersMap: Map<AccessProvider["type"] | string, AccessProv
|
||||
[ACCESS_PROVIDERS.RUCENTER, "provider.rucenter", "/imgs/providers/rucenter.svg", [ACCESS_USAGES.DNS]],
|
||||
[ACCESS_PROVIDERS.SPACESHIP, "provider.spaceship", "/imgs/providers/spaceship.png", [ACCESS_USAGES.DNS]],
|
||||
[ACCESS_PROVIDERS.VULTR, "provider.vultr", "/imgs/providers/vultr.svg", [ACCESS_USAGES.DNS]],
|
||||
[ACCESS_PROVIDERS.CMCCCLOUD, "provider.cmcccloud", "/imgs/providers/cmcccloud.svg", [ACCESS_USAGES.DNS]],
|
||||
[ACCESS_PROVIDERS["35CN"], "provider.35cn", "/imgs/providers/35cn.png", [ACCESS_USAGES.DNS]],
|
||||
[ACCESS_PROVIDERS["51DNSCOM"], "provider.51dnscom", "/imgs/providers/51dnscom.png", [ACCESS_USAGES.DNS]],
|
||||
[ACCESS_PROVIDERS.DNSLA, "provider.dnsla", "/imgs/providers/dnsla.svg", [ACCESS_USAGES.DNS]],
|
||||
@ -643,6 +643,7 @@ export const DEPLOYMENT_PROVIDERS = Object.freeze({
|
||||
CACHEFLY: `${ACCESS_PROVIDERS.CACHEFLY}`,
|
||||
CDNFLY: `${ACCESS_PROVIDERS.CDNFLY}`,
|
||||
CLOUDFLARE_SSL: `${ACCESS_PROVIDERS.CLOUDFLARE}-ssl`,
|
||||
CMCCCLOUD_CDN: `${ACCESS_PROVIDERS.CMCCCLOUD}-cdn`,
|
||||
CPANEL: `${ACCESS_PROVIDERS.CPANEL}`,
|
||||
CTCCCLOUD_AO: `${ACCESS_PROVIDERS.CTCCCLOUD}-ao`,
|
||||
CTCCCLOUD_CDN: `${ACCESS_PROVIDERS.CTCCCLOUD}-cdn`,
|
||||
@ -861,6 +862,7 @@ export const deploymentProvidersMap: Map<DeploymentProvider["type"] | string, De
|
||||
[DEPLOYMENT_PROVIDERS.BAIDUCLOUD_BLB, "provider.baiducloud_blb", DEPLOYMENT_CATEGORIES.LOADBALANCE],
|
||||
[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.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],
|
||||
|
||||
@ -108,6 +108,7 @@
|
||||
"cloudflare_ssl": "Cloudflare - Edge Certificates",
|
||||
"cloudns": "ClouDNS",
|
||||
"cmcccloud": "China Mobile ECloud",
|
||||
"cmcccloud_cdn": "China Mobile ECloud - CDN (Content Delivery Network)",
|
||||
"cmcccloud_dns": "China Mobile ECloud - DNS",
|
||||
"conohavps": "ConoHa VPS",
|
||||
"constellix": "Constellix",
|
||||
|
||||
@ -1428,6 +1428,10 @@
|
||||
"help": "Notes: Leave it blank to import a new certificate; otherwise, to replace the existing one.",
|
||||
"tooltip": "For more information, see <a href=\"https://developers.cloudflare.com/ssl/edge-certificates/custom-certificates/uploading/\" target=\"_blank\">https://developers.cloudflare.com/ssl/edge-certificates/custom-certificates/uploading/</a>"
|
||||
},
|
||||
"cmcccloud_cdn_domain": {
|
||||
"label": "CMCC ECloud CDN domain",
|
||||
"placeholder": "Please enter CMCC ECloud CDN domain name"
|
||||
},
|
||||
"cpanel_deploy_target": {
|
||||
"option": {
|
||||
"website": {
|
||||
|
||||
@ -108,6 +108,7 @@
|
||||
"cloudflare_ssl": "Cloudflare - 边缘证书",
|
||||
"cloudns": "ClouDNS",
|
||||
"cmcccloud": "移动云",
|
||||
"cmcccloud_cdn": "移动云 - 内容分发网络 CDN",
|
||||
"cmcccloud_dns": "移动云 - 云解析 DNS",
|
||||
"conohavps": "ConoHa VPS",
|
||||
"constellix": "Constellix",
|
||||
|
||||
@ -1427,6 +1427,10 @@
|
||||
"help": "提示:不填写时,将上传新证书;否则,将替换原证书。",
|
||||
"tooltip": "这是什么?请参阅 <a href=\"https://developers.cloudflare.com/ssl/edge-certificates/custom-certificates/uploading/\" target=\"_blank\">https://developers.cloudflare.com/ssl/edge-certificates/custom-certificates/uploading/</a>"
|
||||
},
|
||||
"cmcccloud_cdn_domain": {
|
||||
"label": "移动云 CDN 加速域名",
|
||||
"placeholder": "请输入移动云 CDN 加速域名"
|
||||
},
|
||||
"cpanel_deploy_target": {
|
||||
"option": {
|
||||
"website": {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user