feat(provider): new deployment provider: tencentcloud tse

This commit is contained in:
Fu Diwei 2026-06-11 16:37:55 +08:00 committed by RHQYZ
parent 4c475a87ed
commit fe05eefa45
19 changed files with 822 additions and 3 deletions

1
go.mod
View File

@ -73,6 +73,7 @@ require (
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf v1.3.101
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.3.105
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.3.112
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tse v1.3.107
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod v1.3.112
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/waf v1.3.111
github.com/ucloud/ucloud-sdk-go v0.22.77

3
go.sum
View File

@ -903,6 +903,7 @@ github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.90/go.mod h
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.101/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.103/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.105/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.107/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.111/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.112 h1:PNCN4HXHVAfG87Msvelk7Ks5MhotAXk2vqPVvfy1Epw=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.112/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
@ -916,6 +917,8 @@ github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.3.105 h1:rzbhp0b
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.3.105/go.mod h1:KScd4O0ZJum7PsWPoJY1wbKnK1zRCAq7RH3PBRmiYJI=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.3.112 h1:VPiTJ5n49TS2nmCF1LDZ/T2jSRpsv1ZJnddTkzrvm1I=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.3.112/go.mod h1:FGEhdHxUk6wOSNpDvr+wdL34Lu6FunNDCQTyK4YqwUw=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tse v1.3.107 h1:doa/f0RtjMuoCpQo5P/Ni3EPOEmcn7MCkCRMnULWqHo=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tse v1.3.107/go.mod h1:uTigeKJi8/YABmv8LeucOcpK/ZAK5htJaCia8L3ol6E=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod v1.3.112 h1:vxOJOerDOVMvjFh+X3ZMrbb8/htfyxDSKjGkmtD+2jM=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod v1.3.112/go.mod h1:zCS+AwYqW2r0RBeCWHh9dmydCmP6LSew6y9Uyxsedy0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/waf v1.3.111 h1:CKRs1TWBVinSLGZ2J0OVtfzoqoWMizrJ6IdYo6QEfow=

View File

@ -0,0 +1,35 @@
package deployers
import (
"fmt"
"strings"
"github.com/samber/lo"
"github.com/certimate-go/certimate/internal/domain"
"github.com/certimate-go/certimate/pkg/core"
dplyimpl "github.com/certimate-go/certimate/pkg/core/deployer/providers/tencentcloud-tse"
xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
)
func init() {
Registries.MustRegister(domain.DeploymentProviderTypeTencentCloudTSE, func(options *ProviderFactoryOptions) (core.Deployer, error) {
credentials := domain.AccessConfigForTencentCloud{}
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{
SecretId: credentials.SecretId,
SecretKey: credentials.SecretKey,
ProjectId: credentials.ProjectId,
Endpoint: xmaps.GetString(options.ProviderExtendedConfig, "endpoint"),
Region: xmaps.GetString(options.ProviderExtendedConfig, "region"),
ServiceType: xmaps.GetString(options.ProviderExtendedConfig, "serviceType"),
GatewayId: xmaps.GetString(options.ProviderExtendedConfig, "gatewayId"),
Domains: lo.Filter(strings.Split(xmaps.GetString(options.ProviderExtendedConfig, "domains"), ";"), func(s string, _ int) bool { return s != "" }),
CertificateId: xmaps.GetString(options.ProviderExtendedConfig, "certificateId"),
})
return provider, err
})
}

View File

