diff --git a/pkg/core/deployer/providers/baotapanel/baotapanel.go b/pkg/core/deployer/providers/baotapanel/baotapanel.go index bec99eb5..6c40acaf 100644 --- a/pkg/core/deployer/providers/baotapanel/baotapanel.go +++ b/pkg/core/deployer/providers/baotapanel/baotapanel.go @@ -76,30 +76,12 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*Dep switch d.config.SiteType { case "any": { - // 上传证书 - sslCertSaveCertReq := &btpanelsdk.SSLCertSaveCertRequest{ - Certificate: certPEM, - PrivateKey: privkeyPEM, - } - sslCertSaveCertResp, err := d.sdkClient.SSLCertSaveCertWithContext(ctx, sslCertSaveCertReq) - d.logger.Debug("sdk request 'ssl.cert.SaveCert'", slog.Any("request", sslCertSaveCertReq), slog.Any("response", sslCertSaveCertResp)) - if err != nil { - return nil, fmt.Errorf("failed to execute sdk request 'ssl.cert.SaveCert': %w", err) - } - - // 设置站点证书 - sslSetBatchCertToSiteReq := &btpanelsdk.SSLSetBatchCertToSiteRequest{ - BatchInfo: lo.Map(d.config.SiteNames, func(siteName string, _ int) *btpanelsdk.SSLSetBatchCertToSiteRequestBatchInfo { - return &btpanelsdk.SSLSetBatchCertToSiteRequestBatchInfo{ - SiteName: siteName, - SSLHash: sslCertSaveCertResp.SSLHash, - } - }), - } - sslSetBatchCertToSiteResp, err := d.sdkClient.SSLSetBatchCertToSiteWithContext(ctx, sslSetBatchCertToSiteReq) - d.logger.Debug("sdk request 'ssl.SetBatchCertToSite'", slog.Any("request", sslSetBatchCertToSiteReq), slog.Any("response", sslSetBatchCertToSiteResp)) - if err != nil { - return nil, fmt.Errorf("failed to execute sdk request 'ssl.SetBatchCertToSite': %w", err) + // 批量更新站点证书 + // 注意,如果 v1 接口不可用,则尝试使用 v2 接口重试 + if err1 := d.updateSitesCertificateByAny(ctx, d.config.SiteNames, certPEM, privkeyPEM); err1 != nil { + if err2 := d.updateSitesCertificateByAnyV2(ctx, d.config.SiteNames, certPEM, privkeyPEM); err2 != nil { + return nil, errors.Join(err1, err2) + } } } @@ -171,6 +153,63 @@ func (d *Deployer) updateSiteCertificate(ctx context.Context, siteType, siteName return nil } +func (d *Deployer) updateSitesCertificateByAny(ctx context.Context, siteNames []string, certPEM, privkeyPEM string) error { + // 上传证书 + sslCertSaveCertReq := &btpanelsdk.SSLCertSaveCertRequest{ + Certificate: certPEM, + PrivateKey: privkeyPEM, + } + sslCertSaveCertResp, err := d.sdkClient.SSLCertSaveCertWithContext(ctx, sslCertSaveCertReq) + d.logger.Debug("sdk request 'ssl.cert.SaveCert'", slog.Any("request", sslCertSaveCertReq), slog.Any("response", sslCertSaveCertResp)) + if err != nil { + return fmt.Errorf("failed to execute sdk request 'ssl.cert.SaveCert': %w", err) + } + + // 设置站点证书 + sslSetBatchCertToSiteReq := &btpanelsdk.SSLSetBatchCertToSiteRequest{ + BatchInfo: lo.Map(siteNames, func(siteName string, _ int) *btpanelsdk.SSLSetBatchCertToSiteRequestBatchInfo { + return &btpanelsdk.SSLSetBatchCertToSiteRequestBatchInfo{ + SiteName: siteName, + SSLHash: sslCertSaveCertResp.SSLHash, + } + }), + } + sslSetBatchCertToSiteResp, err := d.sdkClient.SSLSetBatchCertToSiteWithContext(ctx, sslSetBatchCertToSiteReq) + d.logger.Debug("sdk request 'ssl.SetBatchCertToSite'", slog.Any("request", sslSetBatchCertToSiteReq), slog.Any("response", sslSetBatchCertToSiteResp)) + if err != nil { + return fmt.Errorf("failed to execute sdk request 'ssl.SetBatchCertToSite': %w", err) + } + + return nil +} + +func (d *Deployer) updateSitesCertificateByAnyV2(ctx context.Context, siteNames []string, certPEM, privkeyPEM string) error { + // 上传证书 + sslDomainUploadCertV2Req := &btpanelsdk.SSLDomainUploadCertV2Request{ + Certificate: certPEM, + PrivateKey: privkeyPEM, + } + sslDomainUploadCertV2Resp, err := d.sdkClient.SSLDomainUploadCertV2WithContext(ctx, sslDomainUploadCertV2Req) + d.logger.Debug("sdk request 'v2.ssldomain.UploadCert'", slog.Any("request", sslDomainUploadCertV2Req), slog.Any("response", sslDomainUploadCertV2Resp)) + if err != nil { + return fmt.Errorf("failed to execute sdk request 'v2.ssldomain.UploadCert': %w", err) + } + + // 设置站点证书 + sslDomainCertDeploySitesV2Req := &btpanelsdk.SSLDomainCertDeploySitesV2Request{ + SSLHash: sslDomainUploadCertV2Resp.Message.SSLHash, + Domains: siteNames, + Append: 1, + } + sslDomainCertDeploySitesV2Resp, err := d.sdkClient.SSLDomainCertDeploySitesV2WithContext(ctx, sslDomainCertDeploySitesV2Req) + d.logger.Debug("sdk request 'v2.ssldomain.CertDeploySites'", slog.Any("request", sslDomainCertDeploySitesV2Req), slog.Any("response", sslDomainCertDeploySitesV2Resp)) + if err != nil { + return fmt.Errorf("failed to execute sdk request 'v2.ssldomain.CertDeploySites': %w", err) + } + + return nil +} + func createSDKClient(serverUrl, apiKey string, skipTlsVerify bool) (*btpanelsdk.Client, error) { client, err := btpanelsdk.NewClient(serverUrl, btpanelsdk.WithApiKey(apiKey), diff --git a/pkg/sdk3rd/btpanel/api_ssldomain_cert_deploy_sites_v2.go b/pkg/sdk3rd/btpanel/api_ssldomain_cert_deploy_sites_v2.go new file mode 100644 index 00000000..99a1fdd7 --- /dev/null +++ b/pkg/sdk3rd/btpanel/api_ssldomain_cert_deploy_sites_v2.go @@ -0,0 +1,36 @@ +package btpanel + +import ( + "context" + "net/http" +) + +type SSLDomainCertDeploySitesV2Request struct { + SSLHash string `json:"hash"` + Domains []string `json:"domains"` + Append int32 `json:"append"` +} + +type SSLDomainCertDeploySitesV2Response struct { + sdkResponseBaseV2 +} + +func (c *Client) SSLDomainCertDeploySitesV2(req *SSLDomainCertDeploySitesV2Request) (*SSLDomainCertDeploySitesV2Response, error) { + return c.SSLDomainCertDeploySitesV2WithContext(context.Background(), req) +} + +func (c *Client) SSLDomainCertDeploySitesV2WithContext(ctx context.Context, req *SSLDomainCertDeploySitesV2Request) (*SSLDomainCertDeploySitesV2Response, error) { + httpreq, err := c.newRequest(http.MethodPost, "/v2/ssl_domain?action=cert_deploy_sites", req) + if err != nil { + return nil, err + } else { + httpreq.SetContext(ctx) + } + + result := &SSLDomainCertDeploySitesV2Response{} + if _, err := c.doRequestWithResult(httpreq, result); err != nil { + return result, err + } + + return result, nil +} diff --git a/pkg/sdk3rd/btpanel/api_ssldomain_upload_cert_v2.go b/pkg/sdk3rd/btpanel/api_ssldomain_upload_cert_v2.go new file mode 100644 index 00000000..0ac23752 --- /dev/null +++ b/pkg/sdk3rd/btpanel/api_ssldomain_upload_cert_v2.go @@ -0,0 +1,39 @@ +package btpanel + +import ( + "context" + "net/http" +) + +type SSLDomainUploadCertV2Request struct { + PrivateKey string `json:"key"` + Certificate string `json:"cert"` +} + +type SSLDomainUploadCertV2Response struct { + sdkResponseBaseV2 + + Message *struct { + SSLHash string `json:"hash,omitempty"` + } `json:"message,omitempty"` +} + +func (c *Client) SSLDomainUploadCertV2(req *SSLDomainUploadCertV2Request) (*SSLDomainUploadCertV2Response, error) { + return c.SSLDomainUploadCertV2WithContext(context.Background(), req) +} + +func (c *Client) SSLDomainUploadCertV2WithContext(ctx context.Context, req *SSLDomainUploadCertV2Request) (*SSLDomainUploadCertV2Response, error) { + httpreq, err := c.newRequest(http.MethodPost, "/v2/ssl_domain?action=upload_cert", req) + if err != nil { + return nil, err + } else { + httpreq.SetContext(ctx) + } + + result := &SSLDomainUploadCertV2Response{} + if _, err := c.doRequestWithResult(httpreq, result); err != nil { + return result, err + } + + return result, nil +} diff --git a/pkg/sdk3rd/btpanel/types.go b/pkg/sdk3rd/btpanel/types.go index bf494904..9e5b05d3 100644 --- a/pkg/sdk3rd/btpanel/types.go +++ b/pkg/sdk3rd/btpanel/types.go @@ -17,3 +17,32 @@ func (r *sdkResponseBase) GetStatus() *bool { func (r *sdkResponseBase) GetMessage() *string { return r.Message } + +var _ sdkResponse = (*sdkResponseBase)(nil) + +type sdkResponseBaseV2 struct { + Status *int32 `json:"status,omitempty"` + Timestamp *int64 `json:"timestamp,omitempty"` + Message *struct { + Result *string `json:"result,omitempty"` + } `json:"message,omitempty"` +} + +func (r *sdkResponseBaseV2) GetStatus() *bool { + if r.Status != nil { + status := *r.Status == 0 + return &status + } + + return nil +} + +func (r *sdkResponseBaseV2) GetMessage() *string { + if r.Message != nil { + return r.Message.Result + } + + return nil +} + +var _ sdkResponse = (*sdkResponseBaseV2)(nil) diff --git a/pkg/sdk3rd/btpanelgo/types.go b/pkg/sdk3rd/btpanelgo/types.go index 347f94f1..e60cd65e 100644 --- a/pkg/sdk3rd/btpanelgo/types.go +++ b/pkg/sdk3rd/btpanelgo/types.go @@ -22,3 +22,5 @@ func (r *sdkResponseBase) GetStatus() json.RawMessage { func (r *sdkResponseBase) GetMessage() *string { return r.Message } + +var _ sdkResponse = (*sdkResponseBase)(nil) diff --git a/ui/src/i18n/resources/en/nls.workflow.nodes.json b/ui/src/i18n/resources/en/nls.workflow.nodes.json index d0f20ba4..a9d7991d 100644 --- a/ui/src/i18n/resources/en/nls.workflow.nodes.json +++ b/ui/src/i18n/resources/en/nls.workflow.nodes.json @@ -1173,7 +1173,7 @@ "tooltip": "For more information, see https://cdnx.console.baishan.com/#/cdn/cert" }, "baotapanel": { - "guide": "Requires aaPanel v7.0 or higher." + "guide": "Requires aaPanel v7.0 / BaotaPanel v8.3 or higher." }, "baotapanel_site_type": { "label": "aaPanel website type", @@ -1204,7 +1204,7 @@ "label": "General Project" }, "any": { - "label": "Any Project (aaPanel v7.26+)" + "label": "Any Project (aaPanel v7.26+ / BaotaPanel v9.4+)" } } }, diff --git a/ui/src/i18n/resources/zh/nls.workflow.nodes.json b/ui/src/i18n/resources/zh/nls.workflow.nodes.json index 162cbcbe..e0ce0f54 100644 --- a/ui/src/i18n/resources/zh/nls.workflow.nodes.json +++ b/ui/src/i18n/resources/zh/nls.workflow.nodes.json @@ -1172,7 +1172,7 @@ "tooltip": "这是什么?请参阅 https://cdnx.console.baishan.com/#/cdn/cert" }, "baotapanel": { - "guide": "需要宝塔面板 v8.3 或更高版本。" + "guide": "需要宝塔面板 v8.3 / aaPanel v7.0 或更高版本。" }, "baotapanel_site_type": { "label": "宝塔面板网站类型", @@ -1203,7 +1203,7 @@ "label": "通用项目" }, "any": { - "label": "任意类型(需要宝塔面板 v9.4+)" + "label": "任意类型(需要宝塔面板 v9.4+ / aaPanel v7.26+)" } } },