Merge branch 'main' into feat-ssh-jumpserver
This commit is contained in:
@@ -9,12 +9,15 @@ import (
|
||||
"net/url"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||
opsdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/1panel"
|
||||
onepanelsdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/1panel"
|
||||
)
|
||||
|
||||
type DeployerConfig struct {
|
||||
// 1Panel 地址。
|
||||
ApiUrl string `json:"apiUrl"`
|
||||
// 1Panel 版本。
|
||||
// 可取值 "v1"、"v2"。
|
||||
ApiVersion string `json:"apiVersion"`
|
||||
// 1Panel 接口密钥。
|
||||
ApiKey string `json:"apiKey"`
|
||||
// 是否允许不安全的连接。
|
||||
@@ -26,7 +29,7 @@ type DeployerConfig struct {
|
||||
type DeployerProvider struct {
|
||||
config *DeployerConfig
|
||||
logger *slog.Logger
|
||||
sdkClient *opsdk.Client
|
||||
sdkClient *onepanelsdk.Client
|
||||
}
|
||||
|
||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
||||
@@ -36,7 +39,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
panic("config is nil")
|
||||
}
|
||||
|
||||
client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.AllowInsecureConnections)
|
||||
client, err := createSdkClient(config.ApiUrl, config.ApiVersion, config.ApiKey, config.AllowInsecureConnections)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||
}
|
||||
@@ -59,7 +62,7 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
|
||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
|
||||
// 设置面板 SSL 证书
|
||||
updateSystemSSLReq := &opsdk.UpdateSystemSSLRequest{
|
||||
updateSystemSSLReq := &onepanelsdk.UpdateSystemSSLRequest{
|
||||
Cert: certPEM,
|
||||
Key: privkeyPEM,
|
||||
SSL: "enable",
|
||||
@@ -79,16 +82,20 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
||||
return &deployer.DeployResult{}, nil
|
||||
}
|
||||
|
||||
func createSdkClient(apiUrl, apiKey string, skipTlsVerify bool) (*opsdk.Client, error) {
|
||||
func createSdkClient(apiUrl, apiVersion, apiKey string, skipTlsVerify bool) (*onepanelsdk.Client, error) {
|
||||
if _, err := url.Parse(apiUrl); err != nil {
|
||||
return nil, errors.New("invalid 1panel api url")
|
||||
}
|
||||
|
||||
if apiVersion == "" {
|
||||
return nil, errors.New("invalid 1panel api version")
|
||||
}
|
||||
|
||||
if apiKey == "" {
|
||||
return nil, errors.New("invalid 1panel api key")
|
||||
}
|
||||
|
||||
client := opsdk.NewClient(apiUrl, apiKey)
|
||||
client := onepanelsdk.NewClient(apiUrl, apiVersion, apiKey)
|
||||
if skipTlsVerify {
|
||||
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ var (
|
||||
fInputCertPath string
|
||||
fInputKeyPath string
|
||||
fApiUrl string
|
||||
fApiVersion string
|
||||
fApiKey string
|
||||
)
|
||||
|
||||
@@ -24,6 +25,7 @@ func init() {
|
||||
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||
flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "")
|
||||
flag.StringVar(&fApiVersion, argsPrefix+"APIVERSION", "v1", "")
|
||||
flag.StringVar(&fApiKey, argsPrefix+"APIKEY", "", "")
|
||||
}
|
||||
|
||||
@@ -34,6 +36,7 @@ Shell command to run this test:
|
||||
--CERTIMATE_DEPLOYER_1PANELCONSOLE_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||
--CERTIMATE_DEPLOYER_1PANELCONSOLE_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||
--CERTIMATE_DEPLOYER_1PANELCONSOLE_APIURL="http://127.0.0.1:20410" \
|
||||
--CERTIMATE_DEPLOYER_1PANELCONSOLE_APIVERSION="v1" \
|
||||
--CERTIMATE_DEPLOYER_1PANELCONSOLE_APIKEY="your-api-key"
|
||||
*/
|
||||
func TestDeploy(t *testing.T) {
|
||||
@@ -45,11 +48,13 @@ func TestDeploy(t *testing.T) {
|
||||
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
||||
fmt.Sprintf("APIURL: %v", fApiUrl),
|
||||
fmt.Sprintf("APIVERSION: %v", fApiVersion),
|
||||
fmt.Sprintf("APIKEY: %v", fApiKey),
|
||||
}, "\n"))
|
||||
|
||||
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||
ApiUrl: fApiUrl,
|
||||
ApiVersion: fApiVersion,
|
||||
ApiKey: fApiKey,
|
||||
AllowInsecureConnections: true,
|
||||
AutoRestart: true,
|
||||
|
||||
@@ -12,12 +12,15 @@ import (
|
||||
"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/1panel-ssl"
|
||||
opsdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/1panel"
|
||||
onepanelsdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/1panel"
|
||||
)
|
||||
|
||||
type DeployerConfig struct {
|
||||
// 1Panel 地址。
|
||||
ApiUrl string `json:"apiUrl"`
|
||||
// 1Panel 版本。
|
||||
// 可取值 "v1"、"v2"。
|
||||
ApiVersion string `json:"apiVersion"`
|
||||
// 1Panel 接口密钥。
|
||||
ApiKey string `json:"apiKey"`
|
||||
// 是否允许不安全的连接。
|
||||
@@ -35,7 +38,7 @@ type DeployerConfig struct {
|
||||
type DeployerProvider struct {
|
||||
config *DeployerConfig
|
||||
logger *slog.Logger
|
||||
sdkClient *opsdk.Client
|
||||
sdkClient *onepanelsdk.Client
|
||||
sslUploader uploader.Uploader
|
||||
}
|
||||
|
||||
@@ -46,14 +49,15 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
panic("config is nil")
|
||||
}
|
||||
|
||||
client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.AllowInsecureConnections)
|
||||
client, err := createSdkClient(config.ApiUrl, config.ApiVersion, config.ApiKey, config.AllowInsecureConnections)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||
}
|
||||
|
||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||
ApiUrl: config.ApiUrl,
|
||||
ApiKey: config.ApiKey,
|
||||
ApiUrl: config.ApiUrl,
|
||||
ApiVersion: config.ApiVersion,
|
||||
ApiKey: config.ApiKey,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||
@@ -103,7 +107,7 @@ func (d *DeployerProvider) deployToWebsite(ctx context.Context, certPEM string,
|
||||
}
|
||||
|
||||
// 获取网站 HTTPS 配置
|
||||
getHttpsConfReq := &opsdk.GetHttpsConfRequest{
|
||||
getHttpsConfReq := &onepanelsdk.GetHttpsConfRequest{
|
||||
WebsiteID: d.config.WebsiteId,
|
||||
}
|
||||
getHttpsConfResp, err := d.sdkClient.GetHttpsConf(getHttpsConfReq)
|
||||
@@ -122,7 +126,7 @@ func (d *DeployerProvider) deployToWebsite(ctx context.Context, certPEM string,
|
||||
|
||||
// 修改网站 HTTPS 配置
|
||||
certId, _ := strconv.ParseInt(upres.CertId, 10, 64)
|
||||
updateHttpsConfReq := &opsdk.UpdateHttpsConfRequest{
|
||||
updateHttpsConfReq := &onepanelsdk.UpdateHttpsConfRequest{
|
||||
WebsiteID: d.config.WebsiteId,
|
||||
Type: "existed",
|
||||
WebsiteSSLID: certId,
|
||||
@@ -147,7 +151,7 @@ func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPEM stri
|
||||
}
|
||||
|
||||
// 获取证书详情
|
||||
getWebsiteSSLReq := &opsdk.GetWebsiteSSLRequest{
|
||||
getWebsiteSSLReq := &onepanelsdk.GetWebsiteSSLRequest{
|
||||
SSLID: d.config.CertificateId,
|
||||
}
|
||||
getWebsiteSSLResp, err := d.sdkClient.GetWebsiteSSL(getWebsiteSSLReq)
|
||||
@@ -157,7 +161,7 @@ func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPEM stri
|
||||
}
|
||||
|
||||
// 更新证书
|
||||
uploadWebsiteSSLReq := &opsdk.UploadWebsiteSSLRequest{
|
||||
uploadWebsiteSSLReq := &onepanelsdk.UploadWebsiteSSLRequest{
|
||||
Type: "paste",
|
||||
SSLID: d.config.CertificateId,
|
||||
Description: getWebsiteSSLResp.Data.Description,
|
||||
@@ -173,16 +177,20 @@ func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPEM stri
|
||||
return nil
|
||||
}
|
||||
|
||||
func createSdkClient(apiUrl, apiKey string, skipTlsVerify bool) (*opsdk.Client, error) {
|
||||
func createSdkClient(apiUrl, apiVersion, apiKey string, skipTlsVerify bool) (*onepanelsdk.Client, error) {
|
||||
if _, err := url.Parse(apiUrl); err != nil {
|
||||
return nil, errors.New("invalid 1panel api url")
|
||||
}
|
||||
|
||||
if apiVersion == "" {
|
||||
return nil, errors.New("invalid 1panel api version")
|
||||
}
|
||||
|
||||
if apiKey == "" {
|
||||
return nil, errors.New("invalid 1panel api key")
|
||||
}
|
||||
|
||||
client := opsdk.NewClient(apiUrl, apiKey)
|
||||
client := onepanelsdk.NewClient(apiUrl, apiVersion, apiKey)
|
||||
if skipTlsVerify {
|
||||
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ var (
|
||||
fInputCertPath string
|
||||
fInputKeyPath string
|
||||
fApiUrl string
|
||||
fApiVersion string
|
||||
fApiKey string
|
||||
fWebsiteId int64
|
||||
)
|
||||
@@ -25,6 +26,7 @@ func init() {
|
||||
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||
flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "")
|
||||
flag.StringVar(&fApiVersion, argsPrefix+"APIVERSION", "v1", "")
|
||||
flag.StringVar(&fApiKey, argsPrefix+"APIKEY", "", "")
|
||||
flag.Int64Var(&fWebsiteId, argsPrefix+"WEBSITEID", 0, "")
|
||||
}
|
||||
@@ -36,6 +38,7 @@ Shell command to run this test:
|
||||
--CERTIMATE_DEPLOYER_1PANELSITE_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||
--CERTIMATE_DEPLOYER_1PANELSITE_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||
--CERTIMATE_DEPLOYER_1PANELSITE_APIURL="http://127.0.0.1:20410" \
|
||||
--CERTIMATE_DEPLOYER_1PANELSITE_APIVERSION="v1" \
|
||||
--CERTIMATE_DEPLOYER_1PANELSITE_APIKEY="your-api-key" \
|
||||
--CERTIMATE_DEPLOYER_1PANELSITE_WEBSITEID="your-website-id"
|
||||
*/
|
||||
@@ -48,12 +51,14 @@ func TestDeploy(t *testing.T) {
|
||||
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
||||
fmt.Sprintf("APIURL: %v", fApiUrl),
|
||||
fmt.Sprintf("APIVERSION: %v", fApiVersion),
|
||||
fmt.Sprintf("APIKEY: %v", fApiKey),
|
||||
fmt.Sprintf("WEBSITEID: %v", fWebsiteId),
|
||||
}, "\n"))
|
||||
|
||||
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||
ApiUrl: fApiUrl,
|
||||
ApiVersion: fApiVersion,
|
||||
ApiKey: fApiKey,
|
||||
AllowInsecureConnections: true,
|
||||
ResourceType: provider.RESOURCE_TYPE_WEBSITE,
|
||||
|
||||
@@ -157,7 +157,7 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
|
||||
|
||||
if listListenersResp.Body.Listeners != nil {
|
||||
for _, listener := range listListenersResp.Body.Listeners {
|
||||
listenerIds = append(listenerIds, *listener.ListenerId)
|
||||
listenerIds = append(listenerIds, tea.StringValue(listener.ListenerId))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
|
||||
|
||||
if listListenersResp.Body.Listeners != nil {
|
||||
for _, listener := range listListenersResp.Body.Listeners {
|
||||
listenerIds = append(listenerIds, *listener.ListenerId)
|
||||
listenerIds = append(listenerIds, tea.StringValue(listener.ListenerId))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,8 +211,13 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
|
||||
d.logger.Info("found https/quic listeners to deploy", slog.Any("listenerIds", listenerIds))
|
||||
|
||||
for _, listenerId := range listenerIds {
|
||||
if err := d.updateListenerCertificate(ctx, listenerId, cloudCertId); err != nil {
|
||||
errs = append(errs, err)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
if err := d.updateListenerCertificate(ctx, listenerId, cloudCertId); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -96,6 +96,7 @@ func TestDeploy(t *testing.T) {
|
||||
fmt.Sprintf("ACCESSKEYSECRET: %v", fAccessKeySecret),
|
||||
fmt.Sprintf("REGION: %v", fRegion),
|
||||
fmt.Sprintf("LISTENERID: %v", fListenerId),
|
||||
fmt.Sprintf("DOMAIN: %v", fDomain),
|
||||
}, "\n"))
|
||||
|
||||
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||
|
||||
@@ -171,7 +171,6 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
|
||||
default:
|
||||
if err := d.updateListenerCertificate(ctx, d.config.LoadbalancerId, listenerPort, cloudCertId); err != nil {
|
||||
errs = append(errs, err)
|
||||
|
||||
@@ -18,7 +18,7 @@ var (
|
||||
fAccessKeySecret string
|
||||
fRegion string
|
||||
fLoadbalancerId string
|
||||
fListenerPort int
|
||||
fListenerPort int64
|
||||
fDomain string
|
||||
)
|
||||
|
||||
@@ -31,7 +31,7 @@ func init() {
|
||||
flag.StringVar(&fAccessKeySecret, argsPrefix+"ACCESSKEYSECRET", "", "")
|
||||
flag.StringVar(&fRegion, argsPrefix+"REGION", "", "")
|
||||
flag.StringVar(&fLoadbalancerId, argsPrefix+"LOADBALANCERID", "", "")
|
||||
flag.IntVar(&fListenerPort, argsPrefix+"LISTENERPORT", 443, "")
|
||||
flag.Int64Var(&fListenerPort, argsPrefix+"LISTENERPORT", 443, "")
|
||||
flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "")
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ type DeployerConfig struct {
|
||||
// 阿里云地域。
|
||||
Region string `json:"region"`
|
||||
// 服务版本。
|
||||
// 可取值 "2.0"、"3.0"。
|
||||
ServiceVersion string `json:"serviceVersion"`
|
||||
// 自定义域名(支持泛域名)。
|
||||
Domain string `json:"domain"`
|
||||
|
||||
322
internal/pkg/core/deployer/providers/aliyun-ga/aliyun_ga.go
Normal file
322
internal/pkg/core/deployer/providers/aliyun-ga/aliyun_ga.go
Normal file
@@ -0,0 +1,322 @@
|
||||
package aliyunga
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strings"
|
||||
|
||||
aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client"
|
||||
aliga "github.com/alibabacloud-go/ga-20191120/v3/client"
|
||||
"github.com/alibabacloud-go/tea/tea"
|
||||
|
||||
"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/aliyun-cas"
|
||||
sliceutil "github.com/usual2970/certimate/internal/pkg/utils/slice"
|
||||
)
|
||||
|
||||
type DeployerConfig struct {
|
||||
// 阿里云 AccessKeyId。
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 阿里云 AccessKeySecret。
|
||||
AccessKeySecret string `json:"accessKeySecret"`
|
||||
// 部署资源类型。
|
||||
ResourceType ResourceType `json:"resourceType"`
|
||||
// 全球加速实例 ID。
|
||||
AcceleratorId string `json:"acceleratorId"`
|
||||
// 全球加速监听 ID。
|
||||
// 部署资源类型为 [RESOURCE_TYPE_LISTENER] 时必填。
|
||||
ListenerId string `json:"listenerId,omitempty"`
|
||||
// SNI 域名(不支持泛域名)。
|
||||
// 部署资源类型为 [RESOURCE_TYPE_ACCELERATOR]、[RESOURCE_TYPE_LISTENER] 时选填。
|
||||
Domain string `json:"domain,omitempty"`
|
||||
}
|
||||
|
||||
type DeployerProvider struct {
|
||||
config *DeployerConfig
|
||||
logger *slog.Logger
|
||||
sdkClient *aliga.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.AccessKeySecret)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||
}
|
||||
|
||||
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret)
|
||||
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.Default()
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
d.sslUploader.WithLogger(logger)
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
|
||||
// 上传证书到 CAS
|
||||
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_ACCELERATOR:
|
||||
if err := d.deployToAccelerator(ctx, upres.ExtendedData["certIdentifier"].(string)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
case RESOURCE_TYPE_LISTENER:
|
||||
if err := d.deployToListener(ctx, upres.ExtendedData["certIdentifier"].(string)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported resource type '%s'", d.config.ResourceType)
|
||||
}
|
||||
|
||||
return &deployer.DeployResult{}, nil
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) deployToAccelerator(ctx context.Context, cloudCertId string) error {
|
||||
if d.config.AcceleratorId == "" {
|
||||
return errors.New("config `acceleratorId` is required")
|
||||
}
|
||||
|
||||
// 查询 HTTPS 监听列表
|
||||
// REF: https://help.aliyun.com/zh/ga/developer-reference/api-ga-2019-11-20-listlisteners
|
||||
listenerIds := make([]string, 0)
|
||||
listListenersPageNumber := int32(1)
|
||||
listListenersPageSize := int32(50)
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
listListenersReq := &aliga.ListListenersRequest{
|
||||
RegionId: tea.String("cn-hangzhou"),
|
||||
AcceleratorId: tea.String(d.config.AcceleratorId),
|
||||
PageNumber: tea.Int32(listListenersPageNumber),
|
||||
PageSize: tea.Int32(listListenersPageSize),
|
||||
}
|
||||
listListenersResp, err := d.sdkClient.ListListeners(listListenersReq)
|
||||
d.logger.Debug("sdk request 'ga.ListListeners'", slog.Any("request", listListenersReq), slog.Any("response", listListenersResp))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'ga.ListListeners': %w", err)
|
||||
}
|
||||
|
||||
if listListenersResp.Body.Listeners != nil {
|
||||
for _, listener := range listListenersResp.Body.Listeners {
|
||||
if strings.EqualFold(tea.StringValue(listener.Protocol), "https") {
|
||||
listenerIds = append(listenerIds, tea.StringValue(listener.ListenerId))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(listListenersResp.Body.Listeners) < int(listListenersPageSize) {
|
||||
break
|
||||
} else {
|
||||
listListenersPageNumber++
|
||||
}
|
||||
}
|
||||
|
||||
// 遍历更新监听证书
|
||||
if len(listenerIds) == 0 {
|
||||
d.logger.Info("no ga listeners to deploy")
|
||||
} else {
|
||||
var errs []error
|
||||
d.logger.Info("found https listeners to deploy", slog.Any("listenerIds", listenerIds))
|
||||
|
||||
for _, listenerId := range listenerIds {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
if err := d.updateListenerCertificate(ctx, d.config.AcceleratorId, 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.AcceleratorId == "" {
|
||||
return errors.New("config `acceleratorId` is required")
|
||||
}
|
||||
if d.config.ListenerId == "" {
|
||||
return errors.New("config `listenerId` is required")
|
||||
}
|
||||
|
||||
// 更新监听
|
||||
if err := d.updateListenerCertificate(ctx, d.config.AcceleratorId, d.config.ListenerId, cloudCertId); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudAcceleratorId string, cloudListenerId string, cloudCertId string) error {
|
||||
// 查询监听绑定的证书列表
|
||||
// REF: https://help.aliyun.com/zh/ga/developer-reference/api-ga-2019-11-20-listlistenercertificates
|
||||
var listenerDefaultCertificate *aliga.ListListenerCertificatesResponseBodyCertificates
|
||||
var listenerAdditionalCertificates []*aliga.ListListenerCertificatesResponseBodyCertificates = make([]*aliga.ListListenerCertificatesResponseBodyCertificates, 0)
|
||||
var listListenerCertificatesNextToken *string
|
||||
for {
|
||||
listListenerCertificatesReq := &aliga.ListListenerCertificatesRequest{
|
||||
RegionId: tea.String("cn-hangzhou"),
|
||||
AcceleratorId: tea.String(d.config.AcceleratorId),
|
||||
NextToken: listListenerCertificatesNextToken,
|
||||
MaxResults: tea.Int32(20),
|
||||
}
|
||||
listListenerCertificatesResp, err := d.sdkClient.ListListenerCertificates(listListenerCertificatesReq)
|
||||
d.logger.Debug("sdk request 'ga.ListListenerCertificates'", slog.Any("request", listListenerCertificatesReq), slog.Any("response", listListenerCertificatesResp))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'ga.ListListenerCertificates': %w", err)
|
||||
}
|
||||
|
||||
if listListenerCertificatesResp.Body.Certificates != nil {
|
||||
for _, certificate := range listListenerCertificatesResp.Body.Certificates {
|
||||
if tea.BoolValue(certificate.IsDefault) {
|
||||
listenerDefaultCertificate = certificate
|
||||
} else {
|
||||
listenerAdditionalCertificates = append(listenerAdditionalCertificates, certificate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if listListenerCertificatesResp.Body.NextToken == nil {
|
||||
break
|
||||
} else {
|
||||
listListenerCertificatesNextToken = listListenerCertificatesResp.Body.NextToken
|
||||
}
|
||||
}
|
||||
|
||||
if d.config.Domain == "" {
|
||||
// 未指定 SNI,只需部署到监听器
|
||||
if listenerDefaultCertificate != nil && tea.StringValue(listenerDefaultCertificate.CertificateId) == cloudCertId {
|
||||
d.logger.Info("no need to update ga listener default certificate")
|
||||
return nil
|
||||
}
|
||||
|
||||
// 修改监听的属性
|
||||
// REF: https://help.aliyun.com/zh/ga/developer-reference/api-ga-2019-11-20-updatelistener
|
||||
updateListenerReq := &aliga.UpdateListenerRequest{
|
||||
RegionId: tea.String("cn-hangzhou"),
|
||||
ListenerId: tea.String(cloudListenerId),
|
||||
Certificates: []*aliga.UpdateListenerRequestCertificates{{
|
||||
Id: tea.String(cloudCertId),
|
||||
}},
|
||||
}
|
||||
updateListenerResp, err := d.sdkClient.UpdateListener(updateListenerReq)
|
||||
d.logger.Debug("sdk request 'ga.UpdateListener'", slog.Any("request", updateListenerReq), slog.Any("response", updateListenerResp))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'ga.UpdateListener': %w", err)
|
||||
}
|
||||
} else {
|
||||
// 指定 SNI,需部署到扩展域名
|
||||
if sliceutil.Some(listenerAdditionalCertificates, func(item *aliga.ListListenerCertificatesResponseBodyCertificates) bool {
|
||||
return tea.StringValue(item.CertificateId) == cloudCertId
|
||||
}) {
|
||||
d.logger.Info("no need to update ga listener additional certificate")
|
||||
return nil
|
||||
}
|
||||
|
||||
if sliceutil.Some(listenerAdditionalCertificates, func(item *aliga.ListListenerCertificatesResponseBodyCertificates) bool {
|
||||
return tea.StringValue(item.Domain) == d.config.Domain
|
||||
}) {
|
||||
// 为监听替换扩展证书
|
||||
// REF: https://help.aliyun.com/zh/ga/developer-reference/api-ga-2019-11-20-updateadditionalcertificatewithlistener
|
||||
updateAdditionalCertificateWithListenerReq := &aliga.UpdateAdditionalCertificateWithListenerRequest{
|
||||
RegionId: tea.String("cn-hangzhou"),
|
||||
AcceleratorId: tea.String(cloudAcceleratorId),
|
||||
ListenerId: tea.String(cloudListenerId),
|
||||
CertificateId: tea.String(cloudCertId),
|
||||
Domain: tea.String(d.config.Domain),
|
||||
}
|
||||
updateAdditionalCertificateWithListenerResp, err := d.sdkClient.UpdateAdditionalCertificateWithListener(updateAdditionalCertificateWithListenerReq)
|
||||
d.logger.Debug("sdk request 'ga.UpdateAdditionalCertificateWithListener'", slog.Any("request", updateAdditionalCertificateWithListenerReq), slog.Any("response", updateAdditionalCertificateWithListenerResp))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'ga.UpdateAdditionalCertificateWithListener': %w", err)
|
||||
}
|
||||
} else {
|
||||
// 为监听绑定扩展证书
|
||||
// REF: https://help.aliyun.com/zh/ga/developer-reference/api-ga-2019-11-20-associateadditionalcertificateswithlistener
|
||||
associateAdditionalCertificatesWithListenerReq := &aliga.AssociateAdditionalCertificatesWithListenerRequest{
|
||||
RegionId: tea.String("cn-hangzhou"),
|
||||
AcceleratorId: tea.String(cloudAcceleratorId),
|
||||
ListenerId: tea.String(cloudListenerId),
|
||||
Certificates: []*aliga.AssociateAdditionalCertificatesWithListenerRequestCertificates{{
|
||||
Id: tea.String(cloudCertId),
|
||||
Domain: tea.String(d.config.Domain),
|
||||
}},
|
||||
}
|
||||
associateAdditionalCertificatesWithListenerResp, err := d.sdkClient.AssociateAdditionalCertificatesWithListener(associateAdditionalCertificatesWithListenerReq)
|
||||
d.logger.Debug("sdk request 'ga.AssociateAdditionalCertificatesWithListener'", slog.Any("request", associateAdditionalCertificatesWithListenerReq), slog.Any("response", associateAdditionalCertificatesWithListenerResp))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'ga.AssociateAdditionalCertificatesWithListener': %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createSdkClient(accessKeyId, accessKeySecret string) (*aliga.Client, error) {
|
||||
// 接入点一览 https://api.aliyun.com/product/Ga
|
||||
config := &aliopen.Config{
|
||||
AccessKeyId: tea.String(accessKeyId),
|
||||
AccessKeySecret: tea.String(accessKeySecret),
|
||||
Endpoint: tea.String("ga.cn-hangzhou.aliyuncs.com"),
|
||||
}
|
||||
|
||||
client, err := aliga.NewClient(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func createSslUploader(accessKeyId, accessKeySecret string) (uploader.Uploader, error) {
|
||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||
AccessKeyId: accessKeyId,
|
||||
AccessKeySecret: accessKeySecret,
|
||||
Region: "cn-hangzhou",
|
||||
})
|
||||
return uploader, err
|
||||
}
|
||||
118
internal/pkg/core/deployer/providers/aliyun-ga/aliyun_ga_test.go
Normal file
118
internal/pkg/core/deployer/providers/aliyun-ga/aliyun_ga_test.go
Normal file
@@ -0,0 +1,118 @@
|
||||
package aliyunga_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-ga"
|
||||
)
|
||||
|
||||
var (
|
||||
fInputCertPath string
|
||||
fInputKeyPath string
|
||||
fAccessKeyId string
|
||||
fAccessKeySecret string
|
||||
fAcceleratorId string
|
||||
fListenerId string
|
||||
fDomain string
|
||||
)
|
||||
|
||||
func init() {
|
||||
argsPrefix := "CERTIMATE_DEPLOYER_ALIYUNGA_"
|
||||
|
||||
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||
flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "")
|
||||
flag.StringVar(&fAccessKeySecret, argsPrefix+"ACCESSKEYSECRET", "", "")
|
||||
flag.StringVar(&fAcceleratorId, argsPrefix+"ACCELERATORID", "", "")
|
||||
flag.StringVar(&fListenerId, argsPrefix+"LISTENERID", "", "")
|
||||
flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -v ./aliyun_ga_test.go -args \
|
||||
--CERTIMATE_DEPLOYER_ALIYUNGA_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||
--CERTIMATE_DEPLOYER_ALIYUNGA_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||
--CERTIMATE_DEPLOYER_ALIYUNGA_ACCESSKEYID="your-access-key-id" \
|
||||
--CERTIMATE_DEPLOYER_ALIYUNGA_ACCESSKEYSECRET="your-access-key-secret" \
|
||||
--CERTIMATE_DEPLOYER_ALIYUNGA_ACCELERATORID="your-ga-accelerator-id" \
|
||||
--CERTIMATE_DEPLOYER_ALIYUNGA_LISTENERID="your-ga-listener-id" \
|
||||
--CERTIMATE_DEPLOYER_ALIYUNGA_DOMAIN="your-ga-sni-domain"
|
||||
*/
|
||||
func TestDeploy(t *testing.T) {
|
||||
flag.Parse()
|
||||
|
||||
t.Run("Deploy_ToAccelerator", 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("ACCESSKEYSECRET: %v", fAccessKeySecret),
|
||||
fmt.Sprintf("ACCELERATORID: %v", fAcceleratorId),
|
||||
fmt.Sprintf("DOMAIN: %v", fDomain),
|
||||
}, "\n"))
|
||||
|
||||
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||
AccessKeyId: fAccessKeyId,
|
||||
AccessKeySecret: fAccessKeySecret,
|
||||
ResourceType: provider.RESOURCE_TYPE_ACCELERATOR,
|
||||
AcceleratorId: fAcceleratorId,
|
||||
Domain: fDomain,
|
||||
})
|
||||
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("ACCESSKEYSECRET: %v", fAccessKeySecret),
|
||||
fmt.Sprintf("LISTENERID: %v", fListenerId),
|
||||
fmt.Sprintf("DOMAIN: %v", fDomain),
|
||||
}, "\n"))
|
||||
|
||||
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||
AccessKeyId: fAccessKeyId,
|
||||
AccessKeySecret: fAccessKeySecret,
|
||||
ResourceType: provider.RESOURCE_TYPE_LISTENER,
|
||||
ListenerId: fListenerId,
|
||||
Domain: fDomain,
|
||||
})
|
||||
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)
|
||||
})
|
||||
}
|
||||
10
internal/pkg/core/deployer/providers/aliyun-ga/consts.go
Normal file
10
internal/pkg/core/deployer/providers/aliyun-ga/consts.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package aliyunga
|
||||
|
||||
type ResourceType string
|
||||
|
||||
const (
|
||||
// 资源类型:部署到指定全球加速器。
|
||||
RESOURCE_TYPE_ACCELERATOR = ResourceType("accelerator")
|
||||
// 资源类型:部署到指定监听器。
|
||||
RESOURCE_TYPE_LISTENER = ResourceType("listener")
|
||||
)
|
||||
@@ -145,7 +145,7 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
|
||||
|
||||
if listListenersResp.Body.Listeners != nil {
|
||||
for _, listener := range listListenersResp.Body.Listeners {
|
||||
listenerIds = append(listenerIds, *listener.ListenerId)
|
||||
listenerIds = append(listenerIds, tea.StringValue(listener.ListenerId))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,7 +167,6 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
|
||||
default:
|
||||
if err := d.updateListenerCertificate(ctx, listenerId, cloudCertId); err != nil {
|
||||
errs = append(errs, err)
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
package baotapanelconsole
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/url"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||
btsdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/btwaf"
|
||||
)
|
||||
|
||||
type DeployerConfig struct {
|
||||
// 堡塔云 WAF 地址。
|
||||
ApiUrl string `json:"apiUrl"`
|
||||
// 堡塔云 WAF 接口密钥。
|
||||
ApiKey string `json:"apiKey"`
|
||||
// 是否允许不安全的连接。
|
||||
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||
}
|
||||
|
||||
type DeployerProvider struct {
|
||||
config *DeployerConfig
|
||||
logger *slog.Logger
|
||||
sdkClient *btsdk.Client
|
||||
}
|
||||
|
||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
||||
|
||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
if config == nil {
|
||||
panic("config is nil")
|
||||
}
|
||||
|
||||
client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.AllowInsecureConnections)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||
}
|
||||
|
||||
return &DeployerProvider{
|
||||
config: config,
|
||||
logger: slog.Default(),
|
||||
sdkClient: client,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
|
||||
// 设置面板 SSL
|
||||
configSetSSLReq := &btsdk.ConfigSetSSLRequest{
|
||||
CertContent: certPEM,
|
||||
KeyContent: privkeyPEM,
|
||||
}
|
||||
configSetSSLResp, err := d.sdkClient.ConfigSetSSL(configSetSSLReq)
|
||||
d.logger.Debug("sdk request 'bt.ConfigSetSSL'", slog.Any("request", configSetSSLReq), slog.Any("response", configSetSSLResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'bt.ConfigSetSSL': %w", err)
|
||||
}
|
||||
|
||||
return &deployer.DeployResult{}, nil
|
||||
}
|
||||
|
||||
func createSdkClient(apiUrl, apiKey string, skipTlsVerify bool) (*btsdk.Client, error) {
|
||||
if _, err := url.Parse(apiUrl); err != nil {
|
||||
return nil, errors.New("invalid baota api url")
|
||||
}
|
||||
|
||||
if apiKey == "" {
|
||||
return nil, errors.New("invalid baota api key")
|
||||
}
|
||||
|
||||
client := btsdk.NewClient(apiUrl, apiKey)
|
||||
if skipTlsVerify {
|
||||
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package baotapanelconsole_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baotawaf-console"
|
||||
)
|
||||
|
||||
var (
|
||||
fInputCertPath string
|
||||
fInputKeyPath string
|
||||
fApiUrl string
|
||||
fApiKey string
|
||||
fSiteName string
|
||||
fSitePort int64
|
||||
)
|
||||
|
||||
func init() {
|
||||
argsPrefix := "CERTIMATE_DEPLOYER_BAOTAWAFCONSOLE_"
|
||||
|
||||
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||
flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "")
|
||||
flag.StringVar(&fApiKey, argsPrefix+"APIKEY", "", "")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -v ./baotawaf_console_test.go -args \
|
||||
--CERTIMATE_DEPLOYER_BAOTAWAFCONSOLE_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||
--CERTIMATE_DEPLOYER_BAOTAWAFCONSOLE_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||
--CERTIMATE_DEPLOYER_BAOTAWAFCONSOLE_APIURL="http://127.0.0.1:8888" \
|
||||
--CERTIMATE_DEPLOYER_BAOTAWAFCONSOLE_APIKEY="your-api-key"
|
||||
*/
|
||||
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("APIURL: %v", fApiUrl),
|
||||
fmt.Sprintf("APIKEY: %v", fApiKey),
|
||||
}, "\n"))
|
||||
|
||||
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||
ApiUrl: fApiUrl,
|
||||
ApiKey: fApiKey,
|
||||
AllowInsecureConnections: true,
|
||||
})
|
||||
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,151 @@
|
||||
package baotapanelwaf
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/url"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||
btsdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/btwaf"
|
||||
typeutil "github.com/usual2970/certimate/internal/pkg/utils/type"
|
||||
)
|
||||
|
||||
type DeployerConfig struct {
|
||||
// 堡塔云 WAF 地址。
|
||||
ApiUrl string `json:"apiUrl"`
|
||||
// 堡塔云 WAF 接口密钥。
|
||||
ApiKey string `json:"apiKey"`
|
||||
// 是否允许不安全的连接。
|
||||
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||
// 网站名称。
|
||||
SiteName string `json:"siteName"`
|
||||
// 网站 SSL 端口。
|
||||
// 零值时默认为 443。
|
||||
SitePort int32 `json:"sitePort,omitempty"`
|
||||
}
|
||||
|
||||
type DeployerProvider struct {
|
||||
config *DeployerConfig
|
||||
logger *slog.Logger
|
||||
sdkClient *btsdk.Client
|
||||
}
|
||||
|
||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
||||
|
||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
if config == nil {
|
||||
panic("config is nil")
|
||||
}
|
||||
|
||||
client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.AllowInsecureConnections)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||
}
|
||||
|
||||
return &DeployerProvider{
|
||||
config: config,
|
||||
logger: slog.Default(),
|
||||
sdkClient: client,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
|
||||
if d.config.SiteName == "" {
|
||||
return nil, errors.New("config `siteName` is required")
|
||||
}
|
||||
if d.config.SitePort == 0 {
|
||||
d.config.SitePort = 443
|
||||
}
|
||||
|
||||
// 遍历获取网站列表,获取网站 ID
|
||||
// REF: https://support.huaweicloud.com/api-waf/ListHost.html
|
||||
siteId := ""
|
||||
getSitListPage := int32(1)
|
||||
getSitListPageSize := int32(100)
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
getSiteListReq := &btsdk.GetSiteListRequest{
|
||||
SiteName: typeutil.ToPtr(d.config.SiteName),
|
||||
Page: typeutil.ToPtr(getSitListPage),
|
||||
PageSize: typeutil.ToPtr(getSitListPageSize),
|
||||
}
|
||||
getSiteListResp, err := d.sdkClient.GetSiteList(getSiteListReq)
|
||||
d.logger.Debug("sdk request 'bt.GetSiteList'", slog.Any("request", getSiteListReq), slog.Any("response", getSiteListResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'bt.GetSiteList': %w", err)
|
||||
}
|
||||
|
||||
if getSiteListResp.Result != nil && getSiteListResp.Result.List != nil {
|
||||
for _, siteItem := range getSiteListResp.Result.List {
|
||||
if siteItem.SiteName == d.config.SiteName {
|
||||
siteId = siteItem.SiteId
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if getSiteListResp.Result == nil || len(getSiteListResp.Result.List) < int(getSitListPageSize) {
|
||||
break
|
||||
} else {
|
||||
getSitListPage++
|
||||
}
|
||||
}
|
||||
if siteId == "" {
|
||||
return nil, errors.New("site not found")
|
||||
}
|
||||
|
||||
// 修改站点配置
|
||||
modifySiteReq := &btsdk.ModifySiteRequest{
|
||||
SiteId: siteId,
|
||||
Type: typeutil.ToPtr("openCert"),
|
||||
Server: &btsdk.SiteServerInfo{
|
||||
ListenSSLPort: typeutil.ToPtr(d.config.SitePort),
|
||||
SSL: &btsdk.SiteServerSSLInfo{
|
||||
IsSSL: typeutil.ToPtr(int32(1)),
|
||||
FullChain: typeutil.ToPtr(certPEM),
|
||||
PrivateKey: typeutil.ToPtr(privkeyPEM),
|
||||
},
|
||||
},
|
||||
}
|
||||
modifySiteResp, err := d.sdkClient.ModifySite(modifySiteReq)
|
||||
d.logger.Debug("sdk request 'bt.ModifySite'", slog.Any("request", modifySiteReq), slog.Any("response", modifySiteResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'bt.ModifySite': %w", err)
|
||||
}
|
||||
|
||||
return &deployer.DeployResult{}, nil
|
||||
}
|
||||
|
||||
func createSdkClient(apiUrl, apiKey string, skipTlsVerify bool) (*btsdk.Client, error) {
|
||||
if _, err := url.Parse(apiUrl); err != nil {
|
||||
return nil, errors.New("invalid baota api url")
|
||||
}
|
||||
|
||||
if apiKey == "" {
|
||||
return nil, errors.New("invalid baota api key")
|
||||
}
|
||||
|
||||
client := btsdk.NewClient(apiUrl, apiKey)
|
||||
if skipTlsVerify {
|
||||
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package baotapanelwaf_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baotawaf-site"
|
||||
)
|
||||
|
||||
var (
|
||||
fInputCertPath string
|
||||
fInputKeyPath string
|
||||
fApiUrl string
|
||||
fApiKey string
|
||||
fSiteName string
|
||||
fSitePort int64
|
||||
)
|
||||
|
||||
func init() {
|
||||
argsPrefix := "CERTIMATE_DEPLOYER_BAOTAWAFSITE_"
|
||||
|
||||
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||
flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "")
|
||||
flag.StringVar(&fApiKey, argsPrefix+"APIKEY", "", "")
|
||||
flag.StringVar(&fSiteName, argsPrefix+"SITENAME", "", "")
|
||||
flag.Int64Var(&fSitePort, argsPrefix+"SITEPORT", 0, "")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -v ./baotawaf_site_test.go -args \
|
||||
--CERTIMATE_DEPLOYER_BAOTAWAFSITE_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||
--CERTIMATE_DEPLOYER_BAOTAWAFSITE_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||
--CERTIMATE_DEPLOYER_BAOTAWAFSITE_APIURL="http://127.0.0.1:8888" \
|
||||
--CERTIMATE_DEPLOYER_BAOTAWAFSITE_APIKEY="your-api-key" \
|
||||
--CERTIMATE_DEPLOYER_BAOTAWAFSITE_SITENAME="your-site-name"\
|
||||
--CERTIMATE_DEPLOYER_BAOTAWAFSITE_SITEPORT=443
|
||||
*/
|
||||
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("APIURL: %v", fApiUrl),
|
||||
fmt.Sprintf("APIKEY: %v", fApiKey),
|
||||
fmt.Sprintf("SITENAME: %v", fSiteName),
|
||||
fmt.Sprintf("SITEPORT: %v", fSitePort),
|
||||
}, "\n"))
|
||||
|
||||
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||
ApiUrl: fApiUrl,
|
||||
ApiKey: fApiKey,
|
||||
AllowInsecureConnections: true,
|
||||
SiteName: fSiteName,
|
||||
SitePort: int32(fSitePort),
|
||||
})
|
||||
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)
|
||||
})
|
||||
}
|
||||
8
internal/pkg/core/deployer/providers/flexcdn/consts.go
Normal file
8
internal/pkg/core/deployer/providers/flexcdn/consts.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package flexcdn
|
||||
|
||||
type ResourceType string
|
||||
|
||||
const (
|
||||
// 资源类型:替换指定证书。
|
||||
RESOURCE_TYPE_CERTIFICATE = ResourceType("certificate")
|
||||
)
|
||||
145
internal/pkg/core/deployer/providers/flexcdn/flexcdn.go
Normal file
145
internal/pkg/core/deployer/providers/flexcdn/flexcdn.go
Normal file
@@ -0,0 +1,145 @@
|
||||
package flexcdn
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||
flexcdnsdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/flexcdn"
|
||||
certutil "github.com/usual2970/certimate/internal/pkg/utils/cert"
|
||||
)
|
||||
|
||||
type DeployerConfig struct {
|
||||
// FlexCDN URL。
|
||||
ApiUrl string `json:"apiUrl"`
|
||||
// FlexCDN 用户角色。
|
||||
// 可取值 "user"、"admin"。
|
||||
ApiRole string `json:"apiRole"`
|
||||
// FlexCDN AccessKeyId。
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// FlexCDN AccessKey。
|
||||
AccessKey string `json:"accessKey"`
|
||||
// 是否允许不安全的连接。
|
||||
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||
// 部署资源类型。
|
||||
ResourceType ResourceType `json:"resourceType"`
|
||||
// 证书 ID。
|
||||
// 部署资源类型为 [RESOURCE_TYPE_CERTIFICATE] 时必填。
|
||||
CertificateId int64 `json:"certificateId,omitempty"`
|
||||
}
|
||||
|
||||
type DeployerProvider struct {
|
||||
config *DeployerConfig
|
||||
logger *slog.Logger
|
||||
sdkClient *flexcdnsdk.Client
|
||||
}
|
||||
|
||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
||||
|
||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
if config == nil {
|
||||
panic("config is nil")
|
||||
}
|
||||
|
||||
client, err := createSdkClient(config.ApiUrl, config.ApiRole, config.AccessKeyId, config.AccessKey, config.AllowInsecureConnections)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||
}
|
||||
|
||||
return &DeployerProvider{
|
||||
config: config,
|
||||
logger: slog.Default(),
|
||||
sdkClient: client,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
|
||||
// 根据部署资源类型决定部署方式
|
||||
switch d.config.ResourceType {
|
||||
case RESOURCE_TYPE_CERTIFICATE:
|
||||
if err := d.deployToCertificate(ctx, certPEM, privkeyPEM); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported resource type '%s'", d.config.ResourceType)
|
||||
}
|
||||
|
||||
return &deployer.DeployResult{}, nil
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPEM string, privkeyPEM string) error {
|
||||
if d.config.CertificateId == 0 {
|
||||
return errors.New("config `certificateId` is required")
|
||||
}
|
||||
|
||||
// 解析证书内容
|
||||
certX509, err := certutil.ParseCertificateFromPEM(certPEM)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 修改证书
|
||||
// REF: https://flexcdn.cloud/dev/api/service/SSLCertService?role=user#updateSSLCert
|
||||
updateSSLCertReq := &flexcdnsdk.UpdateSSLCertRequest{
|
||||
SSLCertId: d.config.CertificateId,
|
||||
IsOn: true,
|
||||
Name: fmt.Sprintf("certimate-%d", time.Now().UnixMilli()),
|
||||
Description: "upload from certimate",
|
||||
ServerName: certX509.Subject.CommonName,
|
||||
IsCA: false,
|
||||
CertData: base64.StdEncoding.EncodeToString([]byte(certPEM)),
|
||||
KeyData: base64.StdEncoding.EncodeToString([]byte(privkeyPEM)),
|
||||
TimeBeginAt: certX509.NotBefore.Unix(),
|
||||
TimeEndAt: certX509.NotAfter.Unix(),
|
||||
DNSNames: certX509.DNSNames,
|
||||
CommonNames: []string{certX509.Subject.CommonName},
|
||||
}
|
||||
updateSSLCertResp, err := d.sdkClient.UpdateSSLCert(updateSSLCertReq)
|
||||
d.logger.Debug("sdk request 'flexcdn.UpdateSSLCert'", slog.Any("request", updateSSLCertReq), slog.Any("response", updateSSLCertResp))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'flexcdn.UpdateSSLCert': %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createSdkClient(apiUrl, apiRole, accessKeyId, accessKey string, skipTlsVerify bool) (*flexcdnsdk.Client, error) {
|
||||
if _, err := url.Parse(apiUrl); err != nil {
|
||||
return nil, errors.New("invalid flexcdn api url")
|
||||
}
|
||||
|
||||
if apiRole != "user" && apiRole != "admin" {
|
||||
return nil, errors.New("invalid flexcdn api role")
|
||||
}
|
||||
|
||||
if accessKeyId == "" {
|
||||
return nil, errors.New("invalid flexcdn access key id")
|
||||
}
|
||||
|
||||
if accessKey == "" {
|
||||
return nil, errors.New("invalid flexcdn access key")
|
||||
}
|
||||
|
||||
client := flexcdnsdk.NewClient(apiUrl, apiRole, accessKeyId, accessKey)
|
||||
if skipTlsVerify {
|
||||
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
83
internal/pkg/core/deployer/providers/flexcdn/flexcdn_test.go
Normal file
83
internal/pkg/core/deployer/providers/flexcdn/flexcdn_test.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package flexcdn_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/flexcdn"
|
||||
)
|
||||
|
||||
var (
|
||||
fInputCertPath string
|
||||
fInputKeyPath string
|
||||
fApiUrl string
|
||||
fAccessKeyId string
|
||||
fAccessKey string
|
||||
fCertificateId int64
|
||||
)
|
||||
|
||||
func init() {
|
||||
argsPrefix := "CERTIMATE_DEPLOYER_FLEXCDN_"
|
||||
|
||||
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||
flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "")
|
||||
flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "")
|
||||
flag.StringVar(&fAccessKey, argsPrefix+"ACCESSKEY", "", "")
|
||||
flag.Int64Var(&fCertificateId, argsPrefix+"CERTIFICATEID", 0, "")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -v ./flexcdn_test.go -args \
|
||||
--CERTIMATE_DEPLOYER_FLEXCDN_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||
--CERTIMATE_DEPLOYER_FLEXCDN_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||
--CERTIMATE_DEPLOYER_FLEXCDN_APIURL="http://127.0.0.1:7788" \
|
||||
--CERTIMATE_DEPLOYER_FLEXCDN_ACCESSKEYID="your-access-key-id" \
|
||||
--CERTIMATE_DEPLOYER_FLEXCDN_ACCESSKEY="your-access-key" \
|
||||
--CERTIMATE_DEPLOYER_FLEXCDN_CERTIFICATEID="your-cerficiate-id"
|
||||
*/
|
||||
func TestDeploy(t *testing.T) {
|
||||
flag.Parse()
|
||||
|
||||
t.Run("Deploy_ToCertificate", func(t *testing.T) {
|
||||
t.Log(strings.Join([]string{
|
||||
"args:",
|
||||
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
||||
fmt.Sprintf("APIURL: %v", fApiUrl),
|
||||
fmt.Sprintf("ACCESSKEYID: %v", fAccessKeyId),
|
||||
fmt.Sprintf("ACCESSKEY: %v", fAccessKey),
|
||||
fmt.Sprintf("CERTIFICATEID: %v", fCertificateId),
|
||||
}, "\n"))
|
||||
|
||||
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||
ApiUrl: fApiUrl,
|
||||
ApiRole: "user",
|
||||
AccessKeyId: fAccessKeyId,
|
||||
AccessKey: fAccessKey,
|
||||
AllowInsecureConnections: true,
|
||||
ResourceType: provider.RESOURCE_TYPE_CERTIFICATE,
|
||||
CertificateId: fCertificateId,
|
||||
})
|
||||
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)
|
||||
})
|
||||
}
|
||||
@@ -19,6 +19,7 @@ type DeployerConfig struct {
|
||||
// GoEdge URL。
|
||||
ApiUrl string `json:"apiUrl"`
|
||||
// GoEdge 用户角色。
|
||||
// 可取值 "user"、"admin"。
|
||||
ApiRole string `json:"apiRole"`
|
||||
// GoEdge AccessKeyId。
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
|
||||
@@ -17,7 +17,7 @@ var (
|
||||
fApiUrl string
|
||||
fAccessKeyId string
|
||||
fAccessKey string
|
||||
fCertificateId int
|
||||
fCertificateId int64
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -28,7 +28,7 @@ func init() {
|
||||
flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "")
|
||||
flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "")
|
||||
flag.StringVar(&fAccessKey, argsPrefix+"ACCESSKEY", "", "")
|
||||
flag.IntVar(&fCertificateId, argsPrefix+"CERTIFICATEID", 0, "")
|
||||
flag.Int64Var(&fCertificateId, argsPrefix+"CERTIFICATEID", 0, "")
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -45,7 +45,7 @@ Shell command to run this test:
|
||||
func TestDeploy(t *testing.T) {
|
||||
flag.Parse()
|
||||
|
||||
t.Run("Deploy", func(t *testing.T) {
|
||||
t.Run("Deploy_ToCertificate", func(t *testing.T) {
|
||||
t.Log(strings.Join([]string{
|
||||
"args:",
|
||||
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||
@@ -58,11 +58,12 @@ func TestDeploy(t *testing.T) {
|
||||
|
||||
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||
ApiUrl: fApiUrl,
|
||||
ApiRole: "user",
|
||||
AccessKeyId: fAccessKeyId,
|
||||
AccessKey: fAccessKey,
|
||||
AllowInsecureConnections: true,
|
||||
ResourceType: provider.RESOURCE_TYPE_CERTIFICATE,
|
||||
CertificateId: int64(fCertificateId),
|
||||
CertificateId: fCertificateId,
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("err: %+v", err)
|
||||
|
||||
@@ -210,7 +210,6 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, certPEM str
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
|
||||
default:
|
||||
if err := d.modifyListenerCertificate(ctx, listenerId, upres.CertId); err != nil {
|
||||
errs = append(errs, err)
|
||||
|
||||
8
internal/pkg/core/deployer/providers/lecdn/consts.go
Normal file
8
internal/pkg/core/deployer/providers/lecdn/consts.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package lecdn
|
||||
|
||||
type ResourceType string
|
||||
|
||||
const (
|
||||
// 资源类型:替换指定证书。
|
||||
RESOURCE_TYPE_CERTIFICATE = ResourceType("certificate")
|
||||
)
|
||||
176
internal/pkg/core/deployer/providers/lecdn/lecdn.go
Normal file
176
internal/pkg/core/deployer/providers/lecdn/lecdn.go
Normal file
@@ -0,0 +1,176 @@
|
||||
package lecdn
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||
leclientsdkv3 "github.com/usual2970/certimate/internal/pkg/sdk3rd/lecdn/v3/client"
|
||||
lemastersdkv3 "github.com/usual2970/certimate/internal/pkg/sdk3rd/lecdn/v3/master"
|
||||
)
|
||||
|
||||
type DeployerConfig struct {
|
||||
// LeCDN URL。
|
||||
ApiUrl string `json:"apiUrl"`
|
||||
// LeCDN 版本。
|
||||
// 可取值 "v3"。
|
||||
ApiVersion string `json:"apiVersion"`
|
||||
// LeCDN 用户角色。
|
||||
// 可取值 "client"、"master"。
|
||||
ApiRole string `json:"apiRole"`
|
||||
// LeCDN 用户名。
|
||||
Username string `json:"accessKeyId"`
|
||||
// LeCDN 用户密码。
|
||||
Password string `json:"accessKey"`
|
||||
// 是否允许不安全的连接。
|
||||
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||
// 部署资源类型。
|
||||
ResourceType ResourceType `json:"resourceType"`
|
||||
// 证书 ID。
|
||||
// 部署资源类型为 [RESOURCE_TYPE_CERTIFICATE] 时必填。
|
||||
CertificateId int64 `json:"certificateId,omitempty"`
|
||||
// 客户 ID。
|
||||
// 部署资源类型为 [RESOURCE_TYPE_CERTIFICATE] 时选填。
|
||||
ClientId int64 `json:"clientId,omitempty"`
|
||||
}
|
||||
|
||||
type DeployerProvider struct {
|
||||
config *DeployerConfig
|
||||
logger *slog.Logger
|
||||
sdkClient interface{}
|
||||
}
|
||||
|
||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
||||
|
||||
const (
|
||||
apiVersionV3 = "v3"
|
||||
|
||||
apiRoleClient = "client"
|
||||
apiRoleMaster = "master"
|
||||
)
|
||||
|
||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
if config == nil {
|
||||
panic("config is nil")
|
||||
}
|
||||
|
||||
client, err := createSdkClient(config.ApiUrl, config.ApiVersion, config.ApiRole, config.Username, config.Password, config.AllowInsecureConnections)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||
}
|
||||
|
||||
return &DeployerProvider{
|
||||
config: config,
|
||||
logger: slog.Default(),
|
||||
sdkClient: client,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
|
||||
// 根据部署资源类型决定部署方式
|
||||
switch d.config.ResourceType {
|
||||
case RESOURCE_TYPE_CERTIFICATE:
|
||||
if err := d.deployToCertificate(ctx, certPEM, privkeyPEM); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported resource type '%s'", d.config.ResourceType)
|
||||
}
|
||||
|
||||
return &deployer.DeployResult{}, nil
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPEM string, privkeyPEM string) error {
|
||||
if d.config.CertificateId == 0 {
|
||||
return errors.New("config `certificateId` is required")
|
||||
}
|
||||
|
||||
// 修改证书
|
||||
// REF: https://wdk0pwf8ul.feishu.cn/wiki/YE1XwCRIHiLYeKkPupgcXrlgnDd
|
||||
switch sdkClient := d.sdkClient.(type) {
|
||||
case *leclientsdkv3.Client:
|
||||
updateSSLCertReq := &leclientsdkv3.UpdateCertificateRequest{
|
||||
Name: fmt.Sprintf("certimate-%d", time.Now().UnixMilli()),
|
||||
Description: "upload from certimate",
|
||||
Type: "upload",
|
||||
SSLPEM: certPEM,
|
||||
SSLKey: privkeyPEM,
|
||||
AutoRenewal: false,
|
||||
}
|
||||
updateSSLCertResp, err := sdkClient.UpdateCertificate(d.config.CertificateId, updateSSLCertReq)
|
||||
d.logger.Debug("sdk request 'lecdn.UpdateCertificate'", slog.Int64("certId", d.config.CertificateId), slog.Any("request", updateSSLCertReq), slog.Any("response", updateSSLCertResp))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'lecdn.UpdateCertificate': %w", err)
|
||||
}
|
||||
|
||||
case *lemastersdkv3.Client:
|
||||
updateSSLCertReq := &lemastersdkv3.UpdateCertificateRequest{
|
||||
ClientId: d.config.ClientId,
|
||||
Name: fmt.Sprintf("certimate-%d", time.Now().UnixMilli()),
|
||||
Description: "upload from certimate",
|
||||
Type: "upload",
|
||||
SSLPEM: certPEM,
|
||||
SSLKey: privkeyPEM,
|
||||
AutoRenewal: false,
|
||||
}
|
||||
updateSSLCertResp, err := sdkClient.UpdateCertificate(d.config.CertificateId, updateSSLCertReq)
|
||||
d.logger.Debug("sdk request 'lecdn.UpdateCertificate'", slog.Int64("certId", d.config.CertificateId), slog.Any("request", updateSSLCertReq), slog.Any("response", updateSSLCertResp))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'lecdn.UpdateCertificate': %w", err)
|
||||
}
|
||||
|
||||
default:
|
||||
panic("sdk client is not implemented")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createSdkClient(apiUrl, apiVersion, apiRole, username, password string, skipTlsVerify bool) (interface{}, error) {
|
||||
if _, err := url.Parse(apiUrl); err != nil {
|
||||
return nil, errors.New("invalid lecdn api url")
|
||||
}
|
||||
|
||||
if username == "" {
|
||||
return nil, errors.New("invalid lecdn username")
|
||||
}
|
||||
|
||||
if password == "" {
|
||||
return nil, errors.New("invalid lecdn password")
|
||||
}
|
||||
|
||||
if apiVersion == apiVersionV3 && apiRole == apiRoleClient {
|
||||
// v3 版客户端
|
||||
client := leclientsdkv3.NewClient(apiUrl, username, password)
|
||||
if skipTlsVerify {
|
||||
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
|
||||
}
|
||||
|
||||
return client, nil
|
||||
} else if apiVersion == apiVersionV3 && apiRole == apiRoleMaster {
|
||||
// v3 版主控端
|
||||
client := lemastersdkv3.NewClient(apiUrl, username, password)
|
||||
if skipTlsVerify {
|
||||
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("invalid lecdn api version or user role")
|
||||
}
|
||||
87
internal/pkg/core/deployer/providers/lecdn/lecdn_test.go
Normal file
87
internal/pkg/core/deployer/providers/lecdn/lecdn_test.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package lecdn_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/lecdn"
|
||||
)
|
||||
|
||||
var (
|
||||
fInputCertPath string
|
||||
fInputKeyPath string
|
||||
fApiUrl string
|
||||
fApiVersion string
|
||||
fUsername string
|
||||
fPassword string
|
||||
fCertificateId int64
|
||||
)
|
||||
|
||||
func init() {
|
||||
argsPrefix := "CERTIMATE_DEPLOYER_LECDN_"
|
||||
|
||||
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||
flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "")
|
||||
flag.StringVar(&fApiVersion, argsPrefix+"APIVERSION", "v3", "")
|
||||
flag.StringVar(&fUsername, argsPrefix+"USERNAME", "", "")
|
||||
flag.StringVar(&fPassword, argsPrefix+"PASSWORD", "", "")
|
||||
flag.Int64Var(&fCertificateId, argsPrefix+"CERTIFICATEID", 0, "")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -v ./lecdn_test.go -args \
|
||||
--CERTIMATE_DEPLOYER_LECDN_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||
--CERTIMATE_DEPLOYER_LECDN_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||
--CERTIMATE_DEPLOYER_LECDN_APIURL="http://127.0.0.1:5090" \
|
||||
--CERTIMATE_DEPLOYER_LECDN_USERNAME="your-username" \
|
||||
--CERTIMATE_DEPLOYER_LECDN_PASSWORD="your-password" \
|
||||
--CERTIMATE_DEPLOYER_LECDN_CERTIFICATEID="your-cerficiate-id"
|
||||
*/
|
||||
func TestDeploy(t *testing.T) {
|
||||
flag.Parse()
|
||||
|
||||
t.Run("Deploy_ToCertificate", func(t *testing.T) {
|
||||
t.Log(strings.Join([]string{
|
||||
"args:",
|
||||
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
||||
fmt.Sprintf("APIURL: %v", fApiUrl),
|
||||
fmt.Sprintf("APIVERSION: %v", fApiVersion),
|
||||
fmt.Sprintf("USERNAME: %v", fUsername),
|
||||
fmt.Sprintf("PASSWORD: %v", fPassword),
|
||||
fmt.Sprintf("CERTIFICATEID: %v", fCertificateId),
|
||||
}, "\n"))
|
||||
|
||||
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||
ApiUrl: fApiUrl,
|
||||
ApiVersion: fApiVersion,
|
||||
ApiRole: "user",
|
||||
Username: fUsername,
|
||||
Password: fPassword,
|
||||
AllowInsecureConnections: true,
|
||||
ResourceType: provider.RESOURCE_TYPE_CERTIFICATE,
|
||||
CertificateId: fCertificateId,
|
||||
})
|
||||
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)
|
||||
})
|
||||
}
|
||||
@@ -15,8 +15,8 @@ import (
|
||||
type DeployerConfig struct {
|
||||
// 耗子面板地址。
|
||||
ApiUrl string `json:"apiUrl"`
|
||||
// 耗子面板访问令牌ID。
|
||||
AccessTokenId uint `json:"accessTokenId"`
|
||||
// 耗子面板访问令牌 ID。
|
||||
AccessTokenId int32 `json:"accessTokenId"`
|
||||
// 耗子面板访问令牌。
|
||||
AccessToken string `json:"accessToken"`
|
||||
// 是否允许不安全的连接。
|
||||
@@ -64,15 +64,15 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
||||
PrivateKey: privkeyPEM,
|
||||
}
|
||||
settingCertResp, err := d.sdkClient.SettingCert(settingCertReq)
|
||||
d.logger.Debug("sdk request 'ratpanel.SettingCertRequest'", slog.Any("request", settingCertReq), slog.Any("response", settingCertResp))
|
||||
d.logger.Debug("sdk request 'ratpanel.SettingCert'", slog.Any("request", settingCertReq), slog.Any("response", settingCertResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'ratpanel.SettingCertRequest': %w", err)
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'ratpanel.SettingCert': %w", err)
|
||||
}
|
||||
|
||||
return &deployer.DeployResult{}, nil
|
||||
}
|
||||
|
||||
func createSdkClient(apiUrl string, accessTokenId uint, accessToken string, skipTlsVerify bool) (*rpsdk.Client, error) {
|
||||
func createSdkClient(apiUrl string, accessTokenId int32, accessToken string, skipTlsVerify bool) (*rpsdk.Client, error) {
|
||||
if _, err := url.Parse(apiUrl); err != nil {
|
||||
return nil, errors.New("invalid ratpanel api url")
|
||||
}
|
||||
@@ -80,6 +80,7 @@ func createSdkClient(apiUrl string, accessTokenId uint, accessToken string, skip
|
||||
if accessTokenId == 0 {
|
||||
return nil, errors.New("invalid ratpanel access token id")
|
||||
}
|
||||
|
||||
if accessToken == "" {
|
||||
return nil, errors.New("invalid ratpanel access token")
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@ var (
|
||||
fInputCertPath string
|
||||
fInputKeyPath string
|
||||
fApiUrl string
|
||||
fTokenId uint
|
||||
fToken string
|
||||
fAccessTokenId int64
|
||||
fAccessToken string
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -25,8 +25,8 @@ func init() {
|
||||
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||
flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "")
|
||||
flag.UintVar(&fTokenId, argsPrefix+"TOKENID", 0, "")
|
||||
flag.StringVar(&fToken, argsPrefix+"TOKEN", "", "")
|
||||
flag.Int64Var(&fAccessTokenId, argsPrefix+"ACCESSTOKENID", 0, "")
|
||||
flag.StringVar(&fAccessToken, argsPrefix+"ACCESSTOKEN", "", "")
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -36,8 +36,8 @@ Shell command to run this test:
|
||||
--CERTIMATE_DEPLOYER_RATPANELCONSOLE_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||
--CERTIMATE_DEPLOYER_RATPANELCONSOLE_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||
--CERTIMATE_DEPLOYER_RATPANELCONSOLE_APIURL="http://127.0.0.1:8888" \
|
||||
--CERTIMATE_DEPLOYER_RATPANELCONSOLE_TOKENID=your-access-token-id \
|
||||
--CERTIMATE_DEPLOYER_RATPANELCONSOLE_TOKEN="your-access-token"
|
||||
--CERTIMATE_DEPLOYER_RATPANELCONSOLE_ACCESSTOKENID="your-access-token-id" \
|
||||
--CERTIMATE_DEPLOYER_RATPANELCONSOLE_ACCESSTOKEN="your-access-token"
|
||||
*/
|
||||
func TestDeploy(t *testing.T) {
|
||||
flag.Parse()
|
||||
@@ -48,14 +48,14 @@ func TestDeploy(t *testing.T) {
|
||||
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
||||
fmt.Sprintf("APIURL: %v", fApiUrl),
|
||||
fmt.Sprintf("TOKENID: %v", fTokenId),
|
||||
fmt.Sprintf("TOKEN: %v", fToken),
|
||||
fmt.Sprintf("ACCESSTOKENID: %v", fAccessTokenId),
|
||||
fmt.Sprintf("ACCESSTOKEN: %v", fAccessToken),
|
||||
}, "\n"))
|
||||
|
||||
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||
ApiUrl: fApiUrl,
|
||||
AccessTokenId: fTokenId,
|
||||
AccessToken: fToken,
|
||||
AccessTokenId: int32(fAccessTokenId),
|
||||
AccessToken: fAccessToken,
|
||||
AllowInsecureConnections: true,
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -15,14 +15,14 @@ import (
|
||||
type DeployerConfig struct {
|
||||
// 耗子面板地址。
|
||||
ApiUrl string `json:"apiUrl"`
|
||||
// 耗子面板访问令牌ID。
|
||||
AccessTokenId uint `json:"accessTokenId"`
|
||||
// 耗子面板访问令牌 ID。
|
||||
AccessTokenId int32 `json:"accessTokenId"`
|
||||
// 耗子面板访问令牌。
|
||||
AccessToken string `json:"accessToken"`
|
||||
// 是否允许不安全的连接。
|
||||
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||
// 网站名称。
|
||||
SiteName string `json:"siteName,omitempty"`
|
||||
SiteName string `json:"siteName"`
|
||||
}
|
||||
|
||||
type DeployerProvider struct {
|
||||
@@ -71,15 +71,15 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
||||
PrivateKey: privkeyPEM,
|
||||
}
|
||||
websiteCertResp, err := d.sdkClient.WebsiteCert(websiteCertReq)
|
||||
d.logger.Debug("sdk request 'ratpanel.WebsiteCertRequest'", slog.Any("request", websiteCertReq), slog.Any("response", websiteCertResp))
|
||||
d.logger.Debug("sdk request 'ratpanel.WebsiteCert'", slog.Any("request", websiteCertReq), slog.Any("response", websiteCertResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'ratpanel.WebsiteCertRequest': %w", err)
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'ratpanel.WebsiteCert': %w", err)
|
||||
}
|
||||
|
||||
return &deployer.DeployResult{}, nil
|
||||
}
|
||||
|
||||
func createSdkClient(apiUrl string, accessTokenId uint, accessToken string, skipTlsVerify bool) (*rpsdk.Client, error) {
|
||||
func createSdkClient(apiUrl string, accessTokenId int32, accessToken string, skipTlsVerify bool) (*rpsdk.Client, error) {
|
||||
if _, err := url.Parse(apiUrl); err != nil {
|
||||
return nil, errors.New("invalid ratpanel api url")
|
||||
}
|
||||
@@ -87,6 +87,7 @@ func createSdkClient(apiUrl string, accessTokenId uint, accessToken string, skip
|
||||
if accessTokenId == 0 {
|
||||
return nil, errors.New("invalid ratpanel access token id")
|
||||
}
|
||||
|
||||
if accessToken == "" {
|
||||
return nil, errors.New("invalid ratpanel access token")
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@ var (
|
||||
fInputCertPath string
|
||||
fInputKeyPath string
|
||||
fApiUrl string
|
||||
fTokenId uint
|
||||
fToken string
|
||||
fAccessTokenId int64
|
||||
fAccessToken string
|
||||
fSiteName string
|
||||
)
|
||||
|
||||
@@ -26,8 +26,8 @@ func init() {
|
||||
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||
flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "")
|
||||
flag.UintVar(&fTokenId, argsPrefix+"TOKENID", 0, "")
|
||||
flag.StringVar(&fToken, argsPrefix+"TOKEN", "", "")
|
||||
flag.Int64Var(&fAccessTokenId, argsPrefix+"ACCESSTOKENID", 0, "")
|
||||
flag.StringVar(&fAccessToken, argsPrefix+"ACCESSTOKEN", "", "")
|
||||
flag.StringVar(&fSiteName, argsPrefix+"SITENAME", "", "")
|
||||
}
|
||||
|
||||
@@ -38,8 +38,8 @@ Shell command to run this test:
|
||||
--CERTIMATE_DEPLOYER_RATPANELSITE_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||
--CERTIMATE_DEPLOYER_RATPANELSITE_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||
--CERTIMATE_DEPLOYER_RATPANELSITE_APIURL="http://127.0.0.1:8888" \
|
||||
--CERTIMATE_DEPLOYER_RATPANELSITE_TOKENID=your-access-token-id \
|
||||
--CERTIMATE_DEPLOYER_RATPANELSITE_TOKEN="your-access-token" \
|
||||
--CERTIMATE_DEPLOYER_RATPANELSITE_ACCESSTOKENID="your-access-token-id" \
|
||||
--CERTIMATE_DEPLOYER_RATPANELSITE_ACCESSTOKEN="your-access-token" \
|
||||
--CERTIMATE_DEPLOYER_RATPANELSITE_SITENAME="your-site-name"
|
||||
*/
|
||||
func TestDeploy(t *testing.T) {
|
||||
@@ -51,15 +51,15 @@ func TestDeploy(t *testing.T) {
|
||||
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
||||
fmt.Sprintf("APIURL: %v", fApiUrl),
|
||||
fmt.Sprintf("TOKENID: %v", fTokenId),
|
||||
fmt.Sprintf("TOKEN: %v", fToken),
|
||||
fmt.Sprintf("ACCESSTOKENID: %v", fAccessTokenId),
|
||||
fmt.Sprintf("ACCESSTOKEN: %v", fAccessToken),
|
||||
fmt.Sprintf("SITENAME: %v", fSiteName),
|
||||
}, "\n"))
|
||||
|
||||
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||
ApiUrl: fApiUrl,
|
||||
AccessTokenId: fTokenId,
|
||||
AccessToken: fToken,
|
||||
AccessTokenId: int32(fAccessTokenId),
|
||||
AccessToken: fAccessToken,
|
||||
AllowInsecureConnections: true,
|
||||
SiteName: fSiteName,
|
||||
})
|
||||
|
||||
@@ -16,7 +16,7 @@ var (
|
||||
fInputKeyPath string
|
||||
fApiUrl string
|
||||
fApiToken string
|
||||
fCertificateId int
|
||||
fCertificateId int64
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -26,7 +26,7 @@ func init() {
|
||||
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||
flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "")
|
||||
flag.StringVar(&fApiToken, argsPrefix+"APITOKEN", "", "")
|
||||
flag.IntVar(&fCertificateId, argsPrefix+"CERTIFICATEID", 0, "")
|
||||
flag.Int64Var(&fCertificateId, argsPrefix+"CERTIFICATEID", 0, "")
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -15,7 +15,7 @@ var (
|
||||
fInputCertPath string
|
||||
fInputKeyPath string
|
||||
fSshHost string
|
||||
fSshPort int
|
||||
fSshPort int64
|
||||
fSshUsername string
|
||||
fSshPassword string
|
||||
fOutputCertPath string
|
||||
@@ -28,7 +28,7 @@ func init() {
|
||||
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||
flag.StringVar(&fSshHost, argsPrefix+"SSHHOST", "", "")
|
||||
flag.IntVar(&fSshPort, argsPrefix+"SSHPORT", 0, "")
|
||||
flag.Int64Var(&fSshPort, argsPrefix+"SSHPORT", 0, "")
|
||||
flag.StringVar(&fSshUsername, argsPrefix+"SSHUSERNAME", "", "")
|
||||
flag.StringVar(&fSshPassword, argsPrefix+"SSHPASSWORD", "", "")
|
||||
flag.StringVar(&fOutputCertPath, argsPrefix+"OUTPUTCERTPATH", "", "")
|
||||
|
||||
104
internal/pkg/core/deployer/providers/wangsu-cdn/wangsu_cdn.go
Normal file
104
internal/pkg/core/deployer/providers/wangsu-cdn/wangsu_cdn.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package wangsucdn
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strconv"
|
||||
|
||||
"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/wangsu-certificate"
|
||||
wangsusdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/wangsu/cdn"
|
||||
)
|
||||
|
||||
type DeployerConfig struct {
|
||||
// 网宿云 AccessKeyId。
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 网宿云 AccessKeySecret。
|
||||
AccessKeySecret string `json:"accessKeySecret"`
|
||||
// 加速域名数组。
|
||||
Domains []string `json:"domains"`
|
||||
}
|
||||
|
||||
type DeployerProvider struct {
|
||||
config *DeployerConfig
|
||||
logger *slog.Logger
|
||||
sdkClient *wangsusdk.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.AccessKeySecret)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||
}
|
||||
|
||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||
AccessKeyId: config.AccessKeyId,
|
||||
AccessKeySecret: config.AccessKeySecret,
|
||||
})
|
||||
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.Default()
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
|
||||
// 上传证书到证书管理
|
||||
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))
|
||||
}
|
||||
|
||||
// 批量修改域名证书配置
|
||||
// REF: https://www.wangsu.com/document/api-doc/37447
|
||||
certId, _ := strconv.ParseInt(upres.CertId, 10, 64)
|
||||
batchUpdateCertificateConfigReq := &wangsusdk.BatchUpdateCertificateConfigRequest{
|
||||
CertificateId: certId,
|
||||
DomainNames: d.config.Domains,
|
||||
}
|
||||
batchUpdateCertificateConfigResp, err := d.sdkClient.BatchUpdateCertificateConfig(batchUpdateCertificateConfigReq)
|
||||
d.logger.Debug("sdk request 'cdn.BatchUpdateCertificateConfig'", slog.Any("request", batchUpdateCertificateConfigReq), slog.Any("response", batchUpdateCertificateConfigResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'cdn.BatchUpdateCertificateConfig': %w", err)
|
||||
}
|
||||
|
||||
return &deployer.DeployResult{}, nil
|
||||
}
|
||||
|
||||
func createSdkClient(accessKeyId, accessKeySecret string) (*wangsusdk.Client, error) {
|
||||
if accessKeyId == "" {
|
||||
return nil, errors.New("invalid wangsu access key id")
|
||||
}
|
||||
|
||||
if accessKeySecret == "" {
|
||||
return nil, errors.New("invalid wangsu access key secret")
|
||||
}
|
||||
|
||||
return wangsusdk.NewClient(accessKeyId, accessKeySecret), nil
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package wangsucdn_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/wangsu-cdn"
|
||||
)
|
||||
|
||||
var (
|
||||
fInputCertPath string
|
||||
fInputKeyPath string
|
||||
fAccessKeyId string
|
||||
fAccessKeySecret string
|
||||
fDomain string
|
||||
)
|
||||
|
||||
func init() {
|
||||
argsPrefix := "CERTIMATE_DEPLOYER_WANGSUCDN_"
|
||||
|
||||
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||
flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "")
|
||||
flag.StringVar(&fAccessKeySecret, argsPrefix+"ACCESSKEYSECRET", "", "")
|
||||
flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -v ./wangsu_cdn_test.go -args \
|
||||
--CERTIMATE_DEPLOYER_WANGSUCDN_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||
--CERTIMATE_DEPLOYER_WANGSUCDN_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||
--CERTIMATE_DEPLOYER_WANGSUCDN_ACCESSKEYID="your-access-key-id" \
|
||||
--CERTIMATE_DEPLOYER_WANGSUCDN_ACCESSKEYSECRET="your-access-key-secret" \
|
||||
--CERTIMATE_DEPLOYER_WANGSUCDN_DOMAIN="example.com"
|
||||
*/
|
||||
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("ACCESSKEYSECRET: %v", fAccessKeySecret),
|
||||
fmt.Sprintf("DOMAIN: %v", fDomain),
|
||||
}, "\n"))
|
||||
|
||||
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||
AccessKeyId: fAccessKeyId,
|
||||
AccessKeySecret: fAccessKeySecret,
|
||||
Domains: []string{fDomain},
|
||||
})
|
||||
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)
|
||||
})
|
||||
}
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||
wangsucdn "github.com/usual2970/certimate/internal/pkg/sdk3rd/wangsu/cdn"
|
||||
wangsucdn "github.com/usual2970/certimate/internal/pkg/sdk3rd/wangsu/cdnpro"
|
||||
certutil "github.com/usual2970/certimate/internal/pkg/utils/cert"
|
||||
typeutil "github.com/usual2970/certimate/internal/pkg/utils/type"
|
||||
)
|
||||
@@ -88,9 +88,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
||||
|
||||
// 查询已部署加速域名的详情
|
||||
getHostnameDetailResp, err := d.sdkClient.GetHostnameDetail(d.config.Domain)
|
||||
d.logger.Debug("sdk request 'cdn.GetHostnameDetail'", slog.String("hostname", d.config.Domain), slog.Any("response", getHostnameDetailResp))
|
||||
d.logger.Debug("sdk request 'cdnpro.GetHostnameDetail'", slog.String("hostname", d.config.Domain), slog.Any("response", getHostnameDetailResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'cdn.GetHostnameDetail': %w", err)
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'cdnpro.GetHostnameDetail': %w", err)
|
||||
}
|
||||
|
||||
// 生成网宿云证书参数
|
||||
@@ -126,9 +126,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
||||
NewVersion: certificateNewVersionInfo,
|
||||
}
|
||||
createCertificateResp, err := d.sdkClient.CreateCertificate(createCertificateReq)
|
||||
d.logger.Debug("sdk request 'cdn.CreateCertificate'", slog.Any("request", createCertificateReq), slog.Any("response", createCertificateResp))
|
||||
d.logger.Debug("sdk request 'cdnpro.CreateCertificate'", slog.Any("request", createCertificateReq), slog.Any("response", createCertificateResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'cdn.CreateCertificate': %w", err)
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'cdnpro.CreateCertificate': %w", err)
|
||||
}
|
||||
|
||||
wangsuCertUrl = createCertificateResp.CertificateUrl
|
||||
@@ -149,9 +149,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
||||
NewVersion: certificateNewVersionInfo,
|
||||
}
|
||||
updateCertificateResp, err := d.sdkClient.UpdateCertificate(d.config.CertificateId, updateCertificateReq)
|
||||
d.logger.Debug("sdk request 'cdn.CreateCertificate'", slog.Any("certificateId", d.config.CertificateId), slog.Any("request", updateCertificateReq), slog.Any("response", updateCertificateResp))
|
||||
d.logger.Debug("sdk request 'cdnpro.CreateCertificate'", slog.Any("certificateId", d.config.CertificateId), slog.Any("request", updateCertificateReq), slog.Any("response", updateCertificateResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'cdn.UpdateCertificate': %w", err)
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'cdnpro.UpdateCertificate': %w", err)
|
||||
}
|
||||
|
||||
wangsuCertUrl = updateCertificateResp.CertificateUrl
|
||||
@@ -186,9 +186,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
||||
createDeploymentTaskReq.Webhook = typeutil.ToPtr(d.config.WebhookId)
|
||||
}
|
||||
createDeploymentTaskResp, err := d.sdkClient.CreateDeploymentTask(createDeploymentTaskReq)
|
||||
d.logger.Debug("sdk request 'cdn.CreateCertificate'", slog.Any("request", createDeploymentTaskReq), slog.Any("response", createDeploymentTaskResp))
|
||||
d.logger.Debug("sdk request 'cdnpro.CreateCertificate'", slog.Any("request", createDeploymentTaskReq), slog.Any("response", createDeploymentTaskResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'cdn.CreateDeploymentTask': %w", err)
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'cdnpro.CreateDeploymentTask': %w", err)
|
||||
}
|
||||
|
||||
// 循环获取部署任务详细信息,等待任务状态变更
|
||||
@@ -206,9 +206,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
||||
}
|
||||
|
||||
getDeploymentTaskDetailResp, err := d.sdkClient.GetDeploymentTaskDetail(wangsuTaskId)
|
||||
d.logger.Info("sdk request 'cdn.GetDeploymentTaskDetail'", slog.Any("taskId", wangsuTaskId), slog.Any("response", getDeploymentTaskDetailResp))
|
||||
d.logger.Info("sdk request 'cdnpro.GetDeploymentTaskDetail'", slog.Any("taskId", wangsuTaskId), slog.Any("response", getDeploymentTaskDetailResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'cdn.GetDeploymentTaskDetail': %w", err)
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'cdnpro.GetDeploymentTaskDetail': %w", err)
|
||||
}
|
||||
|
||||
if getDeploymentTaskDetailResp.Status == "failed" {
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
package wangsucertificate
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
"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/wangsu-certificate"
|
||||
wangsusdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/wangsu/certificate"
|
||||
typeutil "github.com/usual2970/certimate/internal/pkg/utils/type"
|
||||
)
|
||||
|
||||
type DeployerConfig struct {
|
||||
// 网宿云 AccessKeyId。
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 网宿云 AccessKeySecret。
|
||||
AccessKeySecret string `json:"accessKeySecret"`
|
||||
// 证书 ID。
|
||||
// 选填。零值时表示新建证书;否则表示更新证书。
|
||||
CertificateId string `json:"certificateId,omitempty"`
|
||||
}
|
||||
|
||||
type DeployerProvider struct {
|
||||
config *DeployerConfig
|
||||
logger *slog.Logger
|
||||
sdkClient *wangsusdk.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.AccessKeySecret)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||
}
|
||||
|
||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||
AccessKeyId: config.AccessKeyId,
|
||||
AccessKeySecret: config.AccessKeySecret,
|
||||
})
|
||||
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.Default()
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
|
||||
if d.config.CertificateId == "" {
|
||||
// 上传证书到证书管理
|
||||
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))
|
||||
}
|
||||
} else {
|
||||
// 修改证书
|
||||
// REF: https://www.wangsu.com/document/api-doc/25568?productCode=certificatemanagement
|
||||
updateCertificateReq := &wangsusdk.UpdateCertificateRequest{
|
||||
Name: typeutil.ToPtr(fmt.Sprintf("certimate_%d", time.Now().UnixMilli())),
|
||||
Certificate: typeutil.ToPtr(certPEM),
|
||||
PrivateKey: typeutil.ToPtr(privkeyPEM),
|
||||
Comment: typeutil.ToPtr("upload from certimate"),
|
||||
}
|
||||
updateCertificateResp, err := d.sdkClient.UpdateCertificate(d.config.CertificateId, updateCertificateReq)
|
||||
d.logger.Debug("sdk request 'certificatemanagement.UpdateCertificate'", slog.Any("request", updateCertificateReq), slog.Any("response", updateCertificateResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'certificatemanagement.CreateCertificate': %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return &deployer.DeployResult{}, nil
|
||||
}
|
||||
|
||||
func createSdkClient(accessKeyId, accessKeySecret string) (*wangsusdk.Client, error) {
|
||||
if accessKeyId == "" {
|
||||
return nil, errors.New("invalid wangsu access key id")
|
||||
}
|
||||
|
||||
if accessKeySecret == "" {
|
||||
return nil, errors.New("invalid wangsu access key secret")
|
||||
}
|
||||
|
||||
return wangsusdk.NewClient(accessKeyId, accessKeySecret), nil
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package wangsucertificate_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/wangsu-certificate"
|
||||
)
|
||||
|
||||
var (
|
||||
fInputCertPath string
|
||||
fInputKeyPath string
|
||||
fAccessKeyId string
|
||||
fAccessKeySecret string
|
||||
fCertificateId string
|
||||
)
|
||||
|
||||
func init() {
|
||||
argsPrefix := "CERTIMATE_DEPLOYER_WANGSUCERTIFICATE_"
|
||||
|
||||
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||
flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "")
|
||||
flag.StringVar(&fAccessKeySecret, argsPrefix+"ACCESSKEYSECRET", "", "")
|
||||
flag.StringVar(&fCertificateId, argsPrefix+"CERTIFICATEID", "", "")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -v ./wangsu_certificate_test.go -args \
|
||||
--CERTIMATE_DEPLOYER_WANGSUCERTIFICATE_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||
--CERTIMATE_DEPLOYER_WANGSUCERTIFICATE_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||
--CERTIMATE_DEPLOYER_WANGSUCERTIFICATE_ACCESSKEYID="your-access-key-id" \
|
||||
--CERTIMATE_DEPLOYER_WANGSUCERTIFICATE_ACCESSKEYSECRET="your-access-key-secret" \
|
||||
--CERTIMATE_DEPLOYER_WANGSUCERTIFICATE_CERTIFICATEID="your-certificate-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("ACCESSKEYSECRET: %v", fAccessKeySecret),
|
||||
fmt.Sprintf("CERTIFICATEID: %v", fCertificateId),
|
||||
}, "\n"))
|
||||
|
||||
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||
AccessKeyId: fAccessKeyId,
|
||||
AccessKeySecret: fAccessKeySecret,
|
||||
CertificateId: fCertificateId,
|
||||
})
|
||||
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)
|
||||
})
|
||||
}
|
||||
@@ -176,7 +176,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
||||
}
|
||||
|
||||
// 发送请求
|
||||
resp, err := req.SetDebug(true).Send()
|
||||
resp, err := req.Send()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to send webhook request: %w", err)
|
||||
} else if resp.IsError() {
|
||||
|
||||
Reference in New Issue
Block a user