@ -419,6 +419,7 @@ const (
DeploymentProviderTypeTencentCloudSSL = DeploymentProviderType(AccessProviderTypeTencentCloud + "-ssl")
DeploymentProviderTypeTencentCloudSSLDeploy = DeploymentProviderType(AccessProviderTypeTencentCloud + "-ssldeploy")
DeploymentProviderTypeTencentCloudSSLUpdate = DeploymentProviderType(AccessProviderTypeTencentCloud + "-sslupdate")
DeploymentProviderTypeTencentCloudTSE = DeploymentProviderType(AccessProviderTypeTencentCloud + "-tse")
DeploymentProviderTypeTencentCloudVOD = DeploymentProviderType(AccessProviderTypeTencentCloud + "-vod")
DeploymentProviderTypeTencentCloudWAF = DeploymentProviderType(AccessProviderTypeTencentCloud + "-waf")
DeploymentProviderTypeUCloudUALB = DeploymentProviderType(AccessProviderTypeUCloud + "-ualb")

View File

@ -0,0 +1,6 @@
package tencentcloudtse
const (
// 服务类型:云原生网关。
SERVICE_TYPE_CLOUDNATIVE = "cloudnative"
)

View File

@ -0,0 +1,239 @@
package tencentcloudtse
import (
"context"
"fmt"
"log/slog"
"time"
"github.com/samber/lo"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
tcssl "github.com/certimate-go/certimate/pkg/sdk3rd-trimmed/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl/v20191205"
tctse "github.com/certimate-go/certimate/pkg/sdk3rd-trimmed/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tse/v20201207"
"github.com/certimate-go/certimate/pkg/core"
xcert "github.com/certimate-go/certimate/pkg/utils/cert"
)
type (
Provider = core.Certmgr
UploadResult = core.CertmgrUploadResult
ReplaceResult = core.CertmgrReplaceResult
)
type CertmgrConfig struct {
// 腾讯云 SecretId。
SecretId string `json:"secretId"`
// 腾讯云 SecretKey。
SecretKey string `json:"secretKey"`
// 腾讯云项目 ID。
ProjectId int64 `json:"projectId,omitempty"`
// 腾讯云接口端点。
Endpoint string `json:"endpoint,omitempty"`
// 腾讯云地域。
Region string `json:"region"`
// 服务类型。
ServiceType string `json:"serviceType"`
// 云原生网关 ID。
// 服务类型为 [SERVICE_TYPE_CLOUDNATIVE] 时必填。
GatewayId string `json:"gatewayId,omitempty"`
// 云原生网关绑定的域名。
// 服务类型为 [SERVICE_TYPE_CLOUDNATIVE] 时选填。
// 零值时根据证书内容自动识别。
Domains []string `json:"domains,omitempty"`
}
type Certmgr struct {
config *CertmgrConfig
logger *slog.Logger
sdkClient *wSDKClients
}
var _ Provider = (*Certmgr)(nil)
type wSDKClients struct {
SSL *tcssl.Client
TSE *tctse.Client
}
func NewCertmgr(config *CertmgrConfig) (*Certmgr, error) {
if config == nil {
return nil, fmt.Errorf("the configuration of the certmgr provider is nil")
}
client, err := createSDKClients(config.SecretId, config.SecretKey, config.Endpoint, config.Region)
if err != nil {
return nil, fmt.Errorf("could not create client: %w", err)
}
return &Certmgr{
config: config,
logger: slog.Default(),
sdkClient: client,
}, nil
}
func (c *Certmgr) SetLogger(logger *slog.Logger) {
if logger == nil {
c.logger = slog.New(slog.DiscardHandler)
} else {
c.logger = logger
}
}
func (c *Certmgr) Upload(ctx context.Context, certPEM, privkeyPEM string) (*UploadResult, error) {
switch c.config.ServiceType {
case SERVICE_TYPE_CLOUDNATIVE:
return c.uploadToCloudNative(ctx, certPEM, privkeyPEM)
default:
return nil, fmt.Errorf("unsupported service type '%s'", c.config.ServiceType)
}
}
func (c *Certmgr) Replace(ctx context.Context, certIdOrName string, certPEM, privkeyPEM string) (*ReplaceResult, error) {
switch c.config.ServiceType {
case SERVICE_TYPE_CLOUDNATIVE:
return c.replaceToCloudNative(ctx, certIdOrName, certPEM, privkeyPEM)
default:
return nil, fmt.Errorf("unsupported service type '%s'", c.config.ServiceType)
}
}
func (c *Certmgr) uploadToCloudNative(ctx context.Context, certPEM, privkeyPEM string) (*UploadResult, error) {
// 解析证书内容
certX509, err := xcert.ParseCertificateFromPEM(certPEM)
if err != nil {
return nil, err
}
// 先上传证书到 SSL
// REF: https://cloud.tencent.com/document/api/400/41665
uploadCertificateReq := tcssl.NewUploadCertificateRequest()
uploadCertificateReq.ProjectId = lo.EmptyableToPtr(uint64(c.config.ProjectId))
uploadCertificateReq.CertificatePublicKey = common.StringPtr(certPEM)
uploadCertificateReq.CertificatePrivateKey = common.StringPtr(privkeyPEM)
uploadCertificateReq.Repeatable = common.BoolPtr(false)
uploadCertificateResp, err := c.sdkClient.SSL.UploadCertificateWithContext(ctx, uploadCertificateReq)
c.logger.Debug("sdk request 'ssl.UploadCertificate'", slog.Any("request", uploadCertificateReq), slog.Any("response", uploadCertificateResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'ssl.UploadCertificate': %w", err)
}
// 查询云原生网关证书列表,避免重复上传
// REF: https://cloud.tencent.com/document/api/1364/98588
describeCloudNativeAPIGatewayCertificatesOffset := 0
describeCloudNativeAPIGatewayCertificatesLimit := 100
for {
select {
case <-ctx.Done():
return nil, ctx.Err()
default:
}
describeCloudNativeAPIGatewayCertificatesReq := tctse.NewDescribeCloudNativeAPIGatewayCertificatesRequest()
describeCloudNativeAPIGatewayCertificatesReq.GatewayId = common.StringPtr(c.config.GatewayId)
describeCloudNativeAPIGatewayCertificatesReq.Offset = common.Int64Ptr(int64(describeCloudNativeAPIGatewayCertificatesOffset))
describeCloudNativeAPIGatewayCertificatesReq.Limit = common.Int64Ptr(int64(describeCloudNativeAPIGatewayCertificatesLimit))
describeCloudNativeAPIGatewayCertificatesResp, err := c.sdkClient.TSE.DescribeCloudNativeAPIGatewayCertificatesWithContext(ctx, describeCloudNativeAPIGatewayCertificatesReq)
c.logger.Debug("sdk request 'tse.DescribeCloudNativeAPIGatewayCertificates'", slog.Any("request", describeCloudNativeAPIGatewayCertificatesReq), slog.Any("response", describeCloudNativeAPIGatewayCertificatesResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'tse.DescribeCloudNativeAPIGatewayCertificates': %w", err)
}
for _, certItem := range describeCloudNativeAPIGatewayCertificatesResp.Response.Result.CertificatesList {
if lo.FromPtr(uploadCertificateResp.Response.CertificateId) == lo.FromPtr(certItem.CertId) ||
xcert.EqualCertificatesFromPEM(certPEM, lo.FromPtr(certItem.Crt)) {
// 如果已存在相同证书,直接返回
c.logger.Info("ssl certificate already exists")
return &UploadResult{
CertId: lo.FromPtr(certItem.CertId),
CertName: lo.FromPtr(certItem.Name),
}, nil
}
}
if len(describeCloudNativeAPIGatewayCertificatesResp.Response.Result.CertificatesList) < describeCloudNativeAPIGatewayCertificatesLimit {
break
}
describeCloudNativeAPIGatewayCertificatesOffset += describeCloudNativeAPIGatewayCertificatesLimit
}
// 生成新证书名(需符合腾讯云命名规则)
certName := fmt.Sprintf("certimate_%d", time.Now().UnixMilli())
// 创建云原生网关证书
// REF: https://cloud.tencent.com/document/api/1364/98591
createCloudNativeAPIGatewayCertificateReq := tctse.NewCreateCloudNativeAPIGatewayCertificateRequest()
createCloudNativeAPIGatewayCertificateReq.GatewayId = common.StringPtr(c.config.GatewayId)
createCloudNativeAPIGatewayCertificateReq.Name = common.StringPtr(certName)
createCloudNativeAPIGatewayCertificateReq.CertId = uploadCertificateResp.Response.CertificateId
createCloudNativeAPIGatewayCertificateReq.BindDomains = common.StringPtrs(lo.Ternary(len(c.config.Domains) != 0, c.config.Domains, certX509.DNSNames))
createCloudNativeAPIGatewayCertificateResp, err := c.sdkClient.TSE.CreateCloudNativeAPIGatewayCertificateWithContext(ctx, createCloudNativeAPIGatewayCertificateReq)
c.logger.Debug("sdk request 'tse.CreateCloudNativeAPIGatewayCertificate'", slog.Any("request", createCloudNativeAPIGatewayCertificateReq), slog.Any("response", createCloudNativeAPIGatewayCertificateResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'tse.CreateCloudNativeAPIGatewayCertificate': %w", err)
}
return &UploadResult{
CertId: lo.FromPtr(createCloudNativeAPIGatewayCertificateResp.Response.Result.Id),
CertName: certName,
}, nil
}
func (c *Certmgr) replaceToCloudNative(ctx context.Context, certIdOrName string, certPEM, privkeyPEM string) (*ReplaceResult, error) {
// 更新云原生网关证书
// REF: https://cloud.tencent.com/document/api/1364/100199
modifyCloudNativeAPIGatewayCertificateReq := tctse.NewModifyCloudNativeAPIGatewayCertificateRequest()
modifyCloudNativeAPIGatewayCertificateReq.GatewayId = common.StringPtr(c.config.GatewayId)
modifyCloudNativeAPIGatewayCertificateReq.Id = common.StringPtr(certIdOrName)
modifyCloudNativeAPIGatewayCertificateReq.Crt = common.StringPtr(certPEM)
modifyCloudNativeAPIGatewayCertificateReq.Key = common.StringPtr(privkeyPEM)
modifyCloudNativeAPIGatewayCertificateReq.CertSource = common.StringPtr("native")
modifyCloudNativeAPIGatewayCertificateResp, err := c.sdkClient.TSE.ModifyCloudNativeAPIGatewayCertificateWithContext(ctx, modifyCloudNativeAPIGatewayCertificateReq)
c.logger.Debug("sdk request 'tse.ModifyCloudNativeAPIGatewayCertificate'", slog.Any("request", modifyCloudNativeAPIGatewayCertificateReq), slog.Any("response", modifyCloudNativeAPIGatewayCertificateResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'tse.ModifyCloudNativeAPIGatewayCertificate': %w", err)
}
return &ReplaceResult{}, nil
}
func createSDKClients(secretId, secretKey, endpoint, region string) (*wSDKClients, error) {
wsdk := &wSDKClients{}
{
credential := common.NewCredential(secretId, secretKey)
cpf := profile.NewClientProfile()
client, err := tcssl.NewClient(credential, "", cpf)
if err != nil {
return nil, err
}
wsdk.SSL = client
}
{
credential := common.NewCredential(secretId, secretKey)
cpf := profile.NewClientProfile()
if endpoint != "" {
cpf.HttpProfile.Endpoint = endpoint
}
client, err := tctse.NewClient(credential, region, cpf)
if err != nil {
return nil, err
}
wsdk.TSE = client
}
return wsdk, nil
}

View File

@ -0,0 +1,61 @@
package tencentcloudtse_test
import (
"testing"
"github.com/certimate-go/certimate/pkg/core/certmgr/internal/tester"
impl "github.com/certimate-go/certimate/pkg/core/certmgr/providers/tencentcloud-tse"
)
var (
fp = tester.Args("TENCENTCLOUDTSE_")
fTestCertPath string
fTestKeyPath string
fSecretId string
fSecretKey string
fRegion string
fServiceType string
fGatewayId string
)
func init() {
fp.DefineString(&fTestCertPath, "TESTCERTPATH")
fp.DefineString(&fTestKeyPath, "TESTKEYPATH")
fp.DefineString(&fSecretId, "SECRETID")
fp.DefineString(&fSecretKey, "SECRETKEY")
fp.DefineString(&fRegion, "REGION")
fp.DefineString(&fServiceType, "SERVICETYPE")
fp.DefineString(&fGatewayId, "GATEWAYID")
}
/*
Shell command to run this test:
go test -v ./tencentcloud_tse_test.go -args \
--TENCENTCLOUDTSE_TESTCERTPATH="/path/to/your-test-cert.pem" \
--TENCENTCLOUDTSE_TESTKEYPATH="/path/to/your-test-key.pem" \
--TENCENTCLOUDTSE_SECRETID="your-secret-id" \
--TENCENTCLOUDTSE_SECRETKEY="your-secret-key" \
--TENCENTCLOUDTSE_REGION="ap-guangzhou" \
--TENCENTCLOUDTSE_SERVICETYPE="cloudnative" \
--TENCENTCLOUDTSE_GATEWAYID="your-gateway-id"
*/
func TestProvider(t *testing.T) {
fp.Parse()
t.Run("Upload", func(t *testing.T) {
provider, err := impl.NewCertmgr(&impl.CertmgrConfig{
SecretId: fSecretId,
SecretKey: fSecretKey,
Region: fRegion,
ServiceType: fServiceType,
GatewayId: fGatewayId,
})
if err != nil {
t.Errorf("err: %+v", err)
return
}
tester.TestUpload(t, provider, tester.TestUploadArgs{CertPath: fTestCertPath, KeyPath: fTestKeyPath})
})
}

View File

@ -0,0 +1,10 @@
package tencentcloudtse
import (
tse "github.com/certimate-go/certimate/pkg/core/certmgr/providers/tencentcloud-tse"
)
const (
// 服务类型:云原生网关。
SERVICE_TYPE_CLOUDNATIVE = tse.SERVICE_TYPE_CLOUDNATIVE
)

View File

@ -0,0 +1,107 @@
package tencentcloudtse
import (
"context"
"fmt"
"log/slog"
"github.com/certimate-go/certimate/pkg/core"
cmgrimpl "github.com/certimate-go/certimate/pkg/core/certmgr/providers/tencentcloud-tse"
)
type (
Provider = core.Deployer
DeployResult = core.DeployerDeployResult
)
type DeployerConfig struct {
// 腾讯云 SecretId。
SecretId string `json:"secretId"`
// 腾讯云 SecretKey。
SecretKey string `json:"secretKey"`
// 腾讯云项目 ID。
ProjectId int64 `json:"projectId,omitempty"`
// 腾讯云接口端点。
Endpoint string `json:"endpoint,omitempty"`
// 腾讯云地域。
Region string `json:"region"`
// 服务类型。
ServiceType string `json:"serviceType"`
// 云原生网关 ID。
// 服务类型为 [SERVICE_TYPE_CLOUDNATIVE] 时必填。
GatewayId string `json:"gatewayId,omitempty"`
// 云原生网关绑定的域名。
// 服务类型为 [SERVICE_TYPE_CLOUDNATIVE] 时选填。
// 零值时根据证书内容自动识别。
Domains []string `json:"domains,omitempty"`
// 云原生网关证书 ID。
// 服务类型为 [SERVICE_TYPE_CLOUDNATIVE] 时选填。
// 零值时表示新建证书;否则表示更新证书。
CertificateId string `json:"certificateId,omitempty"`
}
type Deployer struct {
config *DeployerConfig
logger *slog.Logger
sdkCertmgr core.Certmgr
}
var _ Provider = (*Deployer)(nil)
func NewDeployer(config *DeployerConfig) (*Deployer, error) {
if config == nil {
return nil, fmt.Errorf("the configuration of the deployer provider is nil")
}
pcertmgr, err := cmgrimpl.NewCertmgr(&cmgrimpl.CertmgrConfig{
SecretId: config.SecretId,
SecretKey: config.SecretKey,
ProjectId: config.ProjectId,
Endpoint: config.Endpoint,
Region: config.Region,
ServiceType: config.ServiceType,
GatewayId: config.GatewayId,
Domains: config.Domains,
})
if err != nil {
return nil, fmt.Errorf("could not create certmgr: %w", err)
}
return &Deployer{
config: config,
logger: slog.Default(),
sdkCertmgr: pcertmgr,
}, nil
}
func (d *Deployer) SetLogger(logger *slog.Logger) {
if logger == nil {
d.logger = slog.New(slog.DiscardHandler)
} else {
d.logger = logger
}
d.sdkCertmgr.SetLogger(logger)
}
func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*DeployResult, error) {
if d.config.CertificateId == "" {
// 上传证书
upres, err := d.sdkCertmgr.Upload(ctx, certPEM, privkeyPEM)
if err != nil {
return nil, fmt.Errorf("failed to upload certificate file: %w", err)
} else {
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
}
} else {
// 替换证书
rplres, err := d.sdkCertmgr.Replace(ctx, d.config.CertificateId, certPEM, privkeyPEM)
if err != nil {
return nil, fmt.Errorf("failed to replace certificate file: %w", err)
} else {
d.logger.Info("ssl certificate replaced", slog.Any("result", rplres))
}
}
return &DeployResult{}, nil
}

View File

@ -0,0 +1,99 @@
package v20201207
import (
"context"
"errors"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
tse "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tse/v20201207"
)
const APIVersion = tse.APIVersion
type Client struct {
common.Client
}
func NewClient(credential common.CredentialIface, region string, clientProfile *profile.ClientProfile) (client *Client, err error) {
client = &Client{}
client.Init(region).
WithCredential(credential).
WithProfile(clientProfile)
return
}
func NewCreateCloudNativeAPIGatewayCertificateRequest() (request *CreateCloudNativeAPIGatewayCertificateRequest) {
return tse.NewCreateCloudNativeAPIGatewayCertificateRequest()
}
func NewCreateCloudNativeAPIGatewayCertificateResponse() (response *CreateCloudNativeAPIGatewayCertificateResponse) {
return tse.NewCreateCloudNativeAPIGatewayCertificateResponse()
}
func (c *Client) CreateCloudNativeAPIGatewayCertificateWithContext(ctx context.Context, request *CreateCloudNativeAPIGatewayCertificateRequest) (response *CreateCloudNativeAPIGatewayCertificateResponse, err error) {
if request == nil {
request = NewCreateCloudNativeAPIGatewayCertificateRequest()
}
c.InitBaseRequest(&request.BaseRequest, "tse", APIVersion, "CreateCloudNativeAPIGatewayCertificate")
if c.GetCredential() == nil {
return nil, errors.New("CreateCloudNativeAPIGatewayCertificate require credential")
}
request.SetContext(ctx)
response = NewCreateCloudNativeAPIGatewayCertificateResponse()
err = c.Send(request, response)
return
}
func NewDescribeCloudNativeAPIGatewayCertificatesRequest() (request *DescribeCloudNativeAPIGatewayCertificatesRequest) {
return tse.NewDescribeCloudNativeAPIGatewayCertificatesRequest()
}
func NewDescribeCloudNativeAPIGatewayCertificatesResponse() (response *DescribeCloudNativeAPIGatewayCertificatesResponse) {
return tse.NewDescribeCloudNativeAPIGatewayCertificatesResponse()
}
func (c *Client) DescribeCloudNativeAPIGatewayCertificatesWithContext(ctx context.Context, request *DescribeCloudNativeAPIGatewayCertificatesRequest) (response *DescribeCloudNativeAPIGatewayCertificatesResponse, err error) {
if request == nil {
request = NewDescribeCloudNativeAPIGatewayCertificatesRequest()
}
c.InitBaseRequest(&request.BaseRequest, "tse", APIVersion, "DescribeCloudNativeAPIGatewayCertificates")
if c.GetCredential() == nil {
return nil, errors.New("DescribeCloudNativeAPIGatewayCertificates require credential")
}
request.SetContext(ctx)
response = NewDescribeCloudNativeAPIGatewayCertificatesResponse()
err = c.Send(request, response)
return
}
func NewModifyCloudNativeAPIGatewayCertificateRequest() (request *ModifyCloudNativeAPIGatewayCertificateRequest) {
return tse.NewModifyCloudNativeAPIGatewayCertificateRequest()
}
func NewModifyCloudNativeAPIGatewayCertificateResponse() (response *ModifyCloudNativeAPIGatewayCertificateResponse) {
return tse.NewModifyCloudNativeAPIGatewayCertificateResponse()
}
func (c *Client) ModifyCloudNativeAPIGatewayCertificateWithContext(ctx context.Context, request *ModifyCloudNativeAPIGatewayCertificateRequest) (response *ModifyCloudNativeAPIGatewayCertificateResponse, err error) {
if request == nil {
request = NewModifyCloudNativeAPIGatewayCertificateRequest()
}
c.InitBaseRequest(&request.BaseRequest, "tse", APIVersion, "ModifyCloudNativeAPIGatewayCertificate")
if c.GetCredential() == nil {
return nil, errors.New("ModifyCloudNativeAPIGatewayCertificate require credential")
}
request.SetContext(ctx)
response = NewModifyCloudNativeAPIGatewayCertificateResponse()
err = c.Send(request, response)
return
}

View File

@ -0,0 +1,17 @@
package v20201207
import (
tse "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tse/v20201207"
)
type CreateCloudNativeAPIGatewayCertificateRequest = tse.CreateCloudNativeAPIGatewayCertificateRequest
type CreateCloudNativeAPIGatewayCertificateResponse = tse.CreateCloudNativeAPIGatewayCertificateResponse
type DescribeCloudNativeAPIGatewayCertificatesRequest = tse.DescribeCloudNativeAPIGatewayCertificatesRequest
type DescribeCloudNativeAPIGatewayCertificatesResponse = tse.DescribeCloudNativeAPIGatewayCertificatesResponse
type ModifyCloudNativeAPIGatewayCertificateRequest = tse.ModifyCloudNativeAPIGatewayCertificateRequest
type ModifyCloudNativeAPIGatewayCertificateResponse = tse.ModifyCloudNativeAPIGatewayCertificateResponse

View File

@ -108,6 +108,7 @@ import BizDeployNodeConfigFieldsProviderTencentCloudSCF from "./BizDeployNodeCon
import BizDeployNodeConfigFieldsProviderTencentCloudSSL from "./BizDeployNodeConfigFieldsProviderTencentCloudSSL";
import BizDeployNodeConfigFieldsProviderTencentCloudSSLDeploy from "./BizDeployNodeConfigFieldsProviderTencentCloudSSLDeploy";
import BizDeployNodeConfigFieldsProviderTencentCloudSSLUpdate from "./BizDeployNodeConfigFieldsProviderTencentCloudSSLUpdate";
import BizDeployNodeConfigFieldsProviderTencentCloudTSE from "./BizDeployNodeConfigFieldsProviderTencentCloudTSE";
import BizDeployNodeConfigFieldsProviderTencentCloudVOD from "./BizDeployNodeConfigFieldsProviderTencentCloudVOD";
import BizDeployNodeConfigFieldsProviderTencentCloudWAF from "./BizDeployNodeConfigFieldsProviderTencentCloudWAF";
import BizDeployNodeConfigFieldsProviderUCloudUALB from "./BizDeployNodeConfigFieldsProviderUCloudUALB";
@ -248,6 +249,7 @@ const providerComponentMap: Partial<Record<DeploymentProviderType, React.Compone
[DEPLOYMENT_PROVIDERS.TENCENTCLOUD_SSL]: BizDeployNodeConfigFieldsProviderTencentCloudSSL,
[DEPLOYMENT_PROVIDERS.TENCENTCLOUD_SSL_DEPLOY]: BizDeployNodeConfigFieldsProviderTencentCloudSSLDeploy,
[DEPLOYMENT_PROVIDERS.TENCENTCLOUD_SSL_UPDATE]: BizDeployNodeConfigFieldsProviderTencentCloudSSLUpdate,
[DEPLOYMENT_PROVIDERS.TENCENTCLOUD_TSE]: BizDeployNodeConfigFieldsProviderTencentCloudTSE,
[DEPLOYMENT_PROVIDERS.TENCENTCLOUD_VOD]: BizDeployNodeConfigFieldsProviderTencentCloudVOD,
[DEPLOYMENT_PROVIDERS.TENCENTCLOUD_WAF]: BizDeployNodeConfigFieldsProviderTencentCloudWAF,
[DEPLOYMENT_PROVIDERS.UCLOUD_UALB]: BizDeployNodeConfigFieldsProviderUCloudUALB,

View File

@ -48,7 +48,7 @@ const BizDeployNodeConfigFieldsProviderAliyunAPIGW = () => {
rules={[formRule]}
>
<Select
options={[SERVICE_TYPE_CLOUDNATIVE, SERVICE_TYPE_CLOUDNATIVE].map((s) => ({
options={[SERVICE_TYPE_CLOUDNATIVE, SERVICE_TYPE_TRADITIONAL].map((s) => ({
value: s,
label: t(`workflow_node.deploy.form.aliyun_apigw_service_type.option.${s}.label`),
}))}

View File

@ -0,0 +1,156 @@
import { getI18n, useTranslation } from "react-i18next";
import { Form, Input, Select } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod";
import MultipleSplitValueInput from "@/components/MultipleSplitValueInput";
import Show from "@/components/Show";
import { isDomain } from "@/utils/validator";
import { useFormNestedFieldsContext } from "./_context";
const MULTIPLE_INPUT_SEPARATOR = ";";
const SERVICE_TYPE_CLOUDNATIVE = "cloudnative" as const;
const BizDeployNodeConfigFieldsProviderTencentCloudTSE = () => {
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 fieldServiceType = Form.useWatch([parentNamePath, "serviceType"], formInst);
return (
<>
<Form.Item
name={[parentNamePath, "endpoint"]}
initialValue={initialValues.endpoint}
label={t("workflow_node.deploy.form.tencentcloud_tse_endpoint.label")}
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.tencentcloud_tse_endpoint.tooltip") }}></span>}
>
<Input allowClear placeholder={t("workflow_node.deploy.form.tencentcloud_tse_endpoint.placeholder")} />
</Form.Item>
<Form.Item
name={[parentNamePath, "serviceType"]}
initialValue={initialValues.serviceType}
label={t("workflow_node.deploy.form.tencentcloud_tse_service_type.label")}
rules={[formRule]}
>
<Select
options={[SERVICE_TYPE_CLOUDNATIVE].map((s) => ({
value: s,
label: t(`workflow_node.deploy.form.tencentcloud_tse_service_type.option.${s}.label`),
}))}
placeholder={t("workflow_node.deploy.form.tencentcloud_tse_service_type.placeholder")}
/>
</Form.Item>
<Show when={fieldServiceType === SERVICE_TYPE_CLOUDNATIVE}>
<Form.Item
name={[parentNamePath, "gatewayId"]}
initialValue={initialValues.gatewayId}
label={t("workflow_node.deploy.form.tencentcloud_tse_gateway_id.label")}
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.tencentcloud_tse_gateway_id.tooltip") }}></span>}
>
<Input placeholder={t("workflow_node.deploy.form.tencentcloud_tse_gateway_id.placeholder")} />
</Form.Item>
<Form.Item
name={[parentNamePath, "domains"]}
initialValue={initialValues.domains}
label={t("workflow_node.deploy.form.tencentcloud_tse_domains.label")}
extra={t("workflow_node.deploy.form.tencentcloud_tse_domains.help")}
rules={[formRule]}
>
<MultipleSplitValueInput
modalTitle={t("workflow_node.deploy.form.tencentcloud_tse_domains.multiple_input_modal.title")}
placeholder={t("workflow_node.deploy.form.tencentcloud_tse_domains.placeholder")}
placeholderInModal={t("workflow_node.deploy.form.tencentcloud_tse_domains.multiple_input_modal.placeholder")}
splitOptions={{ removeEmpty: true, trimSpace: true }}
/>
</Form.Item>
<Form.Item
name={[parentNamePath, "certificateId"]}
initialValue={initialValues.certificateId}
label={t("workflow_node.deploy.form.tencentcloud_tse_certificate_id.label")}
extra={t("workflow_node.deploy.form.tencentcloud_tse_certificate_id.help")}
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.tencentcloud_tse_certificate_id.tooltip") }}></span>}
>
<Input placeholder={t("workflow_node.deploy.form.tencentcloud_tse_certificate_id.placeholder")} />
</Form.Item>
</Show>
</>
);
};
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
return {
region: "",
serviceType: SERVICE_TYPE_CLOUDNATIVE,
gatewayId: "",
};
};
const getSchema = ({ i18n = getI18n() }: { i18n?: ReturnType<typeof getI18n> }) => {
const { t } = i18n;
return z
.object({
serviceType: z.enum([SERVICE_TYPE_CLOUDNATIVE]),
endpoint: z.string().nullish(),
region: z.string().nonempty(),
gatewayId: z.string().nullish(),
domains: z.string().nullish(),
certificateId: z.string().nullish(),
})
.superRefine((values, ctx) => {
if (values.serviceType) {
switch (values.serviceType) {
case SERVICE_TYPE_CLOUDNATIVE:
{
const scGatewayId = z.string().nonempty();
const spGatewayId = scGatewayId.safeParse(values.gatewayId);
if (!spGatewayId.success) {
ctx.addIssue({
code: "custom",
message: z.treeifyError(spGatewayId.error).errors.join(),
path: ["gatewayId"],
});
}
const scDomains = z
.string()
.nonempty()
.refine((v) => v.split(MULTIPLE_INPUT_SEPARATOR).every((e) => isDomain(e, { allowWildcard: true })), t("common.errmsg.domain_invalid"));
const spDomains = scDomains.safeParse(values.domains);
if (!spDomains.success) {
ctx.addIssue({
code: "custom",
message: z.treeifyError(spDomains.error).errors.join(),
path: ["domains"],
});
}
}
break;
}
}
});
};
const _default = Object.assign(BizDeployNodeConfigFieldsProviderTencentCloudTSE, {
getInitialValues,
getSchema,
});
export default _default;

View File

@ -704,6 +704,7 @@ export const DEPLOYMENT_PROVIDERS = Object.freeze({
TENCENTCLOUD_SSL: `${ACCESS_PROVIDERS.TENCENTCLOUD}-ssl`,
TENCENTCLOUD_SSL_DEPLOY: `${ACCESS_PROVIDERS.TENCENTCLOUD}-ssldeploy`,
TENCENTCLOUD_SSL_UPDATE: `${ACCESS_PROVIDERS.TENCENTCLOUD}-sslupdate`,
TENCENTCLOUD_TSE: `${ACCESS_PROVIDERS.TENCENTCLOUD}-tse`,
TENCENTCLOUD_VOD: `${ACCESS_PROVIDERS.TENCENTCLOUD}-vod`,
TENCENTCLOUD_WAF: `${ACCESS_PROVIDERS.TENCENTCLOUD}-waf`,
UCLOUD_UALB: `${ACCESS_PROVIDERS.UCLOUD}-ualb`,
@ -797,6 +798,7 @@ export const deploymentProvidersMap: Map<DeploymentProvider["type"] | string, De
[DEPLOYMENT_PROVIDERS.TENCENTCLOUD_CSS, "provider.tencentcloud_css", DEPLOYMENT_CATEGORIES.AV],
[DEPLOYMENT_PROVIDERS.TENCENTCLOUD_VOD, "provider.tencentcloud_vod", DEPLOYMENT_CATEGORIES.AV],
[DEPLOYMENT_PROVIDERS.TENCENTCLOUD_SCF, "provider.tencentcloud_scf", DEPLOYMENT_CATEGORIES.SERVERLESS],
[DEPLOYMENT_PROVIDERS.TENCENTCLOUD_TSE, "provider.tencentcloud_tse", DEPLOYMENT_CATEGORIES.APIGATEWAY],
[DEPLOYMENT_PROVIDERS.TENCENTCLOUD_GAAP, "provider.tencentcloud_gaap", DEPLOYMENT_CATEGORIES.ACCELERATOR],
[DEPLOYMENT_PROVIDERS.TENCENTCLOUD_SSL, "provider.tencentcloud_ssl_upload", DEPLOYMENT_CATEGORIES.SSL],
[DEPLOYMENT_PROVIDERS.TENCENTCLOUD_SSL_DEPLOY, "provider.tencentcloud_ssl_deploy", DEPLOYMENT_CATEGORIES.SSL],

View File

@ -243,6 +243,7 @@
"tencentcloud_ssl_deploy": "Tencent Cloud - Deploy via SSL Certificate Service",
"tencentcloud_ssl_update": "Tencent Cloud - Update via SSL Certificate Service",
"tencentcloud_ssl_upload": "Tencent Cloud - Upload to SSL Certificate Service",
"tencentcloud_tse": "Tencent Cloud - TSE (Cloud Service Engine)",
"tencentcloud_vod": "Tencent Cloud - VOD (Video on Demand)",
"tencentcloud_waf": "Tencent Cloud - WAF (Web Application Firewall)",
"ucloud": "UCloud",

View File

@ -2328,6 +2328,45 @@
"label": "Renewal certificate (certificate ID unchanged)",
"tooltip": "When unchecked, it will invoke <em>UpdateCertificateInstance</em>; otherwise, it will invoke <em>UploadUpdateCertificateInstance</em>."
},
"tencentcloud_tse_endpoint": {
"label": "Tencent Cloud API endpoint (Optional)",
"placeholder": "Please enter Tencent Cloud TSE API endpoint (e.g. tse.intl.tencentcloudapi.com)",
"tooltip": "<ul style=\"list-style: disc;\"><li><strong>tse.intl.tencentcloudapi.com</strong> for Tencent Cloud International</li><li><strong>tse.tencentcloudapi.com</strong> for Tencent Cloud in China</li></ul>"
},
"tencentcloud_tse_region": {
"label": "Tencent Cloud region",
"placeholder": "Please enter Tencent Cloud TSE region (e.g. ap-guangzhou)",
"tooltip": "For more information, see <a href=\"https://www.tencentcloud.com/document/product/1290/79214\" target=\"_blank\">https://www.tencentcloud.com/document/product/1290/79214</a>"
},
"tencentcloud_tse_service_type": {
"label": "Tencent Cloud TSE service type",
"placeholder": "Please select Tencent Cloud TSE service type",
"option": {
"cloudnative": {
"label": "Cloud-native API gateway"
}
}
},
"tencentcloud_tse_gateway_id": {
"label": "Tencent Cloud TSE Cloud-native API gateway ID",
"placeholder": "Please enter Tencent Cloud TSE Cloud-native API gateway ID",
"tooltip": "For more information, see <a href=\"https://console.tencentcloud.com/rcc/governance\" target=\"_blank\">https://console.tencentcloud.com/rcc/governance</a>"
},
"tencentcloud_tse_domains": {
"label": "Tencent Cloud TSE Cloud-native API gateway binding domains",
"placeholder": "Please enter Tencent Cloud TSE Cloud-native API gateway binding domain names (separated by semicolons)",
"help": "Notes: Multiple domains should be separated by semicolons.",
"multiple_input_modal": {
"title": "Change Tencent Cloud TSE Cloud-native API gateway binding domains",
"placeholder": "Please enter Tencent Cloud TSE Cloud-native API gateway binding domain name"
}
},
"tencentcloud_tse_certificate_id": {
"label": "Tencent Cloud TSE Cloud-native certificate ID",
"placeholder": "Please enter Tencent Cloud TSE Cloud-native certificate ID",
"help": "Notes: Leave it blank to import a new certificate; otherwise, to replace the existing one.",
"tooltip": "For more information, see <a href=\"https://console.tencentcloud.com/rcc/governance\" target=\"_blank\">https://console.tencentcloud.com/rcc/governance</a>"
},
"tencentcloud_vod_endpoint": {
"label": "Tencent Cloud API endpoint (Optional)",
"placeholder": "Please enter Tencent Cloud VOD API endpoint (e.g. vod.intl.tencentcloudapi.com)",
@ -2650,7 +2689,7 @@
"help": "Notes: Multiple domains should be separated by semicolons.",
"multiple_input_modal": {
"title": "Change Wangsu Cloud CDN domains",
"placeholder": "Please enter Wangsu Cloud CDN domain"
"placeholder": "Please enter Wangsu Cloud CDN domain name"
}
},
"wangsu_cdnpro_environment": {

View File

@ -243,6 +243,7 @@
"tencentcloud_ssl_deploy": "腾讯云 - 通过 SSL 证书服务创建部署任务",
"tencentcloud_ssl_update": "腾讯云 - 通过 SSL 证书服务更新云资源证书",
"tencentcloud_ssl_upload": "腾讯云 - 上传到 SSL 证书服务",
"tencentcloud_tse": "腾讯云 - 微服务引擎 TSE",
"tencentcloud_vod": "腾讯云 - 云点播 VOD",
"tencentcloud_waf": "腾讯云 - Web 应用防火墙 WAF",
"todaynic": "时代互联",

View File

@ -952,7 +952,7 @@
"aws_acm_certificate_arn": {
"label": "AWS ACM 证书 ARN可选",
"placeholder": "请输入 AWS ACM 证书 ARN",
"help": "提示:不填写时,将导入为新证书;否则,将替换原证书。"
"help": "提示:不填写时,将上传新证书;否则,将替换原证书。"
},
"aws_alb_region": {
"label": "AWS 服务区域",
@ -2324,6 +2324,45 @@
"label": "是否更新原证书(即证书 ID 保持不变)",
"tooltip": "不勾选时,将调用腾讯云 OpenAPI <em>UpdateCertificateInstance</em> 接口;否则,将调用腾讯云 OpenAPI <em>UploadUpdateCertificateInstance</em> 接口。"
},
"tencentcloud_tse_endpoint": {
"label": "腾讯云接口端点(可选)",
"placeholder": "请输入腾讯云 TSE 接口端点例如tse.tencentcloudapi.com",
"tooltip": "这是什么?请参阅 <a href=\"https://cloud.tencent.com.cn/document/product/1364/54618\" target=\"_blank\">https://cloud.tencent.com.cn/document/product/1364/54618</a><br>国际站用户请填写 <em>tse.intl.tencentcloudapi.com</em>。"
},
"tencentcloud_tse_region": {
"label": "腾讯云服务地域",
"placeholder": "输入腾讯云 TSE 服务地域例如ap-guangzhou",
"tooltip": "这是什么?请参阅 <a href=\"https://cloud.tencent.com.cn/document/product/1364/54618\" target=\"_blank\">https://cloud.tencent.com.cn/document/product/1364/54618</a>"
},
"tencentcloud_tse_service_type": {
"label": "腾讯云 TSE 服务类型",
"placeholder": "请选择腾讯云 TSE 服务类型",
"option": {
"cloudnative": {
"label": "云原生网关"
}
}
},
"tencentcloud_tse_gateway_id": {
"label": "腾讯云 TSE 云原生网关 ID",
"placeholder": "请输入腾讯云 TSE 云原生网关 ID",
"tooltip": "这是什么?请参阅 <a href=\"https://console.cloud.tencent.com.cn/rcc/governance\" target=\"_blank\">https://console.cloud.tencent.com.cn/rcc/governance</a>"
},
"tencentcloud_tse_domains": {
"label": "腾讯云 TSE 云原生网关绑定域名",
"placeholder": "输入腾讯云 TSE 云原生网关绑定域名(多个值请用半角分号隔开)",
"help": "提示:支持多个域名,以半角分号隔开。",
"multiple_input_modal": {
"title": "修改腾讯云 TSE 云原生网关绑定域名",
"placeholder": "请输入腾讯云 TSE 云原生网关绑定域名"
}
},
"tencentcloud_tse_certificate_id": {
"label": "腾讯云 TSE 云原生证书 ID可选",
"placeholder": "请输入腾讯云 TSE 云原生证书 ID",
"help": "提示:不填写时,将上传新证书;否则,将替换原证书。",
"tooltip": "这是什么?请参阅 <a href=\"https://console.cloud.tencent.com.cn/rcc/governance\" target=\"_blank\">https://console.cloud.tencent.com.cn/rcc/governance</a>"
},
"tencentcloud_vod_endpoint": {
"label": "腾讯云接口端点(可选)",
"placeholder": "请输入腾讯云云点播接口端点例如vod.tencentcloudapi.com",