From 018743299bdf8dabc343c7a19b4c4a95adc259f6 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Fri, 13 Jun 2025 22:31:49 +0800 Subject: [PATCH] feat: new deployment provider: ctcccloud cms --- internal/deployer/providers.go | 10 +- internal/domain/provider.go | 2 +- .../providers/ctcccloud-cms/ctcccloud_cms.go | 67 +++++++ .../ctcccloud-cms/ctcccloud_cms_test.go | 70 +++++++ .../providers/1panel-ssl/1panel_ssl.go | 6 +- .../ctcccloud-ao/ctcccloud_ao_test.go | 4 +- .../ctcccloud-cdn/ctcccloud_cdn_test.go | 4 +- .../providers/ctcccloud-cms/ctcccloud_cms.go | 186 ++++++++++++++++++ .../ctcccloud-cms/ctcccloud_cms_test.go | 72 +++++++ .../ctcccloud-icdn/ctcccloud_icdn_test.go | 4 +- .../rainyun-sslcenter/rainyun_sslcenter.go | 10 +- .../providers/ucloud-ussl/ucloud_ussl.go | 6 +- .../wangsu_certificate_test.go | 4 +- .../pkg/sdk3rd/ctyun/ao/api_create_cert.go | 2 +- .../pkg/sdk3rd/ctyun/ao/api_query_cert.go | 2 +- internal/pkg/sdk3rd/ctyun/ao/client.go | 11 +- internal/pkg/sdk3rd/ctyun/ao/types.go | 2 +- .../pkg/sdk3rd/ctyun/cdn/api_create_cert.go | 2 +- .../sdk3rd/ctyun/cdn/api_query_cert_detail.go | 2 +- internal/pkg/sdk3rd/ctyun/cdn/client.go | 11 +- internal/pkg/sdk3rd/ctyun/cdn/types.go | 2 +- .../ctyun/cms/api_get_certificate_list.go | 44 +++++ .../ctyun/cms/api_upload_certificate.go | 41 ++++ internal/pkg/sdk3rd/ctyun/cms/client.go | 49 +++++ internal/pkg/sdk3rd/ctyun/cms/types.go | 94 +++++++++ .../pkg/sdk3rd/ctyun/icdn/api_create_cert.go | 2 +- .../ctyun/icdn/api_query_cert_detail.go | 2 +- internal/pkg/sdk3rd/ctyun/icdn/client.go | 11 +- internal/pkg/sdk3rd/ctyun/icdn/types.go | 2 +- ui/src/domain/provider.ts | 2 + 30 files changed, 694 insertions(+), 32 deletions(-) create mode 100644 internal/pkg/core/deployer/providers/ctcccloud-cms/ctcccloud_cms.go create mode 100644 internal/pkg/core/deployer/providers/ctcccloud-cms/ctcccloud_cms_test.go create mode 100644 internal/pkg/core/uploader/providers/ctcccloud-cms/ctcccloud_cms.go create mode 100644 internal/pkg/core/uploader/providers/ctcccloud-cms/ctcccloud_cms_test.go create mode 100644 internal/pkg/sdk3rd/ctyun/cms/api_get_certificate_list.go create mode 100644 internal/pkg/sdk3rd/ctyun/cms/api_upload_certificate.go create mode 100644 internal/pkg/sdk3rd/ctyun/cms/client.go create mode 100644 internal/pkg/sdk3rd/ctyun/cms/types.go diff --git a/internal/deployer/providers.go b/internal/deployer/providers.go index 2a7f368d..fd668ace 100644 --- a/internal/deployer/providers.go +++ b/internal/deployer/providers.go @@ -45,6 +45,7 @@ import ( pCdnfly "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/cdnfly" pCTCCCloudAO "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ctcccloud-ao" pCTCCCloudCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ctcccloud-cdn" + pCTCCCloudCMS "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ctcccloud-cms" pCTCCCloudICDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ctcccloud-icdn" pDogeCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/dogecloud-cdn" pEdgioApplications "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/edgio-applications" @@ -624,7 +625,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer return deployer, err } - case domain.DeploymentProviderTypeCTCCCloudAO, domain.DeploymentProviderTypeCTCCCloudCDN, domain.DeploymentProviderTypeCTCCCloudICDN: + case domain.DeploymentProviderTypeCTCCCloudAO, domain.DeploymentProviderTypeCTCCCloudCDN, domain.DeploymentProviderTypeCTCCCloudCMS, domain.DeploymentProviderTypeCTCCCloudICDN: { access := domain.AccessConfigForCTCCCloud{} if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { @@ -648,6 +649,13 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer }) return deployer, err + case domain.DeploymentProviderTypeCTCCCloudCMS: + deployer, err := pCTCCCloudCMS.NewDeployer(&pCTCCCloudCMS.DeployerConfig{ + AccessKeyId: access.AccessKeyId, + SecretAccessKey: access.SecretAccessKey, + }) + return deployer, err + case domain.DeploymentProviderTypeCTCCCloudICDN: deployer, err := pCTCCCloudICDN.NewDeployer(&pCTCCCloudICDN.DeployerConfig{ AccessKeyId: access.AccessKeyId, diff --git a/internal/domain/provider.go b/internal/domain/provider.go index 1e71f22a..302b8e11 100644 --- a/internal/domain/provider.go +++ b/internal/domain/provider.go @@ -217,7 +217,7 @@ const ( DeploymentProviderTypeCdnfly = DeploymentProviderType(AccessProviderTypeCdnfly) DeploymentProviderTypeCTCCCloudAO = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-ao") DeploymentProviderTypeCTCCCloudCDN = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-cdn") - DeploymentProviderTypeCTCCCloudCMS = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-cms") // (预留) + DeploymentProviderTypeCTCCCloudCMS = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-cms") DeploymentProviderTypeCTCCCloudELB = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-elb") // (预留) DeploymentProviderTypeCTCCCloudICDN = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-icdn") DeploymentProviderTypeDogeCloudLVDN = DeploymentProviderType(AccessProviderTypeDogeCloud + "-ldvn") // (预留) diff --git a/internal/pkg/core/deployer/providers/ctcccloud-cms/ctcccloud_cms.go b/internal/pkg/core/deployer/providers/ctcccloud-cms/ctcccloud_cms.go new file mode 100644 index 00000000..62b4084b --- /dev/null +++ b/internal/pkg/core/deployer/providers/ctcccloud-cms/ctcccloud_cms.go @@ -0,0 +1,67 @@ +package ctcccloudcms + +import ( + "context" + "fmt" + "log/slog" + + "github.com/usual2970/certimate/internal/pkg/core/deployer" + "github.com/usual2970/certimate/internal/pkg/core/uploader" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/ctcccloud-cms" +) + +type DeployerConfig struct { + // 天翼云 AccessKeyId。 + AccessKeyId string `json:"accessKeyId"` + // 天翼云 SecretAccessKey。 + SecretAccessKey string `json:"secretAccessKey"` +} + +type DeployerProvider struct { + config *DeployerConfig + logger *slog.Logger + sslUploader uploader.Uploader +} + +var _ deployer.Deployer = (*DeployerProvider)(nil) + +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { + if config == nil { + panic("config is nil") + } + + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ + AccessKeyId: config.AccessKeyId, + SecretAccessKey: config.SecretAccessKey, + }) + if err != nil { + return nil, fmt.Errorf("failed to create ssl uploader: %w", err) + } + + return &DeployerProvider{ + config: config, + logger: slog.Default(), + sslUploader: uploader, + }, nil +} + +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.New(slog.DiscardHandler) + } else { + d.logger = logger + } + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) { + // 上传证书到 CMS + 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)) + } + + return &deployer.DeployResult{}, nil +} diff --git a/internal/pkg/core/deployer/providers/ctcccloud-cms/ctcccloud_cms_test.go b/internal/pkg/core/deployer/providers/ctcccloud-cms/ctcccloud_cms_test.go new file mode 100644 index 00000000..65c3dade --- /dev/null +++ b/internal/pkg/core/deployer/providers/ctcccloud-cms/ctcccloud_cms_test.go @@ -0,0 +1,70 @@ +package ctcccloudcms_test + +import ( + "context" + "flag" + "fmt" + "os" + "strings" + "testing" + + provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ctcccloud-cms" +) + +var ( + fInputCertPath string + fInputKeyPath string + fAccessKeyId string + fSecretAccessKey string +) + +func init() { + argsPrefix := "CERTIMATE_DEPLOYER_CTCCCLOUDCMS_" + + flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") + flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") + flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "") + flag.StringVar(&fSecretAccessKey, argsPrefix+"SECRETACCESSKEY", "", "") +} + +/* +Shell command to run this test: + + go test -v ./ctcccloud_cms_test.go -args \ + --CERTIMATE_DEPLOYER_CTCCCLOUDCMS_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_DEPLOYER_CTCCCLOUDCMS_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_DEPLOYER_CTCCCLOUDCMS_ACCESSKEYID="your-access-key-id" \ + --CERTIMATE_DEPLOYER_CTCCCLOUDCMS_SECRETACCESSKEY="your-secret-access-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("ACCESSKEYID: %v", fAccessKeyId), + fmt.Sprintf("SECRETACCESSKEY: %v", fSecretAccessKey), + }, "\n")) + + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ + AccessKeyId: fAccessKeyId, + SecretAccessKey: fSecretAccessKey, + }) + 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) + }) +} diff --git a/internal/pkg/core/uploader/providers/1panel-ssl/1panel_ssl.go b/internal/pkg/core/uploader/providers/1panel-ssl/1panel_ssl.go index 7391129d..77ce16f0 100644 --- a/internal/pkg/core/uploader/providers/1panel-ssl/1panel_ssl.go +++ b/internal/pkg/core/uploader/providers/1panel-ssl/1panel_ssl.go @@ -61,7 +61,7 @@ func (u *UploaderProvider) WithLogger(logger *slog.Logger) uploader.Uploader { func (u *UploaderProvider) Upload(ctx context.Context, certPEM string, privkeyPEM string) (*uploader.UploadResult, error) { // 遍历证书列表,避免重复上传 - if res, err := u.getCertIfExists(ctx, certPEM, privkeyPEM); err != nil { + if res, err := u.findCertIfExists(ctx, certPEM, privkeyPEM); err != nil { return nil, err } else if res != nil { u.logger.Info("ssl certificate already exists") @@ -85,7 +85,7 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPEM string, privkeyPE } // 遍历证书列表,获取刚刚上传证书 ID - if res, err := u.getCertIfExists(ctx, certPEM, privkeyPEM); err != nil { + if res, err := u.findCertIfExists(ctx, certPEM, privkeyPEM); err != nil { return nil, err } else if res == nil { return nil, fmt.Errorf("no ssl certificate found, may be upload failed (code: %d, message: %s)", uploadWebsiteSSLResp.GetCode(), uploadWebsiteSSLResp.GetMessage()) @@ -94,7 +94,7 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPEM string, privkeyPE } } -func (u *UploaderProvider) getCertIfExists(ctx context.Context, certPEM string, privkeyPEM string) (*uploader.UploadResult, error) { +func (u *UploaderProvider) findCertIfExists(ctx context.Context, certPEM string, privkeyPEM string) (*uploader.UploadResult, error) { searchWebsiteSSLPageNumber := int32(1) searchWebsiteSSLPageSize := int32(100) for { diff --git a/internal/pkg/core/uploader/providers/ctcccloud-ao/ctcccloud_ao_test.go b/internal/pkg/core/uploader/providers/ctcccloud-ao/ctcccloud_ao_test.go index bbf8a0a9..53d2eee6 100644 --- a/internal/pkg/core/uploader/providers/ctcccloud-ao/ctcccloud_ao_test.go +++ b/internal/pkg/core/uploader/providers/ctcccloud-ao/ctcccloud_ao_test.go @@ -34,8 +34,8 @@ Shell command to run this test: go test -v ./ctcccloud_ao_test.go -args \ --CERTIMATE_UPLOADER_CTCCCLOUDAO_INPUTCERTPATH="/path/to/your-input-cert.pem" \ --CERTIMATE_UPLOADER_CTCCCLOUDAO_INPUTKEYPATH="/path/to/your-input-key.pem" \ - --CERTIMATE_DEPLOYER_CTCCCLOUDAO_ACCESSKEYID="your-access-key-id" \ - --CERTIMATE_DEPLOYER_CTCCCLOUDAO_SECRETACCESSKEY="your-secret-access-key" + --CERTIMATE_UPLOADER_CTCCCLOUDAO_ACCESSKEYID="your-access-key-id" \ + --CERTIMATE_UPLOADER_CTCCCLOUDAO_SECRETACCESSKEY="your-secret-access-key" */ func TestDeploy(t *testing.T) { flag.Parse() diff --git a/internal/pkg/core/uploader/providers/ctcccloud-cdn/ctcccloud_cdn_test.go b/internal/pkg/core/uploader/providers/ctcccloud-cdn/ctcccloud_cdn_test.go index c4eef38a..72ee6dfa 100644 --- a/internal/pkg/core/uploader/providers/ctcccloud-cdn/ctcccloud_cdn_test.go +++ b/internal/pkg/core/uploader/providers/ctcccloud-cdn/ctcccloud_cdn_test.go @@ -34,8 +34,8 @@ Shell command to run this test: go test -v ./ctcccloud_cdn_test.go -args \ --CERTIMATE_UPLOADER_CTCCCLOUDCDN_INPUTCERTPATH="/path/to/your-input-cert.pem" \ --CERTIMATE_UPLOADER_CTCCCLOUDCDN_INPUTKEYPATH="/path/to/your-input-key.pem" \ - --CERTIMATE_DEPLOYER_CTCCCLOUDCDN_ACCESSKEYID="your-access-key-id" \ - --CERTIMATE_DEPLOYER_CTCCCLOUDCDN_SECRETACCESSKEY="your-secret-access-key" + --CERTIMATE_UPLOADER_CTCCCLOUDCDN_ACCESSKEYID="your-access-key-id" \ + --CERTIMATE_UPLOADER_CTCCCLOUDCDN_SECRETACCESSKEY="your-secret-access-key" */ func TestDeploy(t *testing.T) { flag.Parse() diff --git a/internal/pkg/core/uploader/providers/ctcccloud-cms/ctcccloud_cms.go b/internal/pkg/core/uploader/providers/ctcccloud-cms/ctcccloud_cms.go new file mode 100644 index 00000000..a72c11c6 --- /dev/null +++ b/internal/pkg/core/uploader/providers/ctcccloud-cms/ctcccloud_cms.go @@ -0,0 +1,186 @@ +package ctcccloudcms + +import ( + "context" + "crypto/sha1" + "encoding/hex" + "errors" + "fmt" + "log/slog" + "strings" + "time" + + "github.com/usual2970/certimate/internal/pkg/core/uploader" + ctyuncms "github.com/usual2970/certimate/internal/pkg/sdk3rd/ctyun/cms" + certutil "github.com/usual2970/certimate/internal/pkg/utils/cert" + typeutil "github.com/usual2970/certimate/internal/pkg/utils/type" +) + +type UploaderConfig struct { + // 天翼云 AccessKeyId。 + AccessKeyId string `json:"accessKeyId"` + // 天翼云 SecretAccessKey。 + SecretAccessKey string `json:"secretAccessKey"` +} + +type UploaderProvider struct { + config *UploaderConfig + logger *slog.Logger + sdkClient *ctyuncms.Client +} + +var _ uploader.Uploader = (*UploaderProvider)(nil) + +func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { + if config == nil { + panic("config is nil") + } + + client, err := createSdkClient(config.AccessKeyId, config.SecretAccessKey) + if err != nil { + return nil, fmt.Errorf("failed to create sdk client: %w", err) + } + + return &UploaderProvider{ + config: config, + logger: slog.Default(), + sdkClient: client, + }, nil +} + +func (u *UploaderProvider) WithLogger(logger *slog.Logger) uploader.Uploader { + if logger == nil { + u.logger = slog.New(slog.DiscardHandler) + } else { + u.logger = logger + } + return u +} + +func (u *UploaderProvider) Upload(ctx context.Context, certPEM string, privkeyPEM string) (*uploader.UploadResult, error) { + // 遍历证书列表,避免重复上传 + if res, _ := u.findCertIfExists(ctx, certPEM); res != nil { + return res, nil + } + + // 提取服务器证书 + serverCertPEM, intermediaCertPEM, err := certutil.ExtractCertificatesFromPEM(certPEM) + if err != nil { + return nil, fmt.Errorf("failed to extract certs: %w", err) + } + + // 生成新证书名(需符合天翼云命名规则) + certName := fmt.Sprintf("cm%d", time.Now().Unix()) + + // 上传证书 + // REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=152&api=17243&data=204&isNormal=1&vid=283 + uploadCertificateReq := &ctyuncms.UploadCertificateRequest{ + Name: typeutil.ToPtr(certName), + Certificate: typeutil.ToPtr(serverCertPEM), + CertificateChain: typeutil.ToPtr(intermediaCertPEM), + PrivateKey: typeutil.ToPtr(privkeyPEM), + EncryptionStandard: typeutil.ToPtr("INTERNATIONAL"), + } + uploadCertificateResp, err := u.sdkClient.UploadCertificate(uploadCertificateReq) + u.logger.Debug("sdk request 'cms.UploadCertificate'", slog.Any("request", uploadCertificateReq), slog.Any("response", uploadCertificateResp)) + if err != nil { + if uploadCertificateResp != nil && uploadCertificateResp.GetError() == "CCMS_100000067" { + if res, err := u.findCertIfExists(ctx, certPEM); err != nil { + return nil, err + } else if res == nil { + return nil, errors.New("ctyun cms: no certificate found") + } else { + u.logger.Info("ssl certificate already exists") + return res, nil + } + } + + return nil, fmt.Errorf("failed to execute sdk request 'cms.UploadCertificate': %w", err) + } + + // 遍历证书列表,获取刚刚上传证书 ID + if res, err := u.findCertIfExists(ctx, certPEM); err != nil { + return nil, err + } else if res == nil { + return nil, fmt.Errorf("no ssl certificate found, may be upload failed") + } else { + return res, nil + } +} + +func (u *UploaderProvider) findCertIfExists(ctx context.Context, certPEM string) (*uploader.UploadResult, error) { + // 解析证书内容 + certX509, err := certutil.ParseCertificateFromPEM(certPEM) + if err != nil { + return nil, err + } + + // 查询用户证书列表 + // REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=152&api=17233&data=204&isNormal=1&vid=283 + getCertificateListPageNum := int32(1) + getCertificateListPageSize := int32(10) + for { + select { + case <-ctx.Done(): + return nil, ctx.Err() + default: + } + + getCertificateListReq := &ctyuncms.GetCertificateListRequest{ + PageNum: typeutil.ToPtr(getCertificateListPageNum), + PageSize: typeutil.ToPtr(getCertificateListPageSize), + Keyword: typeutil.ToPtr(certX509.Subject.CommonName), + Origin: typeutil.ToPtr("UPLOAD"), + } + getCertificateListResp, err := u.sdkClient.GetCertificateList(getCertificateListReq) + u.logger.Debug("sdk request 'cms.GetCertificateList'", slog.Any("request", getCertificateListReq), slog.Any("response", getCertificateListResp)) + if err != nil { + return nil, fmt.Errorf("failed to execute sdk request 'cms.GetCertificateList': %w", err) + } + + if getCertificateListResp.ReturnObj != nil { + fingerprint := sha1.Sum(certX509.Raw) + fingerprintHex := hex.EncodeToString(fingerprint[:]) + + for _, certRecord := range getCertificateListResp.ReturnObj.List { + // 对比证书名称 + if !strings.EqualFold(strings.Join(certX509.DNSNames, ","), certRecord.DomainName) { + continue + } + + // 对比证书有效期 + oldCertNotBefore, _ := time.Parse("2006-01-02T15:04:05Z", certRecord.IssueTime) + oldCertNotAfter, _ := time.Parse("2006-01-02T15:04:05Z", certRecord.ExpireTime) + if !certX509.NotBefore.Equal(oldCertNotBefore) { + continue + } else if !certX509.NotAfter.Equal(oldCertNotAfter) { + continue + } + + // 对比证书指纹 + if !strings.EqualFold(fingerprintHex, certRecord.Fingerprint) { + continue + } + + // 如果以上信息都一致,则视为已存在相同证书,直接返回 + u.logger.Info("ssl certificate already exists") + return &uploader.UploadResult{ + CertId: string(*&certRecord.Id), + CertName: certRecord.Name, + }, nil + } + } + + if getCertificateListResp.ReturnObj == nil || len(getCertificateListResp.ReturnObj.List) < int(getCertificateListPageSize) { + break + } else { + getCertificateListPageNum++ + } + } + + return nil, nil +} + +func createSdkClient(accessKeyId, secretAccessKey string) (*ctyuncms.Client, error) { + return ctyuncms.NewClient(accessKeyId, secretAccessKey) +} diff --git a/internal/pkg/core/uploader/providers/ctcccloud-cms/ctcccloud_cms_test.go b/internal/pkg/core/uploader/providers/ctcccloud-cms/ctcccloud_cms_test.go new file mode 100644 index 00000000..3fedfe4b --- /dev/null +++ b/internal/pkg/core/uploader/providers/ctcccloud-cms/ctcccloud_cms_test.go @@ -0,0 +1,72 @@ +package ctcccloudcms_test + +import ( + "context" + "encoding/json" + "flag" + "fmt" + "os" + "strings" + "testing" + + provider "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/ctcccloud-cms" +) + +var ( + fInputCertPath string + fInputKeyPath string + fAccessKeyId string + fSecretAccessKey string +) + +func init() { + argsPrefix := "CERTIMATE_UPLOADER_CTCCCLOUDCMS_" + + flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") + flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") + flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "") + flag.StringVar(&fSecretAccessKey, argsPrefix+"SECRETACCESSKEY", "", "") +} + +/* +Shell command to run this test: + + go test -v ./ctcccloud_cms_test.go -args \ + --CERTIMATE_UPLOADER_CTCCCLOUDCMS_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_UPLOADER_CTCCCLOUDCMS_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_UPLOADER_CTCCCLOUDCMS_ACCESSKEYID="your-access-key-id" \ + --CERTIMATE_UPLOADER_CTCCCLOUDCMS_SECRETACCESSKEY="your-secret-access-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("ACCESSKEYID: %v", fAccessKeyId), + fmt.Sprintf("SECRETACCESSKEY: %v", fSecretAccessKey), + }, "\n")) + + uploader, err := provider.NewUploader(&provider.UploaderConfig{ + AccessKeyId: fAccessKeyId, + SecretAccessKey: fSecretAccessKey, + }) + if err != nil { + t.Errorf("err: %+v", err) + return + } + + fInputCertData, _ := os.ReadFile(fInputCertPath) + fInputKeyData, _ := os.ReadFile(fInputKeyPath) + res, err := uploader.Upload(context.Background(), string(fInputCertData), string(fInputKeyData)) + if err != nil { + t.Errorf("err: %+v", err) + return + } + + sres, _ := json.Marshal(res) + t.Logf("ok: %s", string(sres)) + }) +} diff --git a/internal/pkg/core/uploader/providers/ctcccloud-icdn/ctcccloud_icdn_test.go b/internal/pkg/core/uploader/providers/ctcccloud-icdn/ctcccloud_icdn_test.go index c7d781f6..6bbf627f 100644 --- a/internal/pkg/core/uploader/providers/ctcccloud-icdn/ctcccloud_icdn_test.go +++ b/internal/pkg/core/uploader/providers/ctcccloud-icdn/ctcccloud_icdn_test.go @@ -34,8 +34,8 @@ Shell command to run this test: go test -v ./ctcccloud_icdn_test.go -args \ --CERTIMATE_UPLOADER_CTCCCLOUDICDN_INPUTCERTPATH="/path/to/your-input-cert.pem" \ --CERTIMATE_UPLOADER_CTCCCLOUDICDN_INPUTKEYPATH="/path/to/your-input-key.pem" \ - --CERTIMATE_DEPLOYER_CTCCCLOUDICDN_ACCESSKEYID="your-access-key-id" \ - --CERTIMATE_DEPLOYER_CTCCCLOUDICDN_SECRETACCESSKEY="your-secret-access-key" + --CERTIMATE_UPLOADER_CTCCCLOUDICDN_ACCESSKEYID="your-access-key-id" \ + --CERTIMATE_UPLOADER_CTCCCLOUDICDN_SECRETACCESSKEY="your-secret-access-key" */ func TestDeploy(t *testing.T) { flag.Parse() diff --git a/internal/pkg/core/uploader/providers/rainyun-sslcenter/rainyun_sslcenter.go b/internal/pkg/core/uploader/providers/rainyun-sslcenter/rainyun_sslcenter.go index 613fc7a9..cd3771e7 100644 --- a/internal/pkg/core/uploader/providers/rainyun-sslcenter/rainyun_sslcenter.go +++ b/internal/pkg/core/uploader/providers/rainyun-sslcenter/rainyun_sslcenter.go @@ -52,7 +52,8 @@ func (u *UploaderProvider) WithLogger(logger *slog.Logger) uploader.Uploader { } func (u *UploaderProvider) Upload(ctx context.Context, certPEM string, privkeyPEM string) (*uploader.UploadResult, error) { - if res, err := u.getCertIfExists(ctx, certPEM); err != nil { + // 遍历证书列表,避免重复上传 + if res, err := u.findCertIfExists(ctx, certPEM); err != nil { return nil, err } else if res != nil { u.logger.Info("ssl certificate already exists") @@ -71,7 +72,8 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPEM string, privkeyPE return nil, fmt.Errorf("failed to execute sdk request 'sslcenter.Create': %w", err) } - if res, err := u.getCertIfExists(ctx, certPEM); err != nil { + // 遍历证书列表,获取刚刚上传证书 ID + if res, err := u.findCertIfExists(ctx, certPEM); err != nil { return nil, err } else if res == nil { return nil, errors.New("rainyun sslcenter: no certificate found") @@ -80,14 +82,14 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPEM string, privkeyPE } } -func (u *UploaderProvider) getCertIfExists(ctx context.Context, certPEM string) (*uploader.UploadResult, error) { +func (u *UploaderProvider) findCertIfExists(ctx context.Context, certPEM string) (*uploader.UploadResult, error) { // 解析证书内容 certX509, err := certutil.ParseCertificateFromPEM(certPEM) if err != nil { return nil, err } - // 遍历 SSL 证书列表,避免重复上传 + // 遍历 SSL 证书列表 // REF: https://apifox.com/apidoc/shared/a4595cc8-44c5-4678-a2a3-eed7738dab03/api-69943046 // REF: https://apifox.com/apidoc/shared/a4595cc8-44c5-4678-a2a3-eed7738dab03/api-69943048 sslCenterListPage := int32(1) diff --git a/internal/pkg/core/uploader/providers/ucloud-ussl/ucloud_ussl.go b/internal/pkg/core/uploader/providers/ucloud-ussl/ucloud_ussl.go index acfbb214..2ceab189 100644 --- a/internal/pkg/core/uploader/providers/ucloud-ussl/ucloud_ussl.go +++ b/internal/pkg/core/uploader/providers/ucloud-ussl/ucloud_ussl.go @@ -88,7 +88,7 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPEM string, privkeyPE u.logger.Debug("sdk request 'ussl.UploadNormalCertificate'", slog.Any("request", uploadNormalCertificateReq), slog.Any("response", uploadNormalCertificateResp)) if err != nil { if uploadNormalCertificateResp != nil && uploadNormalCertificateResp.GetRetCode() == 80035 { - if res, err := u.getCertIfExists(ctx, certPEM); err != nil { + if res, err := u.findCertIfExists(ctx, certPEM); err != nil { return nil, err } else if res == nil { return nil, errors.New("ucloud ssl: no certificate found") @@ -111,14 +111,14 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPEM string, privkeyPE }, nil } -func (u *UploaderProvider) getCertIfExists(ctx context.Context, certPEM string) (*uploader.UploadResult, error) { +func (u *UploaderProvider) findCertIfExists(ctx context.Context, certPEM string) (*uploader.UploadResult, error) { // 解析证书内容 certX509, err := certutil.ParseCertificateFromPEM(certPEM) if err != nil { return nil, err } - // 遍历获取用户证书列表,避免重复上传 + // 遍历获取用户证书列表 // REF: https://docs.ucloud.cn/api/usslcertificate-api/get_certificate_list // REF: https://docs.ucloud.cn/api/usslcertificate-api/download_certificate getCertificateListPage := int(1) diff --git a/internal/pkg/core/uploader/providers/wangsu-certificate/wangsu_certificate_test.go b/internal/pkg/core/uploader/providers/wangsu-certificate/wangsu_certificate_test.go index 818fc7d0..7bbf63c6 100644 --- a/internal/pkg/core/uploader/providers/wangsu-certificate/wangsu_certificate_test.go +++ b/internal/pkg/core/uploader/providers/wangsu-certificate/wangsu_certificate_test.go @@ -34,8 +34,8 @@ Shell command to run this test: go test -v ./wangsu_certificate_test.go -args \ --CERTIMATE_UPLOADER_WANGSUCERTIFICATE_INPUTCERTPATH="/path/to/your-input-cert.pem" \ --CERTIMATE_UPLOADER_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_UPLOADER_WANGSUCERTIFICATE_ACCESSKEYID="your-access-key-id" \ + --CERTIMATE_UPLOADER_WANGSUCERTIFICATE_ACCESSKEYSECRET="your-access-key-secret" */ func TestDeploy(t *testing.T) { flag.Parse() diff --git a/internal/pkg/sdk3rd/ctyun/ao/api_create_cert.go b/internal/pkg/sdk3rd/ctyun/ao/api_create_cert.go index b45543f0..1a9ac21e 100644 --- a/internal/pkg/sdk3rd/ctyun/ao/api_create_cert.go +++ b/internal/pkg/sdk3rd/ctyun/ao/api_create_cert.go @@ -15,7 +15,7 @@ type CreateCertResponse struct { baseResult ReturnObj *struct { - Id int32 `json:"id"` + Id int64 `json:"id"` } `json:"returnObj,omitempty"` } diff --git a/internal/pkg/sdk3rd/ctyun/ao/api_query_cert.go b/internal/pkg/sdk3rd/ctyun/ao/api_query_cert.go index f8b203d0..9ec2d740 100644 --- a/internal/pkg/sdk3rd/ctyun/ao/api_query_cert.go +++ b/internal/pkg/sdk3rd/ctyun/ao/api_query_cert.go @@ -7,7 +7,7 @@ import ( ) type QueryCertRequest struct { - Id *int32 `json:"id,omitempty"` + Id *int64 `json:"id,omitempty"` Name *string `json:"name,omitempty"` UsageMode *int32 `json:"usage_mode,omitempty"` } diff --git a/internal/pkg/sdk3rd/ctyun/ao/client.go b/internal/pkg/sdk3rd/ctyun/ao/client.go index 822f1a4f..dbf20321 100644 --- a/internal/pkg/sdk3rd/ctyun/ao/client.go +++ b/internal/pkg/sdk3rd/ctyun/ao/client.go @@ -1,6 +1,7 @@ package ao import ( + "fmt" "time" "github.com/go-resty/resty/v2" @@ -36,5 +37,13 @@ func (c *Client) doRequest(request *resty.Request) (*resty.Response, error) { } func (c *Client) doRequestWithResult(request *resty.Request, result baseResultInterface) (*resty.Response, error) { - return c.client.DoRequestWithResult(request, result) + response, err := c.client.DoRequestWithResult(request, result) + if err == nil { + statusCode := result.GetStatusCode() + if statusCode != "" && statusCode != "100000" { + return response, fmt.Errorf("sdkerr: api error, code='%s', message='%s', errorCode='%s', errorMessage='%s'", statusCode, result.GetMessage(), result.GetMessage(), result.GetErrorMessage()) + } + } + + return response, err } diff --git a/internal/pkg/sdk3rd/ctyun/ao/types.go b/internal/pkg/sdk3rd/ctyun/ao/types.go index 98b62097..ba5582b3 100644 --- a/internal/pkg/sdk3rd/ctyun/ao/types.go +++ b/internal/pkg/sdk3rd/ctyun/ao/types.go @@ -71,7 +71,7 @@ func (r *baseResult) GetErrorMessage() string { var _ baseResultInterface = (*baseResult)(nil) type CertRecord struct { - Id int32 `json:"id"` + Id int64 `json:"id"` Name string `json:"name"` CN string `json:"cn"` SANs []string `json:"sans"` diff --git a/internal/pkg/sdk3rd/ctyun/cdn/api_create_cert.go b/internal/pkg/sdk3rd/ctyun/cdn/api_create_cert.go index 7a2290ab..9445035b 100644 --- a/internal/pkg/sdk3rd/ctyun/cdn/api_create_cert.go +++ b/internal/pkg/sdk3rd/ctyun/cdn/api_create_cert.go @@ -15,7 +15,7 @@ type CreateCertResponse struct { baseResult ReturnObj *struct { - Id int32 `json:"id"` + Id int64 `json:"id"` } `json:"returnObj,omitempty"` } diff --git a/internal/pkg/sdk3rd/ctyun/cdn/api_query_cert_detail.go b/internal/pkg/sdk3rd/ctyun/cdn/api_query_cert_detail.go index 02dfd5eb..12501f29 100644 --- a/internal/pkg/sdk3rd/ctyun/cdn/api_query_cert_detail.go +++ b/internal/pkg/sdk3rd/ctyun/cdn/api_query_cert_detail.go @@ -7,7 +7,7 @@ import ( ) type QueryCertDetailRequest struct { - Id *int32 `json:"id,omitempty"` + Id *int64 `json:"id,omitempty"` Name *string `json:"name,omitempty"` UsageMode *int32 `json:"usage_mode,omitempty"` } diff --git a/internal/pkg/sdk3rd/ctyun/cdn/client.go b/internal/pkg/sdk3rd/ctyun/cdn/client.go index 3699c721..77402a4e 100644 --- a/internal/pkg/sdk3rd/ctyun/cdn/client.go +++ b/internal/pkg/sdk3rd/ctyun/cdn/client.go @@ -1,6 +1,7 @@ package cdn import ( + "fmt" "time" "github.com/go-resty/resty/v2" @@ -36,5 +37,13 @@ func (c *Client) doRequest(request *resty.Request) (*resty.Response, error) { } func (c *Client) doRequestWithResult(request *resty.Request, result baseResultInterface) (*resty.Response, error) { - return c.client.DoRequestWithResult(request, result) + response, err := c.client.DoRequestWithResult(request, result) + if err == nil { + statusCode := result.GetStatusCode() + if statusCode != "" && statusCode != "100000" { + return response, fmt.Errorf("sdkerr: api error, code='%s', message='%s', errorCode='%s', errorMessage='%s'", statusCode, result.GetMessage(), result.GetMessage(), result.GetErrorMessage()) + } + } + + return response, err } diff --git a/internal/pkg/sdk3rd/ctyun/cdn/types.go b/internal/pkg/sdk3rd/ctyun/cdn/types.go index a4206792..96c97ce1 100644 --- a/internal/pkg/sdk3rd/ctyun/cdn/types.go +++ b/internal/pkg/sdk3rd/ctyun/cdn/types.go @@ -71,7 +71,7 @@ func (r *baseResult) GetErrorMessage() string { var _ baseResultInterface = (*baseResult)(nil) type CertRecord struct { - Id int32 `json:"id"` + Id int64 `json:"id"` Name string `json:"name"` CN string `json:"cn"` SANs []string `json:"sans"` diff --git a/internal/pkg/sdk3rd/ctyun/cms/api_get_certificate_list.go b/internal/pkg/sdk3rd/ctyun/cms/api_get_certificate_list.go new file mode 100644 index 00000000..f410921f --- /dev/null +++ b/internal/pkg/sdk3rd/ctyun/cms/api_get_certificate_list.go @@ -0,0 +1,44 @@ +package cms + +import ( + "context" + "net/http" +) + +type GetCertificateListRequest struct { + Status *string `json:"status,omitempty"` + Keyword *string `json:"keyword,omitempty"` + PageNum *int32 `json:"pageNum,omitempty"` + PageSize *int32 `json:"pageSize,omitempty"` + Origin *string `json:"origin,omitempty"` +} + +type GetCertificateListResponse struct { + baseResult + + ReturnObj *struct { + List []*CertificateRecord `json:"list,omitempty"` + TotalSize int32 `json:"totalSize,omitempty"` + } `json:"returnObj,omitempty"` +} + +func (c *Client) GetCertificateList(req *GetCertificateListRequest) (*GetCertificateListResponse, error) { + return c.GetCertificateListWithContext(context.Background(), req) +} + +func (c *Client) GetCertificateListWithContext(ctx context.Context, req *GetCertificateListRequest) (*GetCertificateListResponse, error) { + httpreq, err := c.newRequest(http.MethodPost, "/v1/certificate/list") + if err != nil { + return nil, err + } else { + httpreq.SetBody(req) + httpreq.SetContext(ctx) + } + + result := &GetCertificateListResponse{} + if _, err := c.doRequestWithResult(httpreq, result); err != nil { + return result, err + } + + return result, nil +} diff --git a/internal/pkg/sdk3rd/ctyun/cms/api_upload_certificate.go b/internal/pkg/sdk3rd/ctyun/cms/api_upload_certificate.go new file mode 100644 index 00000000..8044aa40 --- /dev/null +++ b/internal/pkg/sdk3rd/ctyun/cms/api_upload_certificate.go @@ -0,0 +1,41 @@ +package cms + +import ( + "context" + "net/http" +) + +type UploadCertificateRequest struct { + Name *string `json:"name,omitempty"` + Certificate *string `json:"certificate,omitempty"` + CertificateChain *string `json:"certificateChain,omitempty"` + PrivateKey *string `json:"privateKey,omitempty"` + EncryptionStandard *string `json:"encryptionStandard,omitempty"` + EncCertificate *string `json:"encCertificate,omitempty"` + EncPrivateKey *string `json:"encPrivateKey,omitempty"` +} + +type UploadCertificateResponse struct { + baseResult +} + +func (c *Client) UploadCertificate(req *UploadCertificateRequest) (*UploadCertificateResponse, error) { + return c.UploadCertificateWithContext(context.Background(), req) +} + +func (c *Client) UploadCertificateWithContext(ctx context.Context, req *UploadCertificateRequest) (*UploadCertificateResponse, error) { + httpreq, err := c.newRequest(http.MethodPost, "/v1/certificate/upload") + if err != nil { + return nil, err + } else { + httpreq.SetBody(req) + httpreq.SetContext(ctx) + } + + result := &UploadCertificateResponse{} + if _, err := c.doRequestWithResult(httpreq, result); err != nil { + return result, err + } + + return result, nil +} diff --git a/internal/pkg/sdk3rd/ctyun/cms/client.go b/internal/pkg/sdk3rd/ctyun/cms/client.go new file mode 100644 index 00000000..015829d5 --- /dev/null +++ b/internal/pkg/sdk3rd/ctyun/cms/client.go @@ -0,0 +1,49 @@ +package cms + +import ( + "fmt" + "time" + + "github.com/go-resty/resty/v2" + "github.com/usual2970/certimate/internal/pkg/sdk3rd/ctyun/openapi" +) + +const endpoint = "https://ccms-global.ctapi.ctyun.cn" + +type Client struct { + client *openapi.Client +} + +func NewClient(accessKeyId, secretAccessKey string) (*Client, error) { + client, err := openapi.NewClient(endpoint, accessKeyId, secretAccessKey) + if err != nil { + return nil, err + } + + return &Client{client: client}, nil +} + +func (c *Client) SetTimeout(timeout time.Duration) *Client { + c.client.SetTimeout(timeout) + return c +} + +func (c *Client) newRequest(method string, path string) (*resty.Request, error) { + return c.client.NewRequest(method, path) +} + +func (c *Client) doRequest(request *resty.Request) (*resty.Response, error) { + return c.client.DoRequest(request) +} + +func (c *Client) doRequestWithResult(request *resty.Request, result baseResultInterface) (*resty.Response, error) { + response, err := c.client.DoRequestWithResult(request, result) + if err == nil { + statusCode := result.GetStatusCode() + if statusCode != "" && statusCode != "200" { + return response, fmt.Errorf("sdkerr: api error, code='%s', message='%s', errorCode='%s', errorMessage='%s'", statusCode, result.GetMessage(), result.GetMessage(), result.GetErrorMessage()) + } + } + + return response, err +} diff --git a/internal/pkg/sdk3rd/ctyun/cms/types.go b/internal/pkg/sdk3rd/ctyun/cms/types.go new file mode 100644 index 00000000..b5b0b4d7 --- /dev/null +++ b/internal/pkg/sdk3rd/ctyun/cms/types.go @@ -0,0 +1,94 @@ +package cms + +import ( + "bytes" + "encoding/json" + "strconv" +) + +type baseResultInterface interface { + GetStatusCode() string + GetMessage() string + GetError() string + GetErrorMessage() string +} + +type baseResult struct { + StatusCode json.RawMessage `json:"statusCode,omitempty"` + Message *string `json:"message,omitempty"` + Error *string `json:"error,omitempty"` + ErrorMessage *string `json:"errorMessage,omitempty"` + RequestId *string `json:"requestId,omitempty"` +} + +func (r *baseResult) GetStatusCode() string { + if r.StatusCode == nil { + return "" + } + + decoder := json.NewDecoder(bytes.NewReader(r.StatusCode)) + token, err := decoder.Token() + if err != nil { + return "" + } + + switch t := token.(type) { + case string: + return t + case float64: + return strconv.FormatFloat(t, 'f', -1, 64) + case json.Number: + return t.String() + default: + return "" + } +} + +func (r *baseResult) GetMessage() string { + if r.Message == nil { + return "" + } + + return *r.Message +} + +func (r *baseResult) GetError() string { + if r.Error == nil { + return "" + } + + return *r.Error +} + +func (r *baseResult) GetErrorMessage() string { + if r.ErrorMessage == nil { + return "" + } + + return *r.ErrorMessage +} + +var _ baseResultInterface = (*baseResult)(nil) + +type CertificateRecord struct { + Id string `json:"id"` + Origin string `json:"origin"` + Type string `json:"type"` + ResourceId string `json:"resourceId"` + ResourceType string `json:"resourceType"` + CertificateId string `json:"certificateId"` + CertificateMode string `json:"certificateMode"` + Name string `json:"name"` + Status string `json:"status"` + DetailStatus string `json:"detailStatus"` + ManagedStatus string `json:"managedStatus"` + Fingerprint string `json:"fingerprint"` + IssueTime string `json:"issueTime"` + ExpireTime string `json:"expireTime"` + DomainType string `json:"domainType"` + DomainName string `json:"domainName"` + EncryptionStandard string `json:"encryptionStandard"` + EncryptionAlgorithm string `json:"encryptionAlgorithm"` + CreateTime string `json:"createTime"` + UpdateTime string `json:"updateTime"` +} diff --git a/internal/pkg/sdk3rd/ctyun/icdn/api_create_cert.go b/internal/pkg/sdk3rd/ctyun/icdn/api_create_cert.go index ce96bd51..93c09087 100644 --- a/internal/pkg/sdk3rd/ctyun/icdn/api_create_cert.go +++ b/internal/pkg/sdk3rd/ctyun/icdn/api_create_cert.go @@ -15,7 +15,7 @@ type CreateCertResponse struct { baseResult ReturnObj *struct { - Id int32 `json:"id"` + Id int64 `json:"id"` } `json:"returnObj,omitempty"` } diff --git a/internal/pkg/sdk3rd/ctyun/icdn/api_query_cert_detail.go b/internal/pkg/sdk3rd/ctyun/icdn/api_query_cert_detail.go index 405ecd50..2842d1f7 100644 --- a/internal/pkg/sdk3rd/ctyun/icdn/api_query_cert_detail.go +++ b/internal/pkg/sdk3rd/ctyun/icdn/api_query_cert_detail.go @@ -7,7 +7,7 @@ import ( ) type QueryCertDetailRequest struct { - Id *int32 `json:"id,omitempty"` + Id *int64 `json:"id,omitempty"` Name *string `json:"name,omitempty"` UsageMode *int32 `json:"usage_mode,omitempty"` } diff --git a/internal/pkg/sdk3rd/ctyun/icdn/client.go b/internal/pkg/sdk3rd/ctyun/icdn/client.go index 0c2248e6..5f3e0084 100644 --- a/internal/pkg/sdk3rd/ctyun/icdn/client.go +++ b/internal/pkg/sdk3rd/ctyun/icdn/client.go @@ -1,6 +1,7 @@ package icdn import ( + "fmt" "time" "github.com/go-resty/resty/v2" @@ -36,5 +37,13 @@ func (c *Client) doRequest(request *resty.Request) (*resty.Response, error) { } func (c *Client) doRequestWithResult(request *resty.Request, result baseResultInterface) (*resty.Response, error) { - return c.client.DoRequestWithResult(request, result) + response, err := c.client.DoRequestWithResult(request, result) + if err == nil { + statusCode := result.GetStatusCode() + if statusCode != "" && statusCode != "100000" { + return response, fmt.Errorf("sdkerr: api error, code='%s', message='%s', errorCode='%s', errorMessage='%s'", statusCode, result.GetMessage(), result.GetMessage(), result.GetErrorMessage()) + } + } + + return response, err } diff --git a/internal/pkg/sdk3rd/ctyun/icdn/types.go b/internal/pkg/sdk3rd/ctyun/icdn/types.go index 095109e0..2b2f3d95 100644 --- a/internal/pkg/sdk3rd/ctyun/icdn/types.go +++ b/internal/pkg/sdk3rd/ctyun/icdn/types.go @@ -71,7 +71,7 @@ func (r *baseResult) GetErrorMessage() string { var _ baseResultInterface = (*baseResult)(nil) type CertRecord struct { - Id int32 `json:"id"` + Id int64 `json:"id"` Name string `json:"name"` CN string `json:"cn"` SANs []string `json:"sans"` diff --git a/ui/src/domain/provider.ts b/ui/src/domain/provider.ts index 5caf1f05..10a23571 100644 --- a/ui/src/domain/provider.ts +++ b/ui/src/domain/provider.ts @@ -415,6 +415,7 @@ export const DEPLOYMENT_PROVIDERS = Object.freeze({ CDNFLY: `${ACCESS_PROVIDERS.CDNFLY}`, CTCCCLOUD_AO: `${ACCESS_PROVIDERS.CTCCCLOUD}-ao`, CTCCCLOUD_CDN: `${ACCESS_PROVIDERS.CTCCCLOUD}-cdn`, + CTCCCLOUD_CMS: `${ACCESS_PROVIDERS.CTCCCLOUD}-cms`, CTCCCLOUD_ICDN: `${ACCESS_PROVIDERS.CTCCCLOUD}-icdn`, DOGECLOUD_CDN: `${ACCESS_PROVIDERS.DOGECLOUD}-cdn`, EDGIO_APPLICATIONS: `${ACCESS_PROVIDERS.EDGIO}-applications`, @@ -576,6 +577,7 @@ export const deploymentProvidersMap: Map