refactor: clean code

This commit is contained in:
Fu Diwei
2025-11-13 20:27:03 +08:00
parent 73fa214c9f
commit 1c252310e5
84 changed files with 1727 additions and 1460 deletions
@@ -17,9 +17,10 @@ func init() {
}
provider, err := baishancdn.NewSSLDeployerProvider(&baishancdn.SSLDeployerProviderConfig{
ApiToken: credentials.ApiToken,
Domain: xmaps.GetString(options.ProviderExtendedConfig, "domain"),
CertificateId: xmaps.GetString(options.ProviderExtendedConfig, "certificateId"),
ApiToken: credentials.ApiToken,
DomainMatchPattern: xmaps.GetString(options.ProviderExtendedConfig, "domainMatchPattern"),
Domain: xmaps.GetString(options.ProviderExtendedConfig, "domain"),
CertificateId: xmaps.GetString(options.ProviderExtendedConfig, "certificateId"),
})
return provider, err
})
@@ -20,9 +20,10 @@ func init() {
}
provider, err := wangsucdn.NewSSLDeployerProvider(&wangsucdn.SSLDeployerProviderConfig{
AccessKeyId: credentials.AccessKeyId,
AccessKeySecret: credentials.AccessKeySecret,
Domains: lo.Filter(strings.Split(xmaps.GetString(options.ProviderExtendedConfig, "domains"), ";"), func(s string, _ int) bool { return s != "" }),
AccessKeyId: credentials.AccessKeyId,
AccessKeySecret: credentials.AccessKeySecret,
DomainMatchPattern: xmaps.GetString(options.ProviderExtendedConfig, "domainMatchPattern"),
Domains: lo.Filter(strings.Split(xmaps.GetString(options.ProviderExtendedConfig, "domains"), ";"), func(s string, _ int) bool { return s != "" }),
})
return provider, err
})
@@ -17,13 +17,14 @@ func init() {
}
provider, err := wangsucdnpro.NewSSLDeployerProvider(&wangsucdnpro.SSLDeployerProviderConfig{
AccessKeyId: credentials.AccessKeyId,
AccessKeySecret: credentials.AccessKeySecret,
ApiKey: credentials.ApiKey,
Environment: xmaps.GetOrDefaultString(options.ProviderExtendedConfig, "environment", "production"),
Domain: xmaps.GetString(options.ProviderExtendedConfig, "domain"),
CertificateId: xmaps.GetString(options.ProviderExtendedConfig, "certificateId"),
WebhookId: xmaps.GetString(options.ProviderExtendedConfig, "webhookId"),
AccessKeyId: credentials.AccessKeyId,
AccessKeySecret: credentials.AccessKeySecret,
ApiKey: credentials.ApiKey,
Environment: xmaps.GetOrDefaultString(options.ProviderExtendedConfig, "environment", "production"),
DomainMatchPattern: xmaps.GetString(options.ProviderExtendedConfig, "domainMatchPattern"),
Domain: xmaps.GetString(options.ProviderExtendedConfig, "domain"),
CertificateId: xmaps.GetString(options.ProviderExtendedConfig, "certificateId"),
WebhookId: xmaps.GetString(options.ProviderExtendedConfig, "webhookId"),
})
return provider, err
})
@@ -106,7 +106,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
}
siteName := dns01.UnFqdn(authZone)
siteID, err := d.getSiteId(siteName)
siteID, err := d.findSiteIdByName(siteName)
if err != nil {
return fmt.Errorf("alicloud-esa: could not find site for zone %q: %w", siteName, err)
}
@@ -158,17 +158,17 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
return d.config.PropagationTimeout, d.config.PollingInterval
}
func (d *DNSProvider) getSiteId(siteName string) (int64, error) {
pageNumber := 1
pageSize := 500
func (d *DNSProvider) findSiteIdByName(siteName string) (int64, error) {
aliListSitesPageNumber := 1
aliListSitesPageSize := 500
for {
// REF: https://www.alibabacloud.com/help/en/edge-security-acceleration/esa/api-esa-2024-09-10-listsites
aliListSitesReq := &aliesa.ListSitesRequest{
SiteName: tea.String(siteName),
SiteSearchType: tea.String("exact"),
PageNumber: tea.Int32(int32(pageNumber)),
PageSize: tea.Int32(int32(pageSize)),
AccessType: tea.String("NS"),
PageNumber: tea.Int32(int32(aliListSitesPageNumber)),
PageSize: tea.Int32(int32(aliListSitesPageSize)),
}
aliListSitesResp, err := d.client.ListSites(aliListSitesReq)
if err != nil {
@@ -177,20 +177,20 @@ func (d *DNSProvider) getSiteId(siteName string) (int64, error) {
if aliListSitesResp.Body == nil {
break
} else {
for _, site := range aliListSitesResp.Body.Sites {
if *site.GetSiteName() == siteName {
return *site.GetSiteId(), nil
}
}
if len(aliListSitesResp.Body.Sites) < pageSize {
break
}
pageNumber++
}
for _, siteItem := range aliListSitesResp.Body.Sites {
if *siteItem.GetSiteName() == siteName {
return *siteItem.GetSiteId(), nil
}
}
if len(aliListSitesResp.Body.Sites) < aliListSitesPageSize {
break
}
aliListSitesPageNumber++
}
return 0, errors.New("site not found")
return 0, fmt.Errorf("could not find site '%s'", siteName)
}
@@ -145,31 +145,31 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
}
func (d *DNSProvider) findDNSRecord(zoneName, subDomain, tokenValue string) (*bcedns.Record, error) {
pageMarker := ""
pageSize := 1000
bceListRecordPageMarker := ""
for {
// REF: https://cloud.baidu.com/doc/DNS/s/El4s7lssr#%E6%9F%A5%E8%AF%A2%E8%A7%A3%E6%9E%90%E8%AE%B0%E5%BD%95%E5%88%97%E8%A1%A8
bceListRecordReq := &bcedns.ListRecordRequest{}
bceListRecordReq.Rr = subDomain
bceListRecordReq.Marker = pageMarker
bceListRecordReq.MaxKeys = pageSize
bceListRecordReq.Marker = bceListRecordPageMarker
bceListRecordReq.MaxKeys = 1000
ceListRecordResp, err := d.client.ListRecord(zoneName, bceListRecordReq)
bceListRecordResp, err := d.client.ListRecord(zoneName, bceListRecordReq)
if err != nil {
return nil, err
}
for _, record := range ceListRecordResp.Records {
for _, record := range bceListRecordResp.Records {
if record.Type == "TXT" && record.Rr == subDomain && record.Value == tokenValue {
return &record, nil
}
}
pageMarker = ceListRecordResp.NextMarker
if pageMarker == "" {
if bceListRecordResp.NextMarker == "" {
break
}
bceListRecordPageMarker = bceListRecordResp.NextMarker
}
return nil, errors.New("record not found")
return nil, errors.New("could not find record")
}
@@ -102,7 +102,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
return fmt.Errorf("dnsla: %w", err)
}
zone, err := d.getDNSZone(dns01.UnFqdn(authZone))
zone, err := d.findZone(dns01.UnFqdn(authZone))
if err != nil {
return fmt.Errorf("dnsla: error when list zones: %w", err)
}
@@ -149,34 +149,36 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
return d.config.PropagationTimeout, d.config.PollingInterval
}
func (d *DNSProvider) getDNSZone(zoneName string) (*dnslasdk.DomainRecord, error) {
pageIndex := int32(1)
pageSize := int32(100)
func (d *DNSProvider) findZone(zoneName string) (*dnslasdk.DomainRecord, error) {
dnslaListDomainsPageIndex := 1
dnslaListDomainsPageSize := 100
for {
// REF: https://www.dnsla.cn/docs/ApiDoc
dnslaListDomainsReq := &dnslasdk.ListDomainsRequest{
PageIndex: &pageIndex,
PageSize: &pageSize,
PageIndex: lo.ToPtr(int32(dnslaListDomainsPageIndex)),
PageSize: lo.ToPtr(int32(dnslaListDomainsPageSize)),
}
dnslaListDomainsResp, err := d.client.ListDomains(dnslaListDomainsReq)
if err != nil {
return nil, err
}
if dnslaListDomainsResp.Data != nil {
for _, item := range dnslaListDomainsResp.Data.Results {
if strings.TrimRight(item.Domain, ".") == zoneName || strings.TrimRight(item.DisplayDomain, ".") == zoneName {
return item, nil
}
}
}
if dnslaListDomainsResp.Data == nil || len(dnslaListDomainsResp.Data.Results) < int(pageSize) {
if dnslaListDomainsResp.Data == nil {
break
}
pageIndex++
for _, domainItem := range dnslaListDomainsResp.Data.Results {
if strings.TrimRight(domainItem.Domain, ".") == zoneName || strings.TrimRight(domainItem.DisplayDomain, ".") == zoneName {
return domainItem, nil
}
}
if len(dnslaListDomainsResp.Data.Results) < dnslaListDomainsPageSize {
break
}
dnslaListDomainsPageIndex++
}
return nil, fmt.Errorf("zone '%s' not found", zoneName)
return nil, fmt.Errorf("could not find zone '%s'", zoneName)
}
@@ -137,5 +137,5 @@ func (d *DNSProvider) findDNSRecord(zoneName, subDomain, tokenValue string) (lib
}
}
return nil, errors.New("record not found")
return nil, errors.New("could not find record")
}
@@ -101,7 +101,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
return fmt.Errorf("jdcloud: %w", err)
}
zone, err := d.getDNSZone(dns01.UnFqdn(authZone))
zone, err := d.findZone(dns01.UnFqdn(authZone))
if err != nil {
return fmt.Errorf("jdcloud: error when list zones: %w", err)
}
@@ -144,7 +144,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return fmt.Errorf("jdcloud: unknown record ID for '%s'", info.EffectiveFQDN)
}
zone, err := d.getDNSZone(dns01.UnFqdn(authZone))
zone, err := d.findZone(dns01.UnFqdn(authZone))
if err != nil {
return fmt.Errorf("jdcloud: error when list zones: %w", err)
}
@@ -166,15 +166,15 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
return d.config.PropagationTimeout, d.config.PollingInterval
}
func (d *DNSProvider) getDNSZone(zoneName string) (*jddnsmodel.DomainInfo, error) {
pageNumber := 1
pageSize := 10
func (d *DNSProvider) findZone(zoneName string) (*jddnsmodel.DomainInfo, error) {
jddnsDescribeDomainsPageNumber := 1
jddnsDescribeDomainsPageSize := 10
for {
// REF: https://docs.jdcloud.com/cn/jd-cloud-dns/api/describedomains
jddnsDescribeDomainsReq := jddns.NewDescribeDomainsRequestWithoutParam()
jddnsDescribeDomainsReq.SetRegionId(d.config.RegionId)
jddnsDescribeDomainsReq.SetPageNumber(pageNumber)
jddnsDescribeDomainsReq.SetPageSize(pageSize)
jddnsDescribeDomainsReq.SetPageNumber(jddnsDescribeDomainsPageNumber)
jddnsDescribeDomainsReq.SetPageSize(jddnsDescribeDomainsPageSize)
jddnsDescribeDomainsReq.SetDomainName(zoneName)
jddnsDescribeDomainsResp, err := d.client.DescribeDomains(jddnsDescribeDomainsReq)
@@ -182,18 +182,18 @@ func (d *DNSProvider) getDNSZone(zoneName string) (*jddnsmodel.DomainInfo, error
return nil, err
}
for _, item := range jddnsDescribeDomainsResp.Result.DataList {
if item.DomainName == zoneName {
return &item, nil
for _, domainItem := range jddnsDescribeDomainsResp.Result.DataList {
if domainItem.DomainName == zoneName {
return &domainItem, nil
}
}
if len(jddnsDescribeDomainsResp.Result.DataList) < pageSize {
if len(jddnsDescribeDomainsResp.Result.DataList) < jddnsDescribeDomainsPageSize {
break
}
pageNumber++
jddnsDescribeDomainsPageNumber++
}
return nil, fmt.Errorf("jdcloud: zone %s not found", zoneName)
return nil, fmt.Errorf("could not find zone '%s'", zoneName)
}
@@ -144,8 +144,7 @@ func (d *SSLDeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCer
// 查询 HTTPS 监听列表
// REF: https://help.aliyun.com/zh/slb/application-load-balancer/developer-reference/api-alb-2020-06-16-listlisteners
listenerIds := make([]string, 0)
listListenersLimit := int32(100)
var listListenersToken *string = nil
listListenersToken := (*string)(nil)
for {
select {
case <-ctx.Done():
@@ -154,9 +153,9 @@ func (d *SSLDeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCer
}
listListenersReq := &alialb.ListListenersRequest{
MaxResults: tea.Int32(listListenersLimit),
NextToken: listListenersToken,
LoadBalancerIds: []*string{tea.String(d.config.LoadbalancerId)},
MaxResults: tea.Int32(100),
LoadBalancerIds: tea.StringSlice([]string{d.config.LoadbalancerId}),
ListenerProtocol: tea.String("HTTPS"),
}
listListenersResp, err := d.sdkClients.ALB.ListListenersWithContext(context.TODO(), listListenersReq, &dara.RuntimeOptions{})
@@ -165,17 +164,19 @@ func (d *SSLDeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCer
return fmt.Errorf("failed to execute sdk request 'alb.ListListeners': %w", err)
}
if listListenersResp.Body.Listeners != nil {
for _, listener := range listListenersResp.Body.Listeners {
listenerIds = append(listenerIds, tea.StringValue(listener.ListenerId))
}
if listListenersResp.Body == nil {
break
}
for _, listener := range listListenersResp.Body.Listeners {
listenerIds = append(listenerIds, tea.StringValue(listener.ListenerId))
}
if len(listListenersResp.Body.Listeners) == 0 || listListenersResp.Body.NextToken == nil {
break
} else {
listListenersToken = listListenersResp.Body.NextToken
}
listListenersToken = listListenersResp.Body.NextToken
}
// 查询 QUIC 监听列表
@@ -189,9 +190,9 @@ func (d *SSLDeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCer
}
listListenersReq := &alialb.ListListenersRequest{
MaxResults: tea.Int32(listListenersLimit),
NextToken: listListenersToken,
LoadBalancerIds: []*string{tea.String(d.config.LoadbalancerId)},
MaxResults: tea.Int32(100),
LoadBalancerIds: tea.StringSlice([]string{d.config.LoadbalancerId}),
ListenerProtocol: tea.String("QUIC"),
}
listListenersResp, err := d.sdkClients.ALB.ListListenersWithContext(context.TODO(), listListenersReq, &dara.RuntimeOptions{})
@@ -200,17 +201,19 @@ func (d *SSLDeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCer
return fmt.Errorf("failed to execute sdk request 'alb.ListListeners': %w", err)
}
if listListenersResp.Body.Listeners != nil {
for _, listener := range listListenersResp.Body.Listeners {
listenerIds = append(listenerIds, tea.StringValue(listener.ListenerId))
}
if listListenersResp.Body == nil {
break
}
for _, listener := range listListenersResp.Body.Listeners {
listenerIds = append(listenerIds, tea.StringValue(listener.ListenerId))
}
if len(listListenersResp.Body.Listeners) == 0 || listListenersResp.Body.NextToken == nil {
break
} else {
listListenersToken = listListenersResp.Body.NextToken
}
listListenersToken = listListenersResp.Body.NextToken
}
// 遍历更新监听证书
@@ -286,8 +289,7 @@ func (d *SSLDeployerProvider) updateListenerCertificate(ctx context.Context, clo
// 查询监听证书列表
// REF: https://help.aliyun.com/zh/slb/application-load-balancer/developer-reference/api-alb-2020-06-16-listlistenercertificates
listenerCertificates := make([]alialb.ListListenerCertificatesResponseBodyCertificates, 0)
listListenerCertificatesLimit := int32(100)
var listListenerCertificatesToken *string = nil
listListenerCertificatesToken := (*string)(nil)
for {
select {
case <-ctx.Done():
@@ -297,7 +299,7 @@ func (d *SSLDeployerProvider) updateListenerCertificate(ctx context.Context, clo
listListenerCertificatesReq := &alialb.ListListenerCertificatesRequest{
NextToken: listListenerCertificatesToken,
MaxResults: tea.Int32(listListenerCertificatesLimit),
MaxResults: tea.Int32(100),
ListenerId: tea.String(cloudListenerId),
CertificateType: tea.String("Server"),
}
@@ -307,17 +309,19 @@ func (d *SSLDeployerProvider) updateListenerCertificate(ctx context.Context, clo
return fmt.Errorf("failed to execute sdk request 'alb.ListListenerCertificates': %w", err)
}
if listListenerCertificatesResp.Body.Certificates != nil {
for _, listenerCertificate := range listListenerCertificatesResp.Body.Certificates {
listenerCertificates = append(listenerCertificates, *listenerCertificate)
}
if listListenerCertificatesResp.Body == nil {
break
}
for _, listenerCertificate := range listListenerCertificatesResp.Body.Certificates {
listenerCertificates = append(listenerCertificates, *listenerCertificate)
}
if len(listListenerCertificatesResp.Body.Certificates) == 0 || listListenerCertificatesResp.Body.NextToken == nil {
break
} else {
listListenerCertificatesToken = listListenerCertificatesResp.Body.NextToken
}
listListenerCertificatesToken = listListenerCertificatesResp.Body.NextToken
}
// 查询监听证书,并找出需要解除关联的证书
@@ -146,52 +146,10 @@ func (d *SSLDeployerProvider) deployToCloudNative(ctx context.Context, certPEM s
return errors.New("config `domain` is required")
}
// 查询域名列表,获取域名 ID
// REF: https://help.aliyun.com/zh/api-gateway/cloud-native-api-gateway/developer-reference/api-apig-2024-03-27-listdomains
var domainId string
listDomainsPageNumber := int32(1)
listDomainsPageSize := int32(10)
for {
select {
case <-ctx.Done():
return ctx.Err()
default:
}
listDomainsReq := &aliapig.ListDomainsRequest{
ResourceGroupId: lo.EmptyableToPtr(d.config.ResourceGroupId),
GatewayId: tea.String(d.config.GatewayId),
NameLike: tea.String(d.config.Domain),
PageNumber: tea.Int32(listDomainsPageNumber),
PageSize: tea.Int32(listDomainsPageSize),
}
listDomainsResp, err := d.sdkClients.CloudNativeAPIGateway.ListDomainsWithContext(context.TODO(), listDomainsReq, make(map[string]*string), &dara.RuntimeOptions{})
d.logger.Debug("sdk request 'apig.ListDomains'", slog.Any("request", listDomainsReq), slog.Any("response", listDomainsResp))
if err != nil {
return fmt.Errorf("failed to execute sdk request 'apig.ListDomains': %w", err)
}
if listDomainsResp.Body.Data.Items != nil {
for _, domainInfo := range listDomainsResp.Body.Data.Items {
if strings.EqualFold(tea.StringValue(domainInfo.Name), d.config.Domain) {
domainId = tea.StringValue(domainInfo.DomainId)
break
}
}
if domainId != "" {
break
}
}
if listDomainsResp.Body.Data.Items == nil || len(listDomainsResp.Body.Data.Items) < int(listDomainsPageSize) {
break
} else {
listDomainsPageNumber++
}
}
if domainId == "" {
return errors.New("domain not found")
// 获取域名 ID
domainId, err := d.findCloudNativeDomainIdByDomain(ctx, d.config.Domain)
if err != nil {
return err
}
// 查询域名
@@ -232,6 +190,51 @@ func (d *SSLDeployerProvider) deployToCloudNative(ctx context.Context, certPEM s
return nil
}
func (d *SSLDeployerProvider) findCloudNativeDomainIdByDomain(ctx context.Context, domain string) (string, error) {
// 查询域名列表
// REF: https://help.aliyun.com/zh/api-gateway/cloud-native-api-gateway/developer-reference/api-apig-2024-03-27-listdomains
listDomainsPageNumber := 1
listDomainsPageSize := 10
for {
select {
case <-ctx.Done():
return "", ctx.Err()
default:
}
listDomainsReq := &aliapig.ListDomainsRequest{
ResourceGroupId: lo.EmptyableToPtr(d.config.ResourceGroupId),
GatewayId: tea.String(d.config.GatewayId),
NameLike: tea.String(d.config.Domain),
PageNumber: tea.Int32(int32(listDomainsPageNumber)),
PageSize: tea.Int32(int32(listDomainsPageSize)),
}
listDomainsResp, err := d.sdkClients.CloudNativeAPIGateway.ListDomainsWithContext(context.TODO(), listDomainsReq, make(map[string]*string), &dara.RuntimeOptions{})
d.logger.Debug("sdk request 'apig.ListDomains'", slog.Any("request", listDomainsReq), slog.Any("response", listDomainsResp))
if err != nil {
return "", fmt.Errorf("failed to execute sdk request 'apig.ListDomains': %w", err)
}
if listDomainsResp.Body == nil || listDomainsResp.Body.Data == nil {
break
}
for _, domainItem := range listDomainsResp.Body.Data.Items {
if strings.EqualFold(tea.StringValue(domainItem.Name), d.config.Domain) {
return tea.StringValue(domainItem.DomainId), nil
}
}
if len(listDomainsResp.Body.Data.Items) < listDomainsPageSize {
break
}
listDomainsPageNumber++
}
return "", fmt.Errorf("could not find domain '%s'", domain)
}
func createSDKClients(accessKeyId, accessKeySecret, region string) (*wSDKClients, error) {
// 接入点一览 https://api.aliyun.com/product/APIG
var cloudNativeAPIGEndpoint string
@@ -146,11 +146,10 @@ func (d *SSLDeployerProvider) Deploy(ctx context.Context, certPEM string, privke
return nil, fmt.Errorf("failed to execute sdk request 'cas.DescribeDeploymentJob': %w", err)
}
if describeDeploymentJobResp.Body.Status == nil || *describeDeploymentJobResp.Body.Status == "editing" {
status := tea.StringValue(describeDeploymentJobResp.Body.Status)
if status == "" || status == "editing" {
return nil, errors.New("unexpected aliyun deployment job status")
}
if *describeDeploymentJobResp.Body.Status == "success" || *describeDeploymentJobResp.Body.Status == "error" {
} else if status == "success" || status == "error" {
break
}
@@ -187,8 +187,8 @@ func (d *SSLDeployerProvider) getAllDomains(ctx context.Context) ([]string, erro
// 查询域名列表
// REF: https://help.aliyun.com/zh/cdn/developer-reference/api-cdn-2018-05-10-describeuserdomains
describeUserDomainsPageNumber := int32(1)
describeUserDomainsPageSize := int32(500)
describeUserDomainsPageNumber := 1
describeUserDomainsPageSize := 500
for {
select {
case <-ctx.Done():
@@ -198,8 +198,8 @@ func (d *SSLDeployerProvider) getAllDomains(ctx context.Context) ([]string, erro
describeUserDomainsReq := &alicdn.DescribeUserDomainsRequest{
ResourceGroupId: lo.EmptyableToPtr(d.config.ResourceGroupId),
PageNumber: tea.Int32(describeUserDomainsPageNumber),
PageSize: tea.Int32(describeUserDomainsPageSize),
PageNumber: tea.Int32(int32(describeUserDomainsPageNumber)),
PageSize: tea.Int32(int32(describeUserDomainsPageSize)),
}
describeUserDomainsResp, err := d.sdkClient.DescribeUserDomainsWithContext(ctx, describeUserDomainsReq, &dara.RuntimeOptions{})
d.logger.Debug("sdk request 'cdn.DescribeUserDomains'", slog.Any("request", describeUserDomainsReq), slog.Any("response", describeUserDomainsResp))
@@ -207,22 +207,24 @@ func (d *SSLDeployerProvider) getAllDomains(ctx context.Context) ([]string, erro
return nil, fmt.Errorf("failed to execute sdk request 'cdn.DescribeUserDomains': %w", err)
}
if describeUserDomainsResp.Body.Domains != nil {
ignoredStatuses := []string{"offline", "checking", "check_failed", "stopping", "deleting"}
for _, domainInfo := range describeUserDomainsResp.Body.Domains.PageData {
if lo.Contains(ignoredStatuses, tea.StringValue(domainInfo.DomainStatus)) {
continue
}
domains = append(domains, tea.StringValue(domainInfo.DomainName))
}
}
if len(describeUserDomainsResp.Body.Domains.PageData) < int(describeUserDomainsPageNumber) {
if describeUserDomainsResp.Body == nil || describeUserDomainsResp.Body.Domains == nil {
break
} else {
describeUserDomainsPageNumber++
}
ignoredStatuses := []string{"offline", "checking", "check_failed", "stopping", "deleting"}
for _, domainItem := range describeUserDomainsResp.Body.Domains.PageData {
if lo.Contains(ignoredStatuses, tea.StringValue(domainItem.DomainStatus)) {
continue
}
domains = append(domains, tea.StringValue(domainItem.DomainName))
}
if len(describeUserDomainsResp.Body.Domains.PageData) < describeUserDomainsPageSize {
break
}
describeUserDomainsPageNumber++
}
return domains, nil
@@ -132,8 +132,7 @@ func (d *SSLDeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCer
// 查询 HTTPS 监听列表
// REF: https://help.aliyun.com/zh/slb/classic-load-balancer/developer-reference/api-slb-2014-05-15-describeloadbalancerlisteners
listenerPorts := make([]int32, 0)
describeLoadBalancerListenersLimit := int32(100)
var describeLoadBalancerListenersToken *string = nil
describeLoadBalancerListenersToken := (*string)(nil)
for {
select {
case <-ctx.Done():
@@ -143,9 +142,9 @@ func (d *SSLDeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCer
describeLoadBalancerListenersReq := &alislb.DescribeLoadBalancerListenersRequest{
RegionId: tea.String(d.config.Region),
MaxResults: tea.Int32(describeLoadBalancerListenersLimit),
NextToken: describeLoadBalancerListenersToken,
LoadBalancerId: []*string{tea.String(d.config.LoadbalancerId)},
MaxResults: tea.Int32(100),
LoadBalancerId: tea.StringSlice([]string{d.config.LoadbalancerId}),
ListenerProtocol: tea.String("https"),
}
describeLoadBalancerListenersResp, err := d.sdkClient.DescribeLoadBalancerListeners(describeLoadBalancerListenersReq)
@@ -154,17 +153,19 @@ func (d *SSLDeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCer
return fmt.Errorf("failed to execute sdk request 'slb.DescribeLoadBalancerListeners': %w", err)
}
if describeLoadBalancerListenersResp.Body.Listeners != nil {
for _, listener := range describeLoadBalancerListenersResp.Body.Listeners {
listenerPorts = append(listenerPorts, *listener.ListenerPort)
}
if describeLoadBalancerListenersResp.Body == nil {
break
}
for _, listener := range describeLoadBalancerListenersResp.Body.Listeners {
listenerPorts = append(listenerPorts, *listener.ListenerPort)
}
if len(describeLoadBalancerListenersResp.Body.Listeners) == 0 || describeLoadBalancerListenersResp.Body.NextToken == nil {
break
} else {
describeLoadBalancerListenersToken = describeLoadBalancerListenersResp.Body.NextToken
}
describeLoadBalancerListenersToken = describeLoadBalancerListenersResp.Body.NextToken
}
// 遍历更新监听证书
@@ -187,8 +187,8 @@ func (d *SSLDeployerProvider) getAllDomains(ctx context.Context) ([]string, erro
// 查询域名列表
// REF: https://help.aliyun.com/zh/edge-security-acceleration/dcdn/developer-reference/api-dcdn-2018-01-15-describedcdnuserdomains
describeUserDomainsPageNumber := int32(1)
describeUserDomainsPageSize := int32(500)
describeUserDomainsPageNumber := 1
describeUserDomainsPageSize := 500
for {
select {
case <-ctx.Done():
@@ -199,8 +199,8 @@ func (d *SSLDeployerProvider) getAllDomains(ctx context.Context) ([]string, erro
describeDcdnUserDomainsReq := &alidcdn.DescribeDcdnUserDomainsRequest{
ResourceGroupId: lo.EmptyableToPtr(d.config.ResourceGroupId),
CheckDomainShow: tea.Bool(true),
PageNumber: tea.Int32(describeUserDomainsPageNumber),
PageSize: tea.Int32(describeUserDomainsPageSize),
PageNumber: tea.Int32(int32(describeUserDomainsPageNumber)),
PageSize: tea.Int32(int32(describeUserDomainsPageSize)),
}
describeDcdnUserDomainsResp, err := d.sdkClient.DescribeDcdnUserDomainsWithContext(ctx, describeDcdnUserDomainsReq, &dara.RuntimeOptions{})
d.logger.Debug("sdk request 'dcdn.DescribeDcdnUserDomains'", slog.Any("request", describeDcdnUserDomainsReq), slog.Any("response", describeDcdnUserDomainsResp))
@@ -208,20 +208,24 @@ func (d *SSLDeployerProvider) getAllDomains(ctx context.Context) ([]string, erro
return nil, fmt.Errorf("failed to execute sdk request 'dcdn.DescribeDcdnUserDomains': %w", err)
}
if describeDcdnUserDomainsResp.Body == nil || describeDcdnUserDomainsResp.Body.Domains == nil {
break
}
ignoredStatuses := []string{"offline", "checking", "check_failed", "stopping", "deleting"}
for _, domainInfo := range describeDcdnUserDomainsResp.Body.Domains.PageData {
if lo.Contains(ignoredStatuses, tea.StringValue(domainInfo.DomainStatus)) {
for _, domainItem := range describeDcdnUserDomainsResp.Body.Domains.PageData {
if lo.Contains(ignoredStatuses, tea.StringValue(domainItem.DomainStatus)) {
continue
}
domains = append(domains, tea.StringValue(domainInfo.DomainName))
domains = append(domains, tea.StringValue(domainItem.DomainName))
}
if len(describeDcdnUserDomainsResp.Body.Domains.PageData) < int(describeUserDomainsPageNumber) {
if len(describeDcdnUserDomainsResp.Body.Domains.PageData) < describeUserDomainsPageNumber {
break
} else {
describeUserDomainsPageNumber++
}
describeUserDomainsPageNumber++
}
return domains, nil
@@ -119,8 +119,8 @@ func (d *SSLDeployerProvider) deployToAccelerator(ctx context.Context, cloudCert
// 查询 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)
listListenersPageNumber := 1
listListenersPageSize := 50
for {
select {
case <-ctx.Done():
@@ -131,8 +131,8 @@ func (d *SSLDeployerProvider) deployToAccelerator(ctx context.Context, cloudCert
listListenersReq := &aliga.ListListenersRequest{
RegionId: tea.String("cn-hangzhou"),
AcceleratorId: tea.String(d.config.AcceleratorId),
PageNumber: tea.Int32(listListenersPageNumber),
PageSize: tea.Int32(listListenersPageSize),
PageNumber: tea.Int32(int32(listListenersPageNumber)),
PageSize: tea.Int32(int32(listListenersPageSize)),
}
listListenersResp, err := d.sdkClient.ListListeners(listListenersReq)
d.logger.Debug("sdk request 'ga.ListListeners'", slog.Any("request", listListenersReq), slog.Any("response", listListenersResp))
@@ -140,19 +140,21 @@ func (d *SSLDeployerProvider) deployToAccelerator(ctx context.Context, cloudCert
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 listListenersResp.Body == nil {
break
}
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) {
if len(listListenersResp.Body.Listeners) < listListenersPageSize {
break
} else {
listListenersPageNumber++
}
listListenersPageNumber++
}
// 遍历更新监听证书
@@ -200,9 +202,9 @@ func (d *SSLDeployerProvider) deployToListener(ctx context.Context, cloudCertId
func (d *SSLDeployerProvider) 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
listenerDefaultCertificate := (*aliga.ListListenerCertificatesResponseBodyCertificates)(nil)
listenerAdditionalCertificates := make([]*aliga.ListListenerCertificatesResponseBodyCertificates, 0)
listListenerCertificatesNextToken := (*string)(nil)
for {
listListenerCertificatesReq := &aliga.ListListenerCertificatesRequest{
RegionId: tea.String("cn-hangzhou"),
@@ -217,21 +219,23 @@ func (d *SSLDeployerProvider) updateListenerCertificate(ctx context.Context, clo
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 == nil {
break
}
for _, certItem := range listListenerCertificatesResp.Body.Certificates {
if tea.BoolValue(certItem.IsDefault) {
listenerDefaultCertificate = certItem
} else {
listenerAdditionalCertificates = append(listenerAdditionalCertificates, certItem)
}
}
if listListenerCertificatesResp.Body.NextToken == nil {
if len(listListenerCertificatesResp.Body.Certificates) == 0 || listListenerCertificatesResp.Body.NextToken == nil {
break
} else {
listListenerCertificatesNextToken = listListenerCertificatesResp.Body.NextToken
}
listListenerCertificatesNextToken = listListenerCertificatesResp.Body.NextToken
}
if d.config.Domain == "" {
@@ -133,8 +133,7 @@ func (d *SSLDeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCer
// 查询 TCPSSL 监听列表
// REF: https://help.aliyun.com/zh/slb/network-load-balancer/developer-reference/api-nlb-2022-04-30-listlisteners
listenerIds := make([]string, 0)
listListenersLimit := int32(100)
var listListenersToken *string = nil
listListenersToken := (*string)(nil)
for {
select {
case <-ctx.Done():
@@ -143,9 +142,9 @@ func (d *SSLDeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCer
}
listListenersReq := &alinlb.ListListenersRequest{
MaxResults: tea.Int32(listListenersLimit),
NextToken: listListenersToken,
LoadBalancerIds: []*string{tea.String(d.config.LoadbalancerId)},
MaxResults: tea.Int32(100),
LoadBalancerIds: tea.StringSlice([]string{d.config.LoadbalancerId}),
ListenerProtocol: tea.String("TCPSSL"),
}
listListenersResp, err := d.sdkClient.ListListenersWithContext(context.TODO(), listListenersReq, &dara.RuntimeOptions{})
@@ -154,17 +153,19 @@ func (d *SSLDeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCer
return fmt.Errorf("failed to execute sdk request 'nlb.ListListeners': %w", err)
}
if listListenersResp.Body.Listeners != nil {
for _, listener := range listListenersResp.Body.Listeners {
listenerIds = append(listenerIds, tea.StringValue(listener.ListenerId))
}
if listListenersResp.Body == nil {
break
}
for _, listener := range listListenersResp.Body.Listeners {
listenerIds = append(listenerIds, tea.StringValue(listener.ListenerId))
}
if len(listListenersResp.Body.Listeners) == 0 || listListenersResp.Body.NextToken == nil {
break
} else {
listListenersToken = listListenersResp.Body.NextToken
}
listListenersToken = listListenersResp.Body.NextToken
}
// 遍历更新监听证书
@@ -255,7 +255,7 @@ func (d *SSLDeployerProvider) updateHttpsListenerCertificate(ctx context.Context
if err != nil {
return fmt.Errorf("failed to execute sdk request 'appblb.DescribeAppHTTPSListeners': %w", err)
} else if len(describeAppHTTPSListenersResp.ListenerList) == 0 {
return fmt.Errorf("listener %s:%d not found", cloudLoadbalancerId, cloudHttpsListenerPort)
return fmt.Errorf("cloud not find listener '%s:%d'", cloudLoadbalancerId, cloudHttpsListenerPort)
}
if d.config.Domain == "" {
@@ -255,7 +255,7 @@ func (d *SSLDeployerProvider) updateHttpsListenerCertificate(ctx context.Context
if err != nil {
return fmt.Errorf("failed to execute sdk request 'blb.DescribeHTTPSListeners': %w", err)
} else if len(describeHTTPSListenersResp.ListenerList) == 0 {
return fmt.Errorf("listener %s:%d not found", cloudLoadbalancerId, cloudHttpsListenerPort)
return fmt.Errorf("could not find listener '%s:%d'", cloudLoadbalancerId, cloudHttpsListenerPort)
}
if d.config.Domain == "" {
@@ -171,9 +171,9 @@ func (d *SSLDeployerProvider) getAllDomains(ctx context.Context) ([]string, erro
if listDomainsNextMarker == "" {
break
} else {
listDomainsMarker = listDomainsNextMarker
}
listDomainsMarker = listDomainsNextMarker
}
return domains, nil
@@ -19,6 +19,9 @@ import (
type SSLDeployerProviderConfig struct {
// 白山云 API Token。
ApiToken string `json:"apiToken"`
// 域名匹配模式。暂时只支持精确匹配。
// 零值时默认值 [DOMAIN_MATCH_PATTERN_EXACT]。
DomainMatchPattern string `json:"domainMatchPattern,omitempty"`
// 加速域名(支持泛域名)。
Domain string `json:"domain"`
// 证书 ID。
@@ -103,7 +106,7 @@ func (d *SSLDeployerProvider) Deploy(ctx context.Context, certPEM string, privke
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'baishan.GetDomainConfig': %w", err)
} else if len(getDomainConfigResp.Data) == 0 {
return nil, fmt.Errorf("domain %s not found", d.config.Domain)
return nil, fmt.Errorf("could not find domain '%s'", d.config.Domain)
}
// 设置域名配置
@@ -49,8 +49,9 @@ func TestDeploy(t *testing.T) {
}, "\n"))
deployer, err := provider.NewSSLDeployerProvider(&provider.SSLDeployerProviderConfig{
ApiToken: fApiToken,
Domain: fDomain,
ApiToken: fApiToken,
DomainMatchPattern: provider.DOMAIN_MATCH_PATTERN_EXACT,
Domain: fDomain,
})
if err != nil {
t.Errorf("err: %+v", err)
@@ -0,0 +1,6 @@
package baishancdn
const (
// 匹配模式:精确匹配。
DOMAIN_MATCH_PATTERN_EXACT = "exact"
)
@@ -74,48 +74,10 @@ func (d *SSLDeployerProvider) Deploy(ctx context.Context, certPEM string, privke
return nil, fmt.Errorf("failed to execute sdk request 'bt.PanelGetConfig': %w", err)
}
// 查询网站列表,获取网站 ID
var siteId int32
datalistGetDataListPage := int32(1)
datalistGetDataListLimit := int32(10)
for {
select {
case <-ctx.Done():
return nil, ctx.Err()
default:
}
datalistGetDataListReq := &btsdk.DatalistGetDataListRequest{
Table: lo.ToPtr("sites"),
SearchString: lo.ToPtr(d.config.SiteName),
Page: lo.ToPtr(datalistGetDataListPage),
Limit: lo.ToPtr(datalistGetDataListLimit),
}
datalistGetDataListResp, err := d.sdkClient.DatalistGetDataList(datalistGetDataListReq)
d.logger.Debug("sdk request 'bt.DatalistGetDataList'", slog.Any("request", datalistGetDataListReq), slog.Any("response", datalistGetDataListResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'bt.DatalistGetDataList': %w", err)
}
for _, siteInfo := range datalistGetDataListResp.Data {
if strings.EqualFold(siteInfo.Name, d.config.SiteName) {
siteId = siteInfo.Id
break
}
}
if siteId != 0 {
break
}
if len(datalistGetDataListResp.Data) < int(datalistGetDataListLimit) {
break
} else {
datalistGetDataListPage++
}
}
if siteId == 0 {
return nil, errors.New("website not found")
// 获取网站 ID
siteId, err := d.findSiteIdByName(ctx, d.config.SiteName)
if err != nil {
return nil, err
}
if panelGetConfigResp.Site != nil && strings.EqualFold(panelGetConfigResp.Site.WebServer, "iis") {
@@ -174,6 +136,45 @@ func (d *SSLDeployerProvider) Deploy(ctx context.Context, certPEM string, privke
return &core.SSLDeployResult{}, nil
}
func (d *SSLDeployerProvider) findSiteIdByName(ctx context.Context, siteName string) (int32, error) {
// 查询网站列表
datalistGetDataListPage := 1
datalistGetDataListLimit := 10
for {
select {
case <-ctx.Done():
return 0, ctx.Err()
default:
}
datalistGetDataListReq := &btsdk.DatalistGetDataListRequest{
Table: lo.ToPtr("sites"),
SearchString: lo.ToPtr(d.config.SiteName),
Page: lo.ToPtr(int32(datalistGetDataListPage)),
Limit: lo.ToPtr(int32(datalistGetDataListLimit)),
}
datalistGetDataListResp, err := d.sdkClient.DatalistGetDataList(datalistGetDataListReq)
d.logger.Debug("sdk request 'bt.DatalistGetDataList'", slog.Any("request", datalistGetDataListReq), slog.Any("response", datalistGetDataListResp))
if err != nil {
return 0, fmt.Errorf("failed to execute sdk request 'bt.DatalistGetDataList': %w", err)
}
for _, siteItem := range datalistGetDataListResp.Data {
if strings.EqualFold(siteItem.Name, d.config.SiteName) {
return siteItem.Id, nil
}
}
if len(datalistGetDataListResp.Data) < datalistGetDataListLimit {
break
}
datalistGetDataListPage++
}
return 0, fmt.Errorf("could not find site '%s'", siteName)
}
func createSDKClient(serverUrl, apiKey string, skipTlsVerify bool) (*btsdk.Client, error) {
client, err := btsdk.NewClient(serverUrl, apiKey)
if err != nil {
@@ -68,46 +68,10 @@ func (d *SSLDeployerProvider) Deploy(ctx context.Context, certPEM string, privke
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 := &btwafsdk.GetSiteListRequest{
SiteName: lo.ToPtr(d.config.SiteName),
Page: lo.ToPtr(getSitListPage),
PageSize: lo.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")
// 获取网站 ID
siteId, err := d.findSiteIdByName(ctx, d.config.SiteName)
if err != nil {
return nil, err
}
// 修改站点配置
@@ -132,6 +96,48 @@ func (d *SSLDeployerProvider) Deploy(ctx context.Context, certPEM string, privke
return &core.SSLDeployResult{}, nil
}
func (d *SSLDeployerProvider) findSiteIdByName(ctx context.Context, siteName string) (string, error) {
// 查询网站列表
getSiteListPage := 1
getSiteListPageSize := 100
for {
select {
case <-ctx.Done():
return "", ctx.Err()
default:
}
getSiteListReq := &btwafsdk.GetSiteListRequest{
SiteName: lo.ToPtr(d.config.SiteName),
Page: lo.ToPtr(int32(getSiteListPage)),
PageSize: lo.ToPtr(int32(getSiteListPageSize)),
}
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 "", fmt.Errorf("failed to execute sdk request 'bt.GetSiteList': %w", err)
}
if getSiteListResp.Result == nil {
break
}
for _, siteItem := range getSiteListResp.Result.List {
if siteItem.SiteName == d.config.SiteName {
return siteItem.SiteId, nil
}
}
if len(getSiteListResp.Result.List) < getSiteListPageSize {
break
}
getSiteListPage++
}
return "", fmt.Errorf("could not find site '%s'", siteName)
}
func createSDKClient(serverUrl, apiKey string, skipTlsVerify bool) (*btwafsdk.Client, error) {
client, err := btwafsdk.NewClient(serverUrl, apiKey)
if err != nil {
@@ -16,7 +16,7 @@ type SSLDeployerProviderConfig struct {
ApiKey string `json:"apiKey"`
// Bunny Pull Zone ID。
PullZoneId string `json:"pullZoneId"`
// Bunny CDN Hostname(支持泛域名)。
// Bunny CDN Hostname。
Hostname string `json:"hostname"`
}
@@ -155,8 +155,8 @@ func (d *SSLDeployerProvider) getMatchedDomainsByWildcard(ctx context.Context, w
// 查询加速域名列表,获取匹配的域名
// REF: https://docs.byteplus.com/en/docs/byteplus-cdn/ListCdnDomains_en-us
listCdnDomainsPageNum := int64(1)
listCdnDomainsPageSize := int64(100)
listCdnDomainsPageNum := 1
listCdnDomainsPageSize := 100
for {
select {
case <-ctx.Done():
@@ -167,8 +167,8 @@ func (d *SSLDeployerProvider) getMatchedDomainsByWildcard(ctx context.Context, w
listCdnDomainsReq := &bpcdn.ListCdnDomainsRequest{
Domain: bp.String(strings.TrimPrefix(wildcardDomain, "*.")),
Status: bp.String("online"),
PageNum: bp.Int64(listCdnDomainsPageNum),
PageSize: bp.Int64(listCdnDomainsPageSize),
PageNum: bp.Int64(int64(listCdnDomainsPageNum)),
PageSize: bp.Int64(int64(listCdnDomainsPageSize)),
}
listCdnDomainsResp, err := d.sdkClient.ListCdnDomains(listCdnDomainsReq)
d.logger.Debug("sdk request 'cdn.ListCdnDomains'", slog.Any("request", listCdnDomainsReq), slog.Any("response", listCdnDomainsResp))
@@ -176,17 +176,17 @@ func (d *SSLDeployerProvider) getMatchedDomainsByWildcard(ctx context.Context, w
return nil, fmt.Errorf("failed to execute sdk request 'cdn.ListCdnDomains': %w", err)
}
for _, domainInfo := range listCdnDomainsResp.Result.Data {
if xcerthostname.IsMatch(wildcardDomain, domainInfo.Domain) {
domains = append(domains, domainInfo.Domain)
for _, domainItem := range listCdnDomainsResp.Result.Data {
if xcerthostname.IsMatch(wildcardDomain, domainItem.Domain) {
domains = append(domains, domainItem.Domain)
}
}
if len(listCdnDomainsResp.Result.Data) < int(listCdnDomainsPageSize) {
if len(listCdnDomainsResp.Result.Data) < listCdnDomainsPageSize {
break
} else {
listCdnDomainsPageSize++
}
listCdnDomainsPageSize++
}
return domains, nil
@@ -171,8 +171,8 @@ func (d *SSLDeployerProvider) getAllDomains(ctx context.Context) ([]string, erro
// 查询域名列表
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=113&api=13816&data=174&isNormal=1&vid=167
queryDomainsPage := int32(1)
queryDomainsPageSize := int32(100)
queryDomainsPage := 1
queryDomainsPageSize := 100
for {
select {
case <-ctx.Done():
@@ -181,8 +181,8 @@ func (d *SSLDeployerProvider) getAllDomains(ctx context.Context) ([]string, erro
}
queryDomainsReq := &ctyunao.QueryDomainsRequest{
Page: lo.ToPtr(queryDomainsPage),
PageSize: lo.ToPtr(queryDomainsPageSize),
Page: lo.ToPtr(int32(queryDomainsPage)),
PageSize: lo.ToPtr(int32(queryDomainsPageSize)),
ProductCode: lo.ToPtr("020"),
}
queryDomainsResp, err := d.sdkClient.QueryDomains(queryDomainsReq)
@@ -191,22 +191,24 @@ func (d *SSLDeployerProvider) getAllDomains(ctx context.Context) ([]string, erro
return nil, fmt.Errorf("failed to execute sdk request 'cdn.QueryDomains': %w", err)
}
if queryDomainsResp.ReturnObj != nil {
ignoredStatuses := []int32{1, 5, 6, 7, 8, 9, 11, 12}
for _, domainInfo := range queryDomainsResp.ReturnObj.Results {
if lo.Contains(ignoredStatuses, domainInfo.Status) {
continue
}
domains = append(domains, domainInfo.Domain)
}
}
if queryDomainsResp.ReturnObj == nil || len(queryDomainsResp.ReturnObj.Results) < int(queryDomainsPageSize) {
if queryDomainsResp.ReturnObj == nil {
break
} else {
queryDomainsPage++
}
ignoredStatuses := []int32{1, 5, 6, 7, 8, 9, 11, 12}
for _, domainItem := range queryDomainsResp.ReturnObj.Results {
if lo.Contains(ignoredStatuses, domainItem.Status) {
continue
}
domains = append(domains, domainItem.Domain)
}
if len(queryDomainsResp.ReturnObj.Results) < queryDomainsPageSize {
break
}
queryDomainsPage++
}
return domains, nil
@@ -170,8 +170,8 @@ func (d *SSLDeployerProvider) getAllDomains(ctx context.Context) ([]string, erro
// 查询域名列表
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=108&api=11307&data=161&isNormal=1&vid=154
queryDomainListPage := int32(1)
queryDomainListPageSize := int32(100)
queryDomainListPage := 1
queryDomainListPageSize := 100
for {
select {
case <-ctx.Done():
@@ -180,8 +180,8 @@ func (d *SSLDeployerProvider) getAllDomains(ctx context.Context) ([]string, erro
}
queryDomainListReq := &ctyuncdn.QueryDomainListRequest{
Page: lo.ToPtr(queryDomainListPage),
PageSize: lo.ToPtr(queryDomainListPageSize),
Page: lo.ToPtr(int32(queryDomainListPage)),
PageSize: lo.ToPtr(int32(queryDomainListPageSize)),
ProductCode: lo.ToPtr("020"),
}
queryDomainListResp, err := d.sdkClient.QueryDomainList(queryDomainListReq)
@@ -190,26 +190,28 @@ func (d *SSLDeployerProvider) getAllDomains(ctx context.Context) ([]string, erro
return nil, fmt.Errorf("failed to execute sdk request 'cdn.QueryDomainList': %w", err)
}
if queryDomainListResp.ReturnObj != nil {
filteredProductCodes := []string{"001", "003", "004", "008"}
ignoredStatuses := []int32{1, 5, 6, 7, 8, 9, 11, 12}
for _, domainInfo := range queryDomainListResp.ReturnObj.Results {
if !lo.Contains(filteredProductCodes, domainInfo.ProductCode) {
continue
}
if lo.Contains(ignoredStatuses, domainInfo.Status) {
continue
}
domains = append(domains, domainInfo.Domain)
}
}
if queryDomainListResp.ReturnObj == nil || len(queryDomainListResp.ReturnObj.Results) < int(queryDomainListPageSize) {
if queryDomainListResp.ReturnObj == nil {
break
} else {
queryDomainListPage++
}
filteredProductCodes := []string{"001", "003", "004", "008"}
ignoredStatuses := []int32{1, 5, 6, 7, 8, 9, 11, 12}
for _, domainItem := range queryDomainListResp.ReturnObj.Results {
if !lo.Contains(filteredProductCodes, domainItem.ProductCode) {
continue
}
if lo.Contains(ignoredStatuses, domainItem.Status) {
continue
}
domains = append(domains, domainItem.Domain)
}
if len(queryDomainListResp.ReturnObj.Results) < queryDomainListPageSize {
break
}
queryDomainListPage++
}
return domains, nil
@@ -111,13 +111,7 @@ func (d *SSLDeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCer
// 查询监听列表
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=24&api=5654&data=88&isNormal=1&vid=82
listenerIds := make([]string, 0)
for {
select {
case <-ctx.Done():
return ctx.Err()
default:
}
{
listListenersReq := &ctyunelb.ListListenersRequest{
RegionID: lo.ToPtr(d.config.RegionId),
LoadBalancerID: lo.ToPtr(d.config.LoadbalancerId),
@@ -133,8 +127,6 @@ func (d *SSLDeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCer
listenerIds = append(listenerIds, listener.ID)
}
}
break
}
// 遍历更新监听证书
@@ -170,8 +170,8 @@ func (d *SSLDeployerProvider) getAllDomains(ctx context.Context) ([]string, erro
// 查询域名列表
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=112&api=10852&data=173&isNormal=1&vid=166
queryDomainsPage := int32(1)
queryDomainsPageSize := int32(100)
queryDomainsPage := 1
queryDomainsPageSize := 100
for {
select {
case <-ctx.Done():
@@ -180,8 +180,8 @@ func (d *SSLDeployerProvider) getAllDomains(ctx context.Context) ([]string, erro
}
queryDomainListReq := &ctyunicdn.QueryDomainListRequest{
Page: lo.ToPtr(queryDomainsPage),
PageSize: lo.ToPtr(queryDomainsPageSize),
Page: lo.ToPtr(int32(queryDomainsPage)),
PageSize: lo.ToPtr(int32(queryDomainsPageSize)),
ProductCode: lo.ToPtr("006"),
}
queryDomainListResp, err := d.sdkClient.QueryDomainList(queryDomainListReq)
@@ -190,22 +190,24 @@ func (d *SSLDeployerProvider) getAllDomains(ctx context.Context) ([]string, erro
return nil, fmt.Errorf("failed to execute sdk request 'cdn.QueryDomainList': %w", err)
}
if queryDomainListResp.ReturnObj != nil {
ignoredStatuses := []int32{1, 5, 6, 7, 8, 9, 11, 12}
for _, domainInfo := range queryDomainListResp.ReturnObj.Results {
if lo.Contains(ignoredStatuses, domainInfo.Status) {
continue
}
domains = append(domains, domainInfo.Domain)
}
}
if queryDomainListResp.ReturnObj == nil || len(queryDomainListResp.ReturnObj.Results) < int(queryDomainsPageSize) {
if queryDomainListResp.ReturnObj == nil {
break
} else {
queryDomainsPage++
}
ignoredStatuses := []int32{1, 5, 6, 7, 8, 9, 11, 12}
for _, domainItem := range queryDomainListResp.ReturnObj.Results {
if lo.Contains(ignoredStatuses, domainItem.Status) {
continue
}
domains = append(domains, domainItem.Domain)
}
if len(queryDomainListResp.ReturnObj.Results) < queryDomainsPageSize {
break
}
queryDomainsPage++
}
return domains, nil
@@ -185,8 +185,8 @@ func (d *SSLDeployerProvider) getAllDomains(ctx context.Context) ([]string, erro
// 查询域名列表
// REF: https://support.huaweicloud.com/api-cdn/ListDomains.html
listDomainsPageNumber := int32(1)
listDomainsPageSize := int32(100)
listDomainsPageNumber := 1
listDomainsPageSize := 100
for {
select {
case <-ctx.Done():
@@ -196,8 +196,8 @@ func (d *SSLDeployerProvider) getAllDomains(ctx context.Context) ([]string, erro
listDomainsReq := &hccdnmodel.ListDomainsRequest{
EnterpriseProjectId: lo.EmptyableToPtr(d.config.EnterpriseProjectId),
PageNumber: lo.ToPtr(listDomainsPageNumber),
PageSize: lo.ToPtr(listDomainsPageSize),
PageNumber: lo.ToPtr(int32(listDomainsPageNumber)),
PageSize: lo.ToPtr(int32(listDomainsPageSize)),
}
listDomainsResp, err := d.sdkClient.ListDomains(listDomainsReq)
d.logger.Debug("sdk request 'cdn.ListDomains'", slog.Any("request", listDomainsReq), slog.Any("response", listDomainsResp))
@@ -205,22 +205,24 @@ func (d *SSLDeployerProvider) getAllDomains(ctx context.Context) ([]string, erro
return nil, fmt.Errorf("failed to execute sdk request 'cdn.ListDomains': %w", err)
}
if listDomainsResp.Domains != nil {
ignoredStatuses := []string{"offline", "checking", "check_failed", "deleting"}
for _, domainInfo := range *listDomainsResp.Domains {
if lo.Contains(ignoredStatuses, lo.FromPtr(domainInfo.DomainStatus)) {
continue
}
domains = append(domains, lo.FromPtr(domainInfo.DomainName))
}
}
if listDomainsResp.Domains == nil || len(*listDomainsResp.Domains) < int(listDomainsPageSize) {
if listDomainsResp.Domains == nil {
break
} else {
listDomainsPageNumber++
}
ignoredStatuses := []string{"offline", "checking", "check_failed", "deleting"}
for _, domainItem := range *listDomainsResp.Domains {
if lo.Contains(ignoredStatuses, lo.FromPtr(domainItem.DomainStatus)) {
continue
}
domains = append(domains, lo.FromPtr(domainItem.DomainName))
}
if len(*listDomainsResp.Domains) < listDomainsPageSize {
break
}
listDomainsPageNumber++
}
return domains, nil
@@ -160,8 +160,7 @@ func (d *SSLDeployerProvider) deployToLoadbalancer(ctx context.Context, certPEM
// 查询监听器列表
// REF: https://support.huaweicloud.com/api-elb/ListListeners.html
listenerIds := make([]string, 0)
listListenersLimit := int32(2000)
var listListenersMarker *string = nil
listListenersMarker := (*string)(nil)
for {
select {
case <-ctx.Done():
@@ -170,8 +169,8 @@ func (d *SSLDeployerProvider) deployToLoadbalancer(ctx context.Context, certPEM
}
listListenersReq := &hcelbmodel.ListListenersRequest{
Limit: lo.ToPtr(listListenersLimit),
Marker: listListenersMarker,
Limit: lo.ToPtr(int32(2000)),
Protocol: &[]string{"HTTPS", "TERMINATED_HTTPS"},
LoadbalancerId: &[]string{showLoadBalancerResp.Loadbalancer.Id},
}
@@ -184,17 +183,19 @@ func (d *SSLDeployerProvider) deployToLoadbalancer(ctx context.Context, certPEM
return fmt.Errorf("failed to execute sdk request 'elb.ListListeners': %w", err)
}
if listListenersResp.Listeners != nil {
for _, listener := range *listListenersResp.Listeners {
listenerIds = append(listenerIds, listener.Id)
}
if listListenersResp.Listeners == nil {
break
}
if listListenersResp.Listeners == nil || len(*listListenersResp.Listeners) < int(listListenersLimit) {
break
} else {
listListenersMarker = listListenersResp.PageInfo.NextMarker
for _, listener := range *listListenersResp.Listeners {
listenerIds = append(listenerIds, listener.Id)
}
if len(*listListenersResp.Listeners) == 0 || listListenersResp.PageInfo.NextMarker == nil {
break
}
listListenersMarker = listListenersResp.PageInfo.NextMarker
}
// 上传证书
@@ -174,8 +174,8 @@ func (d *SSLDeployerProvider) deployToCloudServer(ctx context.Context, certPEM s
// 查询云模式防护域名列表,获取防护域名 ID
// REF: https://support.huaweicloud.com/api-waf/ListHost.html
hostId := ""
listHostPage := int32(1)
listHostPageSize := int32(100)
listHostPage := 1
listHostPageSize := 100
for {
select {
case <-ctx.Done():
@@ -186,8 +186,8 @@ func (d *SSLDeployerProvider) deployToCloudServer(ctx context.Context, certPEM s
listHostReq := &hcwafmodel.ListHostRequest{
EnterpriseProjectId: lo.EmptyableToPtr(d.config.EnterpriseProjectId),
Hostname: lo.ToPtr(strings.TrimPrefix(d.config.Domain, "*")),
Page: lo.ToPtr(listHostPage),
Pagesize: lo.ToPtr(listHostPageSize),
Page: lo.ToPtr(int32(listHostPage)),
Pagesize: lo.ToPtr(int32(listHostPageSize)),
}
listHostResp, err := d.sdkClient.ListHost(listHostReq)
d.logger.Debug("sdk request 'waf.ListHost'", slog.Any("request", listHostReq), slog.Any("response", listHostResp))
@@ -195,23 +195,25 @@ func (d *SSLDeployerProvider) deployToCloudServer(ctx context.Context, certPEM s
return fmt.Errorf("failed to execute sdk request 'waf.ListHost': %w", err)
}
if listHostResp.Items != nil {
for _, hostItem := range *listHostResp.Items {
if strings.TrimPrefix(d.config.Domain, "*") == *hostItem.Hostname {
hostId = *hostItem.Id
break
}
if listHostResp.Items == nil {
break
}
for _, hostItem := range *listHostResp.Items {
if strings.TrimPrefix(d.config.Domain, "*") == *hostItem.Hostname {
hostId = *hostItem.Id
break
}
}
if listHostResp.Items == nil || len(*listHostResp.Items) < int(listHostPageSize) {
if len(*listHostResp.Items) < listHostPageSize {
break
} else {
listHostPage++
}
listHostPage++
}
if hostId == "" {
return errors.New("host not found")
return fmt.Errorf("could not find cloudserver host '%s'", d.config.Domain)
}
// 更新云模式防护域名的配置
@@ -249,8 +251,8 @@ func (d *SSLDeployerProvider) deployToPremiumHost(ctx context.Context, certPEM s
// 查询独享模式域名列表,获取防护域名 ID
// REF: https://support.huaweicloud.com/api-waf/ListPremiumHost.html
hostId := ""
listPremiumHostPage := int32(1)
listPremiumHostPageSize := int32(100)
listPremiumHostPage := 1
listPremiumHostPageSize := 100
for {
select {
case <-ctx.Done():
@@ -270,23 +272,25 @@ func (d *SSLDeployerProvider) deployToPremiumHost(ctx context.Context, certPEM s
return fmt.Errorf("failed to execute sdk request 'waf.ListPremiumHost': %w", err)
}
if listPremiumHostResp.Items != nil {
for _, hostItem := range *listPremiumHostResp.Items {
if strings.TrimPrefix(d.config.Domain, "*") == *hostItem.Hostname {
hostId = *hostItem.Id
break
}
if listPremiumHostResp.Items == nil {
break
}
for _, hostItem := range *listPremiumHostResp.Items {
if strings.TrimPrefix(d.config.Domain, "*") == *hostItem.Hostname {
hostId = *hostItem.Id
break
}
}
if listPremiumHostResp.Items == nil || len(*listPremiumHostResp.Items) < int(listPremiumHostPageSize) {
if len(*listPremiumHostResp.Items) < listPremiumHostPageSize {
break
} else {
listPremiumHostPage++
}
listPremiumHostPage++
}
if hostId == "" {
return errors.New("host not found")
return fmt.Errorf("could not find premium host '%s'", d.config.Domain)
}
// 修改独享模式域名配置
@@ -156,11 +156,11 @@ func (d *SSLDeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCer
}
}
if len(describeListenersResp.Result.Listeners) < int(describeListenersPageSize) {
if len(describeListenersResp.Result.Listeners) < describeListenersPageSize {
break
} else {
describeListenersPageNumber++
}
describeListenersPageNumber++
}
// 遍历更新监听器证书
@@ -236,7 +236,7 @@ func (d *SSLDeployerProvider) updateListenerCertificate(ctx context.Context, clo
return extCertSpec.Domain == d.config.Domain
})
if len(extCertSpecs) == 0 {
return errors.New("extension certificate spec not found")
return errors.New("could not find any extension certificates")
}
// 批量修改扩展证书
@@ -193,19 +193,19 @@ func (d *SSLDeployerProvider) getAllDomains(ctx context.Context) ([]string, erro
}
ignoredStatuses := []string{"offline"}
for _, domainInfo := range getDomainListResp.Result.Domains {
if lo.Contains(ignoredStatuses, domainInfo.Status) {
for _, domainItem := range getDomainListResp.Result.Domains {
if lo.Contains(ignoredStatuses, domainItem.Status) {
continue
}
domains = append(domains, domainInfo.Domain)
domains = append(domains, domainItem.Domain)
}
if len(getDomainListResp.Result.Domains) < getDomainListPageSize {
break
} else {
getDomainListPageNumber++
}
getDomainListPageNumber++
}
return domains, nil
@@ -58,42 +58,10 @@ func (d *SSLDeployerProvider) SetLogger(logger *slog.Logger) {
}
func (d *SSLDeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*core.SSLDeployResult, error) {
// 查询域名列表
// REF: https://docs.jdcloud.com/cn/video-on-demand/api/listdomains
var domainId int
listDomainsPageNumber := 1
listDomainsPageSize := 100
for {
select {
case <-ctx.Done():
return nil, ctx.Err()
default:
}
listDomainsReq := jdvod.NewListDomainsRequestWithoutParam()
listDomainsReq.SetPageNumber(listDomainsPageNumber)
listDomainsReq.SetPageSize(listDomainsPageSize)
listDomainsResp, err := d.sdkClient.ListDomains(listDomainsReq)
d.logger.Debug("sdk request 'vod.ListDomains'", slog.Any("request", listDomainsReq), slog.Any("response", listDomainsResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'vod.ListDomains': %w", err)
}
for _, domainInfo := range listDomainsResp.Result.Content {
if domainInfo.Name == d.config.Domain {
domainId, _ = strconv.Atoi(domainInfo.Id)
break
}
}
if len(listDomainsResp.Result.Content) < listDomainsPageSize {
break
} else {
listDomainsPageNumber++
}
}
if domainId == 0 {
return nil, errors.New("domain not found")
// 获取域名 ID
domainId, err := d.findDomainIdByDomain(ctx, d.config.Domain)
if err != nil {
return nil, err
}
// 查询域名 SSL 配置
@@ -125,6 +93,44 @@ func (d *SSLDeployerProvider) Deploy(ctx context.Context, certPEM string, privke
return &core.SSLDeployResult{}, nil
}
func (d *SSLDeployerProvider) findDomainIdByDomain(ctx context.Context, domain string) (int, error) {
// 查询域名列表
// REF: https://docs.jdcloud.com/cn/video-on-demand/api/listdomains
listDomainsPageNumber := 1
listDomainsPageSize := 100
for {
select {
case <-ctx.Done():
return 0, ctx.Err()
default:
}
listDomainsReq := jdvod.NewListDomainsRequestWithoutParam()
listDomainsReq.SetPageNumber(listDomainsPageNumber)
listDomainsReq.SetPageSize(listDomainsPageSize)
listDomainsResp, err := d.sdkClient.ListDomains(listDomainsReq)
d.logger.Debug("sdk request 'vod.ListDomains'", slog.Any("request", listDomainsReq), slog.Any("response", listDomainsResp))
if err != nil {
return 0, fmt.Errorf("failed to execute sdk request 'vod.ListDomains': %w", err)
}
for _, domainItem := range listDomainsResp.Result.Content {
if domainItem.Name == d.config.Domain {
domainId, _ := strconv.Atoi(domainItem.Id)
return domainId, nil
}
}
if len(listDomainsResp.Result.Content) < listDomainsPageSize {
break
}
listDomainsPageNumber++
}
return 0, fmt.Errorf("could not find domain '%s'", domain)
}
func createSDKClient(accessKeyId, accessKeySecret string) (*internal.VodClient, error) {
clientCredentials := jdcore.NewCredentials(accessKeyId, accessKeySecret)
client := internal.NewVodClient(clientCredentials)
@@ -20,7 +20,7 @@ type SSLDeployerProviderConfig struct {
AccessKeyId string `json:"accessKeyId"`
// 金山云 SecretAccessKey。
SecretAccessKey string `json:"secretAccessKey"`
// 域名匹配模式。
// 域名匹配模式。暂时只支持精确匹配。
// 零值时默认值 [DOMAIN_MATCH_PATTERN_EXACT]。
DomainMatchPattern string `json:"domainMatchPattern,omitempty"`
// 加速域名(支持泛域名)。
@@ -83,69 +83,10 @@ func (d *SSLDeployerProvider) deployToDomain(ctx context.Context, certPEM string
return errors.New("config `domain` is required")
}
// 查询域名列表,获取域名 ID
// https://docs.ksyun.com/documents/198
var domainId string
getCdnDomainsPageNumber := int32(1)
getCdnDomainsPageSize := int32(100)
for {
select {
case <-ctx.Done():
return ctx.Err()
default:
}
getCdnDomainsInput := map[string]any{
"PageNumber": getCdnDomainsPageNumber,
"PageSize": getCdnDomainsPageSize,
"DomainName": d.config.Domain,
"FuzzyMatch": "off",
}
getCdnDomainsReq, getCdnDomainsOutput := d.sdkClient.GetCdnDomainsPostRequest(&getCdnDomainsInput)
getCdnDomainsErr := getCdnDomainsReq.Send()
d.logger.Debug("sdk request 'cdn.GetCdnDomains'", slog.Any("request", getCdnDomainsInput), slog.Any("response", getCdnDomainsOutput))
if getCdnDomainsErr != nil {
return fmt.Errorf("failed to execute sdk request 'cdn.GetCdnDomains': %w", getCdnDomainsErr)
}
type GetCdnDomainsResponse struct {
PageNumber int32 `json:"PageNumber"`
PageSize int32 `json:"PageSize"`
TotalCount int32 `json:"TotalCount"`
Domains []*struct {
DomainId string `json:"DomainId"`
DomainName string `json:"DomainName"`
Cname string `json:"Cname"`
CdnType string `json:"CdnType"`
CreatedTime string `json:"CreatedTime"`
ModifiedTime string `json:"ModifiedTime"`
Region string `json:"Region"`
} `json:"Domains"`
}
var getCdnDomainsResp *GetCdnDomainsResponse
mapstructure.Decode(getCdnDomainsOutput, &getCdnDomainsResp)
if getCdnDomainsResp != nil {
for _, domainItem := range getCdnDomainsResp.Domains {
if strings.EqualFold(domainItem.DomainName, d.config.Domain) {
domainId = domainItem.DomainId
break
}
}
if domainId != "" {
break
}
}
if getCdnDomainsResp == nil || len(getCdnDomainsResp.Domains) < int(getCdnDomainsPageSize) {
break
} else {
getCdnDomainsPageNumber++
}
}
if domainId == "" {
return errors.New("domain not found")
// 获取域名 ID
domainId, err := d.findDomainIdByDomain(ctx, d.config.Domain)
if err != nil {
return err
}
if err := d.updateDomainCertificate(ctx, domainId, certPEM, privkeyPEM); err != nil {
@@ -178,6 +119,67 @@ func (d *SSLDeployerProvider) deployToCertificate(ctx context.Context, certPEM s
return nil
}
func (d *SSLDeployerProvider) findDomainIdByDomain(ctx context.Context, domain string) (string, error) {
// 查询域名列表
// https://docs.ksyun.com/documents/198
getCdnDomainsPageNumber := 1
getCdnDomainsPageSize := 100
for {
select {
case <-ctx.Done():
return "", ctx.Err()
default:
}
getCdnDomainsInput := map[string]any{
"PageNumber": getCdnDomainsPageNumber,
"PageSize": getCdnDomainsPageSize,
"DomainName": domain,
"FuzzyMatch": "off",
}
getCdnDomainsReq, getCdnDomainsOutput := d.sdkClient.GetCdnDomainsPostRequest(&getCdnDomainsInput)
getCdnDomainsErr := getCdnDomainsReq.Send()
d.logger.Debug("sdk request 'cdn.GetCdnDomains'", slog.Any("request", getCdnDomainsInput), slog.Any("response", getCdnDomainsOutput))
if getCdnDomainsErr != nil {
return "", fmt.Errorf("failed to execute sdk request 'cdn.GetCdnDomains': %w", getCdnDomainsErr)
}
type GetCdnDomainsResponse struct {
PageNumber int32 `json:"PageNumber"`
PageSize int32 `json:"PageSize"`
TotalCount int32 `json:"TotalCount"`
Domains []*struct {
DomainId string `json:"DomainId"`
DomainName string `json:"DomainName"`
Cname string `json:"Cname"`
CdnType string `json:"CdnType"`
CreatedTime string `json:"CreatedTime"`
ModifiedTime string `json:"ModifiedTime"`
Region string `json:"Region"`
} `json:"Domains"`
}
var getCdnDomainsResp *GetCdnDomainsResponse
mapstructure.Decode(getCdnDomainsOutput, &getCdnDomainsResp)
if getCdnDomainsResp == nil {
break
}
for _, domainItem := range getCdnDomainsResp.Domains {
if strings.EqualFold(domainItem.DomainName, domain) {
return domainItem.DomainId, nil
}
}
if len(getCdnDomainsResp.Domains) < getCdnDomainsPageSize {
break
}
getCdnDomainsPageNumber++
}
return "", fmt.Errorf("could not find domain '%s'", domain)
}
func (d *SSLDeployerProvider) updateDomainCertificate(ctx context.Context, domainId string, certPEM string, privkeyPEM string) error {
// 为加速域名配置证书接口
// https://docs.ksyun.com/documents/261
@@ -164,8 +164,8 @@ func (d *SSLDeployerProvider) getMatchedDomainsByWildcard(ctx context.Context, w
// 查询域名基本信息,获取匹配的域名
// REF: https://cloud.tencent.com/document/api/228/41118
describeDomainsOffset := int64(0)
describeDomainsLimit := int64(100)
describeDomainsOffset := 0
describeDomainsLimit := 100
for {
select {
case <-ctx.Done():
@@ -181,27 +181,29 @@ func (d *SSLDeployerProvider) getMatchedDomainsByWildcard(ctx context.Context, w
Fuzzy: common.BoolPtr(true),
},
}
describeDomainsReq.Offset = common.Int64Ptr(describeDomainsOffset)
describeDomainsReq.Limit = common.Int64Ptr(describeDomainsLimit)
describeDomainsReq.Offset = common.Int64Ptr(int64(describeDomainsOffset))
describeDomainsReq.Limit = common.Int64Ptr(int64(describeDomainsLimit))
describeDomainsResp, err := d.sdkClient.DescribeDomains(describeDomainsReq)
d.logger.Debug("sdk request 'cdn.DescribeDomains'", slog.Any("request", describeDomainsReq), slog.Any("response", describeDomainsResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'cdn.DescribeDomains': %w", err)
}
if describeDomainsResp.Response.Domains != nil {
for _, domainInfo := range describeDomainsResp.Response.Domains {
if lo.FromPtr(domainInfo.Product) == "cdn" && xcerthostname.IsMatch(wildcardDomain, lo.FromPtr(domainInfo.Domain)) {
domains = append(domains, *domainInfo.Domain)
}
if describeDomainsResp.Response == nil {
break
}
for _, domainItem := range describeDomainsResp.Response.Domains {
if lo.FromPtr(domainItem.Product) == "cdn" && xcerthostname.IsMatch(wildcardDomain, lo.FromPtr(domainItem.Domain)) {
domains = append(domains, lo.FromPtr(domainItem.Domain))
}
}
if len(describeDomainsResp.Response.Domains) < int(describeDomainsLimit) {
if len(describeDomainsResp.Response.Domains) < describeDomainsLimit {
break
} else {
describeDomainsOffset += describeDomainsLimit
}
describeDomainsOffset += describeDomainsLimit
}
return domains, nil
@@ -246,7 +248,7 @@ func (d *SSLDeployerProvider) updateDomainCertificate(ctx context.Context, domai
if err != nil {
return fmt.Errorf("failed to execute sdk request 'cdn.DescribeDomainsConfig': %w", err)
} else if len(describeDomainsConfigResp.Response.Domains) == 0 {
return fmt.Errorf("domain %s not found", domain)
return fmt.Errorf("could not find domain '%s'", domain)
}
domainConfig := describeDomainsConfigResp.Response.Domains[0]
@@ -233,9 +233,10 @@ func (d *SSLDeployerProvider) deployToRuleDomain(ctx context.Context, cloudCertI
return fmt.Errorf("failed to execute sdk request 'clb.DescribeTaskStatus': %w", err)
}
if describeTaskStatusResp.Response.Status == nil || *describeTaskStatusResp.Response.Status == 1 {
status := lo.FromPtr(describeTaskStatusResp.Response.Status)
if status == 1 {
return errors.New("unexpected tencentcloud task status")
} else if *describeTaskStatusResp.Response.Status == 0 {
} else if status == 0 {
break
}
@@ -257,7 +258,7 @@ func (d *SSLDeployerProvider) updateListenerCertificate(ctx context.Context, clo
if err != nil {
return fmt.Errorf("failed to execute sdk request 'clb.DescribeListeners': %w", err)
} else if len(describeListenersResp.Response.Listeners) == 0 {
return fmt.Errorf("listener %s not found", cloudListenerId)
return fmt.Errorf("could not find listener '%s'", cloudListenerId)
}
// 修改监听器属性
@@ -295,9 +296,10 @@ func (d *SSLDeployerProvider) updateListenerCertificate(ctx context.Context, clo
return fmt.Errorf("failed to execute sdk request 'clb.DescribeTaskStatus': %w", err)
}
if describeTaskStatusResp.Response.Status == nil || *describeTaskStatusResp.Response.Status == 1 {
status := lo.FromPtr(describeTaskStatusResp.Response.Status)
if status == 1 {
return errors.New("unexpected tencentcloud task status")
} else if *describeTaskStatusResp.Response.Status == 0 {
} else if status == 0 {
break
}
@@ -7,6 +7,7 @@ import (
"log/slog"
"time"
"github.com/samber/lo"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
tcssl "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl/v20191205"
@@ -134,21 +135,11 @@ func (d *SSLDeployerProvider) Deploy(ctx context.Context, certPEM string, privke
if describeHostDeployRecordDetailResp.Response.TotalCount == nil {
return nil, errors.New("unexpected tencentcloud deployment job status")
} else {
if describeHostDeployRecordDetailResp.Response.PendingTotalCount != nil {
pendingCount = *describeHostDeployRecordDetailResp.Response.PendingTotalCount
}
if describeHostDeployRecordDetailResp.Response.RunningTotalCount != nil {
runningCount = *describeHostDeployRecordDetailResp.Response.RunningTotalCount
}
if describeHostDeployRecordDetailResp.Response.SuccessTotalCount != nil {
succeededCount = *describeHostDeployRecordDetailResp.Response.SuccessTotalCount
}
if describeHostDeployRecordDetailResp.Response.FailedTotalCount != nil {
failedCount = *describeHostDeployRecordDetailResp.Response.FailedTotalCount
}
if describeHostDeployRecordDetailResp.Response.TotalCount != nil {
totalCount = *describeHostDeployRecordDetailResp.Response.TotalCount
}
pendingCount = lo.FromPtr(describeHostDeployRecordDetailResp.Response.PendingTotalCount)
runningCount = lo.FromPtr(describeHostDeployRecordDetailResp.Response.RunningTotalCount)
succeededCount = lo.FromPtr(describeHostDeployRecordDetailResp.Response.SuccessTotalCount)
failedCount = lo.FromPtr(describeHostDeployRecordDetailResp.Response.FailedTotalCount)
totalCount = lo.FromPtr(describeHostDeployRecordDetailResp.Response.TotalCount)
if succeededCount+failedCount == totalCount {
if failedCount > 0 {
@@ -168,8 +159,8 @@ func (d *SSLDeployerProvider) Deploy(ctx context.Context, certPEM string, privke
func (d *SSLDeployerProvider) checkIsBind(ctx context.Context, cloudCertId string) (bool, error) {
// 查询证书 COS 云资源部署实例列表
// REF: https://cloud.tencent.com/document/api/400/91661
describeHostCosInstanceListLimit := int64(100)
describeHostCosInstanceListOffset := int64(0)
describeHostCosInstanceListLimit := 100
describeHostCosInstanceListOffset := 0
for {
select {
case <-ctx.Done():
@@ -181,33 +172,39 @@ func (d *SSLDeployerProvider) checkIsBind(ctx context.Context, cloudCertId strin
describeHostCosInstanceListReq.OldCertificateId = common.StringPtr(cloudCertId)
describeHostCosInstanceListReq.ResourceType = common.StringPtr("cos")
describeHostCosInstanceListReq.IsCache = common.Uint64Ptr(0)
describeHostCosInstanceListReq.Offset = common.Int64Ptr(describeHostCosInstanceListOffset)
describeHostCosInstanceListReq.Limit = common.Int64Ptr(describeHostCosInstanceListLimit)
describeHostCosInstanceListReq.Offset = common.Int64Ptr(int64(describeHostCosInstanceListOffset))
describeHostCosInstanceListReq.Limit = common.Int64Ptr(int64(describeHostCosInstanceListLimit))
describeHostCosInstanceListResp, err := d.sdkClient.SSL.DescribeHostCosInstanceList(describeHostCosInstanceListReq)
d.logger.Debug("sdk request 'ssl.DescribeHostCosInstanceList'", slog.Any("request", describeHostCosInstanceListReq), slog.Any("response", describeHostCosInstanceListResp))
if err != nil {
return false, fmt.Errorf("failed to execute sdk request 'ssl.DescribeHostCosInstanceList': %w", err)
}
if describeHostCosInstanceListResp.Response == nil {
break
}
for _, instance := range describeHostCosInstanceListResp.Response.InstanceList {
if instance.Bucket == nil || *instance.Bucket != d.config.Bucket {
if lo.FromPtr(instance.Bucket) != d.config.Bucket {
continue
}
if instance.Domain == nil || *instance.Domain != d.config.Domain {
if lo.FromPtr(instance.Domain) != d.config.Domain {
continue
}
if instance.Status == nil || *instance.Status != "ENABLED" {
if lo.FromPtr(instance.Status) != "ENABLED" {
continue
}
return true, nil
}
if len(describeHostCosInstanceListResp.Response.InstanceList) < int(describeHostCosInstanceListLimit) {
return false, nil
} else {
describeHostCosInstanceListOffset += describeHostCosInstanceListLimit
if len(describeHostCosInstanceListResp.Response.InstanceList) < describeHostCosInstanceListLimit {
break
}
describeHostCosInstanceListOffset += describeHostCosInstanceListLimit
}
return false, nil
}
func createSDKClients(secretId, secretKey, region string) (*wSDKClients, error) {
@@ -164,8 +164,8 @@ func (d *SSLDeployerProvider) getMatchedDomainsByWildcard(ctx context.Context, w
// 查询域名基本信息,获取匹配的域名
// REF: https://cloud.tencent.com/document/api/228/41118
describeDomainsOffset := int64(0)
describeDomainsLimit := int64(100)
describeDomainsOffset := 0
describeDomainsLimit := 100
for {
select {
case <-ctx.Done():
@@ -181,27 +181,29 @@ func (d *SSLDeployerProvider) getMatchedDomainsByWildcard(ctx context.Context, w
Fuzzy: common.BoolPtr(true),
},
}
describeDomainsReq.Offset = common.Int64Ptr(describeDomainsOffset)
describeDomainsReq.Limit = common.Int64Ptr(describeDomainsLimit)
describeDomainsReq.Offset = common.Int64Ptr(int64(describeDomainsOffset))
describeDomainsReq.Limit = common.Int64Ptr(int64(describeDomainsLimit))
describeDomainsResp, err := d.sdkClient.DescribeDomains(describeDomainsReq)
d.logger.Debug("sdk request 'cdn.DescribeDomains'", slog.Any("request", describeDomainsReq), slog.Any("response", describeDomainsResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'cdn.DescribeDomains': %w", err)
}
if describeDomainsResp.Response.Domains != nil {
for _, domainInfo := range describeDomainsResp.Response.Domains {
if lo.FromPtr(domainInfo.Product) == "ecdn" && xcerthostname.IsMatch(wildcardDomain, lo.FromPtr(domainInfo.Domain)) {
domains = append(domains, *domainInfo.Domain)
}
if describeDomainsResp.Response == nil {
break
}
for _, domainItem := range describeDomainsResp.Response.Domains {
if lo.FromPtr(domainItem.Product) == "ecdn" && xcerthostname.IsMatch(wildcardDomain, lo.FromPtr(domainItem.Domain)) {
domains = append(domains, *domainItem.Domain)
}
}
if len(describeDomainsResp.Response.Domains) < int(describeDomainsLimit) {
if len(describeDomainsResp.Response.Domains) < describeDomainsLimit {
break
} else {
describeDomainsOffset += describeDomainsLimit
}
describeDomainsOffset += describeDomainsLimit
}
return domains, nil
@@ -246,7 +248,7 @@ func (d *SSLDeployerProvider) updateDomainHttpsServerCert(ctx context.Context, d
if err != nil {
return fmt.Errorf("failed to execute sdk request 'cdn.DescribeDomainsConfig': %w", err)
} else if len(describeDomainsConfigResp.Response.Domains) == 0 {
return fmt.Errorf("domain %s not found", domain)
return fmt.Errorf("could not find domain '%s'", domain)
}
domainConfig := describeDomainsConfigResp.Response.Domains[0]
@@ -195,11 +195,12 @@ func (d *SSLDeployerProvider) getAllDomainsInZone(ctx context.Context, zoneId st
return nil, fmt.Errorf("failed to execute sdk request 'teo.DescribeAccelerationDomains': %w", err)
}
for _, accelerationDomain := range describeAccelerationDomainsResp.Response.AccelerationDomains {
if accelerationDomain == nil || accelerationDomain.DomainName == nil {
for _, domainItem := range describeAccelerationDomainsResp.Response.AccelerationDomains {
if domainItem == nil || domainItem.DomainName == nil {
continue
}
domainsInZone = append(domainsInZone, *accelerationDomain.DomainName)
domainsInZone = append(domainsInZone, *domainItem.DomainName)
}
if len(describeAccelerationDomainsResp.Response.AccelerationDomains) < pageSize {
@@ -130,7 +130,7 @@ func (d *SSLDeployerProvider) updateHttpsListenerCertificate(ctx context.Context
if err != nil {
return fmt.Errorf("failed to execute sdk request 'gaap.DescribeHTTPSListeners': %w", err)
} else if len(describeHTTPSListenersResp.Response.ListenerSet) == 0 {
return fmt.Errorf("listener %s not found", cloudListenerId)
return fmt.Errorf("could not find listener '%s'", cloudListenerId)
}
// 修改 HTTPS 监听器配置
@@ -7,6 +7,7 @@ import (
"log/slog"
"time"
"github.com/samber/lo"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
tcssl "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl/v20191205"
@@ -130,21 +131,11 @@ func (d *SSLDeployerProvider) Deploy(ctx context.Context, certPEM string, privke
if describeHostDeployRecordDetailResp.Response.TotalCount == nil {
return nil, errors.New("unexpected tencentcloud deployment job status")
} else {
if describeHostDeployRecordDetailResp.Response.PendingTotalCount != nil {
pendingCount = *describeHostDeployRecordDetailResp.Response.PendingTotalCount
}
if describeHostDeployRecordDetailResp.Response.RunningTotalCount != nil {
runningCount = *describeHostDeployRecordDetailResp.Response.RunningTotalCount
}
if describeHostDeployRecordDetailResp.Response.SuccessTotalCount != nil {
succeededCount = *describeHostDeployRecordDetailResp.Response.SuccessTotalCount
}
if describeHostDeployRecordDetailResp.Response.FailedTotalCount != nil {
failedCount = *describeHostDeployRecordDetailResp.Response.FailedTotalCount
}
if describeHostDeployRecordDetailResp.Response.TotalCount != nil {
totalCount = *describeHostDeployRecordDetailResp.Response.TotalCount
}
pendingCount = lo.FromPtr(describeHostDeployRecordDetailResp.Response.PendingTotalCount)
runningCount = lo.FromPtr(describeHostDeployRecordDetailResp.Response.RunningTotalCount)
succeededCount = lo.FromPtr(describeHostDeployRecordDetailResp.Response.SuccessTotalCount)
failedCount = lo.FromPtr(describeHostDeployRecordDetailResp.Response.FailedTotalCount)
totalCount = lo.FromPtr(describeHostDeployRecordDetailResp.Response.TotalCount)
if succeededCount+failedCount == totalCount {
if failedCount > 0 {
@@ -8,6 +8,7 @@ import (
"slices"
"time"
"github.com/samber/lo"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
tcssl "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl/v20191205"
@@ -163,21 +164,11 @@ func (d *SSLDeployerProvider) executeUpdateCertificateInstance(ctx context.Conte
if describeHostUpdateRecordDetailResp.Response.TotalCount == nil {
return errors.New("unexpected tencentcloud deployment job status")
} else {
if describeHostUpdateRecordDetailResp.Response.PendingTotalCount != nil {
pendingCount = *describeHostUpdateRecordDetailResp.Response.PendingTotalCount
}
if describeHostUpdateRecordDetailResp.Response.RunningTotalCount != nil {
runningCount = *describeHostUpdateRecordDetailResp.Response.RunningTotalCount
}
if describeHostUpdateRecordDetailResp.Response.SuccessTotalCount != nil {
succeededCount = *describeHostUpdateRecordDetailResp.Response.SuccessTotalCount
}
if describeHostUpdateRecordDetailResp.Response.FailedTotalCount != nil {
failedCount = *describeHostUpdateRecordDetailResp.Response.FailedTotalCount
}
if describeHostUpdateRecordDetailResp.Response.TotalCount != nil {
totalCount = *describeHostUpdateRecordDetailResp.Response.TotalCount
}
pendingCount = lo.FromPtr(describeHostUpdateRecordDetailResp.Response.PendingTotalCount)
runningCount = lo.FromPtr(describeHostUpdateRecordDetailResp.Response.RunningTotalCount)
succeededCount = lo.FromPtr(describeHostUpdateRecordDetailResp.Response.SuccessTotalCount)
failedCount = lo.FromPtr(describeHostUpdateRecordDetailResp.Response.FailedTotalCount)
totalCount = lo.FromPtr(describeHostUpdateRecordDetailResp.Response.TotalCount)
if succeededCount+failedCount == totalCount {
if failedCount > 0 {
@@ -250,18 +241,10 @@ func (d *SSLDeployerProvider) executeUploadUpdateCertificateInstance(ctx context
return errors.New("unexpected tencentcloud deployment job status")
} else {
for _, record := range describeHostUploadUpdateRecordDetailResp.Response.DeployRecordDetail {
if record.RunningTotalCount != nil {
runningCount = *record.RunningTotalCount
}
if record.SuccessTotalCount != nil {
succeededCount = *record.SuccessTotalCount
}
if record.FailedTotalCount != nil {
failedCount = *record.FailedTotalCount
}
if record.TotalCount != nil {
totalCount = *record.TotalCount
}
runningCount += lo.FromPtr(record.RunningTotalCount)
succeededCount += lo.FromPtr(record.SuccessTotalCount)
failedCount += lo.FromPtr(record.FailedTotalCount)
totalCount += lo.FromPtr(record.TotalCount)
}
if succeededCount+failedCount == totalCount {
@@ -97,7 +97,7 @@ func (d *SSLDeployerProvider) Deploy(ctx context.Context, certPEM string, privke
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'ucdn.GetUcdnDomainConfig': %w", err)
} else if len(getUcdnDomainConfigResp.DomainList) == 0 {
return nil, fmt.Errorf("domain %s not found", d.config.DomainId)
return nil, fmt.Errorf("could not find domain '%s'", d.config.DomainId)
}
// 更新 HTTPS 加速配置
@@ -129,8 +129,8 @@ func (d *SSLDeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCer
// 查询 HTTPS 监听器列表
// REF: https://www.volcengine.com/docs/6767/113684
listenerIds := make([]string, 0)
describeListenersPageSize := int64(100)
describeListenersPageNumber := int64(1)
describeListenersPageSize := 100
describeListenersPageNumber := 1
for {
select {
case <-ctx.Done():
@@ -141,8 +141,8 @@ func (d *SSLDeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCer
describeListenersReq := &vealb.DescribeListenersInput{
LoadBalancerId: ve.String(d.config.LoadbalancerId),
Protocol: ve.String("HTTPS"),
PageNumber: ve.Int64(describeListenersPageNumber),
PageSize: ve.Int64(describeListenersPageSize),
PageNumber: ve.Int64(int64(describeListenersPageNumber)),
PageSize: ve.Int64(int64(describeListenersPageSize)),
}
describeListenersResp, err := d.sdkClient.DescribeListeners(describeListenersReq)
d.logger.Debug("sdk request 'alb.DescribeListeners'", slog.Any("request", describeListenersReq), slog.Any("response", describeListenersResp))
@@ -154,11 +154,11 @@ func (d *SSLDeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCer
listenerIds = append(listenerIds, *listener.ListenerId)
}
if len(describeListenersResp.Listeners) < int(describeListenersPageSize) {
if len(describeListenersResp.Listeners) < describeListenersPageSize {
break
} else {
describeListenersPageNumber++
}
describeListenersPageNumber++
}
// 遍历更新监听证书
@@ -158,8 +158,8 @@ func (d *SSLDeployerProvider) getMatchedDomainsByWildcard(ctx context.Context, w
// 查询加速域名列表,获取匹配的域名
// REF: https://www.volcengine.com/docs/6454/75269
listCdnDomainsPageNum := int64(1)
listCdnDomainsPageSize := int64(100)
listCdnDomainsPageNum := 1
listCdnDomainsPageSize := 100
for {
select {
case <-ctx.Done():
@@ -170,8 +170,8 @@ func (d *SSLDeployerProvider) getMatchedDomainsByWildcard(ctx context.Context, w
listCdnDomainsReq := &vecdn.ListCdnDomainsInput{
Domain: ve.String(strings.TrimPrefix(wildcardDomain, "*.")),
Status: ve.String("online"),
PageNum: ve.Int64(listCdnDomainsPageNum),
PageSize: ve.Int64(listCdnDomainsPageSize),
PageNum: ve.Int64(int64(listCdnDomainsPageNum)),
PageSize: ve.Int64(int64(listCdnDomainsPageSize)),
}
listCdnDomainsResp, err := d.sdkClient.ListCdnDomains(listCdnDomainsReq)
d.logger.Debug("sdk request 'cdn.ListCdnDomains'", slog.Any("request", listCdnDomainsReq), slog.Any("response", listCdnDomainsResp))
@@ -179,19 +179,17 @@ func (d *SSLDeployerProvider) getMatchedDomainsByWildcard(ctx context.Context, w
return nil, fmt.Errorf("failed to execute sdk request 'cdn.ListCdnDomains': %w", err)
}
if listCdnDomainsResp.Data != nil {
for _, domainInfo := range listCdnDomainsResp.Data {
if xcerthostname.IsMatch(wildcardDomain, ve.StringValue(domainInfo.Domain)) {
domains = append(domains, ve.StringValue(domainInfo.Domain))
}
for _, domainItem := range listCdnDomainsResp.Data {
if xcerthostname.IsMatch(wildcardDomain, ve.StringValue(domainItem.Domain)) {
domains = append(domains, ve.StringValue(domainItem.Domain))
}
}
if len(listCdnDomainsResp.Data) < int(listCdnDomainsPageSize) {
if len(listCdnDomainsResp.Data) < listCdnDomainsPageSize {
break
} else {
listCdnDomainsPageSize++
}
listCdnDomainsPageSize++
}
if len(domains) == 0 {
@@ -125,8 +125,8 @@ func (d *SSLDeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCer
// 查询 HTTPS 监听器列表
// REF: https://www.volcengine.com/docs/6406/71776
listenerIds := make([]string, 0)
describeListenersPageSize := int64(100)
describeListenersPageNumber := int64(1)
describeListenersPageSize := 100
describeListenersPageNumber := 1
for {
select {
case <-ctx.Done():
@@ -137,8 +137,8 @@ func (d *SSLDeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCer
describeListenersReq := &veclb.DescribeListenersInput{
LoadBalancerId: ve.String(d.config.LoadbalancerId),
Protocol: ve.String("HTTPS"),
PageNumber: ve.Int64(describeListenersPageNumber),
PageSize: ve.Int64(describeListenersPageSize),
PageNumber: ve.Int64(int64(describeListenersPageNumber)),
PageSize: ve.Int64(int64(describeListenersPageSize)),
}
describeListenersResp, err := d.sdkClient.DescribeListeners(describeListenersReq)
d.logger.Debug("sdk request 'clb.DescribeListeners'", slog.Any("request", describeListenersReq), slog.Any("response", describeListenersResp))
@@ -150,11 +150,11 @@ func (d *SSLDeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCer
listenerIds = append(listenerIds, *listener.ListenerId)
}
if len(describeListenersResp.Listeners) < int(describeListenersPageSize) {
if len(describeListenersResp.Listeners) < describeListenersPageSize {
break
} else {
describeListenersPageNumber++
}
describeListenersPageNumber++
}
// 遍历更新监听证书
@@ -23,7 +23,7 @@ type SSLDeployerProviderConfig struct {
AccessKeySecret string `json:"accessKeySecret"`
// 火山引擎地域。
Region string `json:"region"`
// 域名匹配模式。
// 域名匹配模式。暂时只支持精确匹配。
// 零值时默认值 [DOMAIN_MATCH_PATTERN_EXACT]。
DomainMatchPattern string `json:"domainMatchPattern,omitempty"`
// 加速域名(支持泛域名)。
@@ -172,8 +172,8 @@ func (d *SSLDeployerProvider) getAllDomains(ctx context.Context) ([]string, erro
// 查询域名列表
// REF: https://www.volcengine.com/docs/6469/1126815
listDomainDetailPageNum := int32(1)
listDomainDetailPageSize := int32(1000)
listDomainDetailPageNum := 1
listDomainDetailPageSize := 1000
for {
select {
case <-ctx.Done():
@@ -183,8 +183,8 @@ func (d *SSLDeployerProvider) getAllDomains(ctx context.Context) ([]string, erro
listDomainDetailReq := &velive.ListDomainDetailBody{
DomainStatusList: ve.Int32Slice([]int32{0}),
PageNum: listDomainDetailPageNum,
PageSize: listDomainDetailPageSize,
PageNum: int32(listDomainDetailPageNum),
PageSize: int32(listDomainDetailPageSize),
}
listDomainDetailResp, err := d.sdkClient.ListDomainDetail(ctx, listDomainDetailReq)
d.logger.Debug("sdk request 'live.ListDomainDetail'", slog.Any("request", listDomainDetailReq), slog.Any("response", listDomainDetailResp))
@@ -192,17 +192,19 @@ func (d *SSLDeployerProvider) getAllDomains(ctx context.Context) ([]string, erro
return nil, fmt.Errorf("failed to execute sdk request 'live.ListDomainDetail': %w", err)
}
if listDomainDetailResp.Result.DomainList != nil {
for _, domainInfo := range listDomainDetailResp.Result.DomainList {
domains = append(domains, domainInfo.Domain)
}
if listDomainDetailResp.Result == nil {
break
}
if len(listDomainDetailResp.Result.DomainList) < int(listDomainDetailPageSize) {
break
} else {
listDomainDetailPageNum++
for _, domainItem := range listDomainDetailResp.Result.DomainList {
domains = append(domains, domainItem.Domain)
}
if len(listDomainDetailResp.Result.DomainList) < listDomainDetailPageSize {
break
}
listDomainDetailPageNum++
}
return domains, nil
@@ -0,0 +1,6 @@
package wangsucdn
const (
// 匹配模式:精确匹配。
DOMAIN_MATCH_PATTERN_EXACT = "exact"
)
@@ -20,6 +20,9 @@ type SSLDeployerProviderConfig struct {
AccessKeyId string `json:"accessKeyId"`
// 网宿云 AccessKeySecret。
AccessKeySecret string `json:"accessKeySecret"`
// 域名匹配模式。暂时只支持精确匹配。
// 零值时默认值 [DOMAIN_MATCH_PATTERN_EXACT]。
DomainMatchPattern string `json:"domainMatchPattern,omitempty"`
// 加速域名数组(支持泛域名)。
Domains []string `json:"domains"`
}
@@ -0,0 +1,6 @@
package wangsucdnpro
const (
// 匹配模式:精确匹配。
DOMAIN_MATCH_PATTERN_EXACT = "exact"
)
@@ -32,6 +32,9 @@ type SSLDeployerProviderConfig struct {
ApiKey string `json:"apiKey"`
// 网宿云环境。
Environment string `json:"environment"`
// 域名匹配模式。暂时只支持精确匹配。
// 零值时默认值 [DOMAIN_MATCH_PATTERN_EXACT]。
DomainMatchPattern string `json:"domainMatchPattern,omitempty"`
// 加速域名(支持泛域名)。
Domain string `json:"domain"`
// 证书 ID。
@@ -60,7 +60,7 @@ func (m *SSLManagerProvider) SetLogger(logger *slog.Logger) {
func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkeyPEM string) (*core.SSLManageUploadResult, error) {
// 避免重复上传
if res, err := m.findCertIfExists(ctx, certPEM, privkeyPEM); err != nil {
if res, err := m.tryFindCert(ctx, certPEM, privkeyPEM); err != nil {
return nil, err
} else if res != nil {
m.logger.Info("ssl certificate already exists")
@@ -107,19 +107,19 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
}
// 获取刚刚上传证书 ID
if res, err := m.findCertIfExists(ctx, certPEM, privkeyPEM); err != nil {
if res, err := m.tryFindCert(ctx, certPEM, privkeyPEM); err != nil {
return nil, err
} else if res == nil {
return nil, fmt.Errorf("no ssl certificate found, may be upload failed")
return nil, fmt.Errorf("could not find ssl certificate, may be upload failed")
} else {
return res, nil
}
}
func (m *SSLManagerProvider) findCertIfExists(ctx context.Context, certPEM string, privkeyPEM string) (*core.SSLManageUploadResult, error) {
searchWebsiteSSLPageNumber := int32(1)
searchWebsiteSSLPageSize := int32(100)
searchWebsiteSSLItemsCount := int32(0)
func (m *SSLManagerProvider) tryFindCert(ctx context.Context, certPEM string, privkeyPEM string) (*core.SSLManageUploadResult, error) {
searchWebsiteSSLPageNumber := 1
searchWebsiteSSLPageSize := 100
searchWebsiteSSLItemsCount := 0
for {
select {
case <-ctx.Done():
@@ -131,8 +131,8 @@ func (m *SSLManagerProvider) findCertIfExists(ctx context.Context, certPEM strin
case *onepanelsdk.Client:
{
searchWebsiteSSLReq := &onepanelsdk.SearchWebsiteSSLRequest{
Page: searchWebsiteSSLPageNumber,
PageSize: searchWebsiteSSLPageSize,
Page: int32(searchWebsiteSSLPageNumber),
PageSize: int32(searchWebsiteSSLPageSize),
}
searchWebsiteSSLResp, err := sdkClient.SearchWebsiteSSL(searchWebsiteSSLReq)
m.logger.Debug("sdk request '1panel.SearchWebsiteSSL'", slog.Any("request", searchWebsiteSSLReq), slog.Any("response", searchWebsiteSSLResp))
@@ -140,27 +140,29 @@ func (m *SSLManagerProvider) findCertIfExists(ctx context.Context, certPEM strin
return nil, fmt.Errorf("failed to execute sdk request '1panel.SearchWebsiteSSL': %w", err)
}
if searchWebsiteSSLResp.Data != nil {
for _, sslItem := range searchWebsiteSSLResp.Data.Items {
if strings.TrimSpace(sslItem.PEM) == strings.TrimSpace(certPEM) &&
strings.TrimSpace(sslItem.PrivateKey) == strings.TrimSpace(privkeyPEM) {
// 如果已存在相同证书,直接返回
return &core.SSLManageUploadResult{
CertId: fmt.Sprintf("%d", sslItem.ID),
CertName: sslItem.Description,
}, nil
}
if searchWebsiteSSLResp.Data == nil {
break
}
for _, sslItem := range searchWebsiteSSLResp.Data.Items {
if strings.TrimSpace(sslItem.PEM) == strings.TrimSpace(certPEM) &&
strings.TrimSpace(sslItem.PrivateKey) == strings.TrimSpace(privkeyPEM) {
// 如果已存在相同证书,直接返回
return &core.SSLManageUploadResult{
CertId: fmt.Sprintf("%d", sslItem.ID),
CertName: sslItem.Description,
}, nil
}
}
searchWebsiteSSLItemsCount = searchWebsiteSSLResp.Data.Total
searchWebsiteSSLItemsCount = int(searchWebsiteSSLResp.Data.Total)
}
case *onepanelsdkv2.Client:
{
searchWebsiteSSLReq := &onepanelsdkv2.SearchWebsiteSSLRequest{
Page: searchWebsiteSSLPageNumber,
PageSize: searchWebsiteSSLPageSize,
Page: int32(searchWebsiteSSLPageNumber),
PageSize: int32(searchWebsiteSSLPageSize),
}
searchWebsiteSSLResp, err := sdkClient.SearchWebsiteSSL(searchWebsiteSSLReq)
m.logger.Debug("sdk request '1panel.SearchWebsiteSSL'", slog.Any("request", searchWebsiteSSLReq), slog.Any("response", searchWebsiteSSLResp))
@@ -168,20 +170,22 @@ func (m *SSLManagerProvider) findCertIfExists(ctx context.Context, certPEM strin
return nil, fmt.Errorf("failed to execute sdk request '1panel.SearchWebsiteSSL': %w", err)
}
if searchWebsiteSSLResp.Data != nil {
for _, sslItem := range searchWebsiteSSLResp.Data.Items {
if strings.TrimSpace(sslItem.PEM) == strings.TrimSpace(certPEM) &&
strings.TrimSpace(sslItem.PrivateKey) == strings.TrimSpace(privkeyPEM) {
// 如果已存在相同证书,直接返回
return &core.SSLManageUploadResult{
CertId: fmt.Sprintf("%d", sslItem.ID),
CertName: sslItem.Description,
}, nil
}
if searchWebsiteSSLResp.Data == nil {
break
}
for _, sslItem := range searchWebsiteSSLResp.Data.Items {
if strings.TrimSpace(sslItem.PEM) == strings.TrimSpace(certPEM) &&
strings.TrimSpace(sslItem.PrivateKey) == strings.TrimSpace(privkeyPEM) {
// 如果已存在相同证书,直接返回
return &core.SSLManageUploadResult{
CertId: fmt.Sprintf("%d", sslItem.ID),
CertName: sslItem.Description,
}, nil
}
}
searchWebsiteSSLItemsCount = searchWebsiteSSLResp.Data.Total
searchWebsiteSSLItemsCount = int(searchWebsiteSSLResp.Data.Total)
}
default:
@@ -73,8 +73,8 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
// 查询证书列表,避免重复上传
// REF: https://help.aliyun.com/zh/ssl-certificate/developer-reference/api-cas-2020-04-07-listusercertificateorder
// REF: https://help.aliyun.com/zh/ssl-certificate/developer-reference/api-cas-2020-04-07-getusercertificatedetail
listUserCertificateOrderPage := int64(1)
listUserCertificateOrderLimit := int64(50)
listUserCertificateOrderPage := 1
listUserCertificateOrderLimit := 50
for {
select {
case <-ctx.Done():
@@ -84,8 +84,8 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
listUserCertificateOrderReq := &alicas.ListUserCertificateOrderRequest{
ResourceGroupId: lo.EmptyableToPtr(m.config.ResourceGroupId),
CurrentPage: tea.Int64(listUserCertificateOrderPage),
ShowSize: tea.Int64(listUserCertificateOrderLimit),
CurrentPage: tea.Int64(int64(listUserCertificateOrderPage)),
ShowSize: tea.Int64(int64(listUserCertificateOrderLimit)),
OrderType: tea.String("CERT"),
}
listUserCertificateOrderResp, err := m.sdkClient.ListUserCertificateOrderWithContext(context.TODO(), listUserCertificateOrderReq, &dara.RuntimeOptions{})
@@ -94,53 +94,55 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
return nil, fmt.Errorf("failed to execute sdk request 'cas.ListUserCertificateOrder': %w", err)
}
if listUserCertificateOrderResp.Body.CertificateOrderList != nil {
for _, certOrder := range listUserCertificateOrderResp.Body.CertificateOrderList {
// 先对比证书通用名称
if !strings.EqualFold(certX509.Subject.CommonName, tea.StringValue(certOrder.CommonName)) {
continue
}
// 再对比证书序列号
// 注意阿里云 CAS 会在序列号前补零,需去除后再比较
oldCertSN := strings.TrimLeft(tea.StringValue(certOrder.SerialNo), "0")
newCertSN := strings.TrimLeft(certX509.SerialNumber.Text(16), "0")
if !strings.EqualFold(newCertSN, oldCertSN) {
continue
}
// 最后对比证书内容
getUserCertificateDetailReq := &alicas.GetUserCertificateDetailRequest{
CertId: certOrder.CertificateId,
}
getUserCertificateDetailResp, err := m.sdkClient.GetUserCertificateDetailWithContext(context.TODO(), getUserCertificateDetailReq, &dara.RuntimeOptions{})
m.logger.Debug("sdk request 'cas.GetUserCertificateDetail'", slog.Any("request", getUserCertificateDetailReq), slog.Any("response", getUserCertificateDetailResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'cas.GetUserCertificateDetail': %w", err)
} else {
if !xcert.EqualCertificatesFromPEM(certPEM, tea.StringValue(getUserCertificateDetailResp.Body.Cert)) {
continue
}
}
// 如果以上信息都一致,则视为已存在相同证书,直接返回
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: fmt.Sprintf("%d", tea.Int64Value(certOrder.CertificateId)),
CertName: *certOrder.Name,
ExtendedData: map[string]any{
"InstanceId": tea.StringValue(getUserCertificateDetailResp.Body.InstanceId),
"CertIdentifier": tea.StringValue(getUserCertificateDetailResp.Body.CertIdentifier),
},
}, nil
}
}
if listUserCertificateOrderResp.Body.CertificateOrderList == nil || len(listUserCertificateOrderResp.Body.CertificateOrderList) < int(listUserCertificateOrderLimit) {
if listUserCertificateOrderResp.Body == nil {
break
} else {
listUserCertificateOrderPage++
}
for _, certItem := range listUserCertificateOrderResp.Body.CertificateOrderList {
// 对比证书通用名称
if !strings.EqualFold(certX509.Subject.CommonName, tea.StringValue(certItem.CommonName)) {
continue
}
// 对比证书序列号
// 注意阿里云 CAS 会在序列号前补零,需去除后再比较
oldCertSN := strings.TrimLeft(tea.StringValue(certItem.SerialNo), "0")
newCertSN := strings.TrimLeft(certX509.SerialNumber.Text(16), "0")
if !strings.EqualFold(newCertSN, oldCertSN) {
continue
}
// 对比证书内容
getUserCertificateDetailReq := &alicas.GetUserCertificateDetailRequest{
CertId: certItem.CertificateId,
}
getUserCertificateDetailResp, err := m.sdkClient.GetUserCertificateDetailWithContext(context.TODO(), getUserCertificateDetailReq, &dara.RuntimeOptions{})
m.logger.Debug("sdk request 'cas.GetUserCertificateDetail'", slog.Any("request", getUserCertificateDetailReq), slog.Any("response", getUserCertificateDetailResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'cas.GetUserCertificateDetail': %w", err)
} else {
if !xcert.EqualCertificatesFromPEM(certPEM, tea.StringValue(getUserCertificateDetailResp.Body.Cert)) {
continue
}
}
// 如果以上信息都一致,则视为已存在相同证书,直接返回
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: fmt.Sprintf("%d", tea.Int64Value(certItem.CertificateId)),
CertName: *certItem.Name,
ExtendedData: map[string]any{
"InstanceId": tea.StringValue(getUserCertificateDetailResp.Body.InstanceId),
"CertIdentifier": tea.StringValue(getUserCertificateDetailResp.Body.CertIdentifier),
},
}, nil
}
if len(listUserCertificateOrderResp.Body.CertificateOrderList) < listUserCertificateOrderLimit {
break
}
listUserCertificateOrderPage++
}
// 生成新证书名(需符合阿里云命名规则)
@@ -87,22 +87,22 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
if describeServerCertificatesResp.Body.ServerCertificates != nil && describeServerCertificatesResp.Body.ServerCertificates.ServerCertificate != nil {
fingerprint := sha256.Sum256(certX509.Raw)
fingerprintHex := hex.EncodeToString(fingerprint[:])
for _, serverCert := range describeServerCertificatesResp.Body.ServerCertificates.ServerCertificate {
if tea.Int32Value(serverCert.IsAliCloudCertificate) != 0 {
for _, certItem := range describeServerCertificatesResp.Body.ServerCertificates.ServerCertificate {
if tea.Int32Value(certItem.IsAliCloudCertificate) != 0 {
continue
}
if !strings.EqualFold(certX509.Subject.CommonName, tea.StringValue(serverCert.CommonName)) {
if !strings.EqualFold(certX509.Subject.CommonName, tea.StringValue(certItem.CommonName)) {
continue
}
if !strings.EqualFold(fingerprintHex, strings.ReplaceAll(tea.StringValue(serverCert.Fingerprint), ":", "")) {
if !strings.EqualFold(fingerprintHex, strings.ReplaceAll(tea.StringValue(certItem.Fingerprint), ":", "")) {
continue
}
// 如果已存在相同证书,直接返回
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: *serverCert.ServerCertificateId,
CertName: *serverCert.ServerCertificateName,
CertId: *certItem.ServerCertificateId,
CertName: *certItem.ServerCertificateName,
}, nil
}
}
@@ -73,8 +73,8 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
// 获取证书列表,避免重复上传
// REF: https://docs.aws.amazon.com/en_us/acm/latest/APIReference/API_ListCertificates.html
var listCertificatesNextToken *string = nil
var listCertificatesMaxItems int32 = 1000
// REF: https://docs.aws.amazon.com/en_us/acm/latest/APIReference/API_GetCertificate.html
listCertificatesNextToken := (*string)(nil)
for {
select {
case <-ctx.Done():
@@ -84,7 +84,7 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
listCertificatesReq := &awsacm.ListCertificatesInput{
NextToken: listCertificatesNextToken,
MaxItems: aws.Int32(listCertificatesMaxItems),
MaxItems: aws.Int32(1000),
}
listCertificatesResp, err := m.sdkClient.ListCertificates(context.TODO(), listCertificatesReq)
m.logger.Debug("sdk request 'acm.ListCertificates'", slog.Any("request", listCertificatesReq), slog.Any("response", listCertificatesResp))
@@ -92,24 +92,23 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
return nil, fmt.Errorf("failed to execute sdk request 'acm.ListCertificates': %w", err)
}
for _, certSummary := range listCertificatesResp.CertificateSummaryList {
// 先对比证书有效期
if certSummary.NotBefore == nil || !certSummary.NotBefore.Equal(certX509.NotBefore) {
for _, certItem := range listCertificatesResp.CertificateSummaryList {
// 对比证书有效期
if certItem.NotBefore == nil || !certItem.NotBefore.Equal(certX509.NotBefore) {
continue
}
if certSummary.NotAfter == nil || !certSummary.NotAfter.Equal(certX509.NotAfter) {
if certItem.NotAfter == nil || !certItem.NotAfter.Equal(certX509.NotAfter) {
continue
}
// 再对比证书多域名
if !strings.EqualFold(strings.Join(certX509.DNSNames, ","), strings.Join(certSummary.SubjectAlternativeNameSummaries, ",")) {
// 对比证书多域名
if !strings.EqualFold(strings.Join(certX509.DNSNames, ","), strings.Join(certItem.SubjectAlternativeNameSummaries, ",")) {
continue
}
// 最后对比证书内容
// REF: https://docs.aws.amazon.com/en_us/acm/latest/APIReference/API_GetCertificate.html
// 对比证书内容
getCertificateReq := &awsacm.GetCertificateInput{
CertificateArn: certSummary.CertificateArn,
CertificateArn: certItem.CertificateArn,
}
getCertificateResp, err := m.sdkClient.GetCertificate(context.TODO(), getCertificateReq)
if err != nil {
@@ -123,15 +122,15 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
// 如果以上信息都一致,则视为已存在相同证书,直接返回
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: *certSummary.CertificateArn,
CertId: *certItem.CertificateArn,
}, nil
}
if listCertificatesResp.NextToken == nil || len(listCertificatesResp.CertificateSummaryList) < int(listCertificatesMaxItems) {
if len(listCertificatesResp.CertificateSummaryList) == 0 || listCertificatesResp.NextToken == nil {
break
} else {
listCertificatesNextToken = listCertificatesResp.NextToken
}
listCertificatesNextToken = listCertificatesResp.NextToken
}
// 导入证书
@@ -76,8 +76,8 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
// 获取证书列表,避免重复上传
// REF: https://docs.aws.amazon.com/en_us/IAM/latest/APIReference/API_ListServerCertificates.html
var listServerCertificatesMarker *string = nil
var listServerCertificatesMaxItems int32 = 1000
// REF: https://docs.aws.amazon.com/en_us/IAM/latest/APIReference/API_GetServerCertificate.html
listServerCertificatesMarker := (*string)(nil)
for {
select {
case <-ctx.Done():
@@ -87,7 +87,7 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
listServerCertificatesReq := &awsiam.ListServerCertificatesInput{
Marker: listServerCertificatesMarker,
MaxItems: aws.Int32(listServerCertificatesMaxItems),
MaxItems: aws.Int32(1000),
}
if m.config.CertificatePath != "" {
listServerCertificatesReq.PathPrefix = aws.String(m.config.CertificatePath)
@@ -98,21 +98,20 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
return nil, fmt.Errorf("failed to execute sdk request 'iam.ListServerCertificates': %w", err)
}
for _, certMeta := range listServerCertificatesResp.ServerCertificateMetadataList {
// 先对比证书路径
if m.config.CertificatePath != "" && aws.ToString(certMeta.Path) != m.config.CertificatePath {
for _, certItem := range listServerCertificatesResp.ServerCertificateMetadataList {
// 对比证书路径
if m.config.CertificatePath != "" && aws.ToString(certItem.Path) != m.config.CertificatePath {
continue
}
// 先对比证书有效期
if certMeta.Expiration == nil || !certMeta.Expiration.Equal(certX509.NotAfter) {
// 对比证书有效期
if certItem.Expiration == nil || !certItem.Expiration.Equal(certX509.NotAfter) {
continue
}
// 最后对比证书内容
// REF: https://docs.aws.amazon.com/en_us/IAM/latest/APIReference/API_GetServerCertificate.html
// 对比证书内容
getServerCertificateReq := &awsiam.GetServerCertificateInput{
ServerCertificateName: certMeta.ServerCertificateName,
ServerCertificateName: certItem.ServerCertificateName,
}
getServerCertificateResp, err := m.sdkClient.GetServerCertificate(context.TODO(), getServerCertificateReq)
if err != nil {
@@ -126,16 +125,16 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
// 如果以上信息都一致,则视为已存在相同证书,直接返回
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: aws.ToString(certMeta.ServerCertificateId),
CertName: aws.ToString(certMeta.ServerCertificateName),
CertId: aws.ToString(certItem.ServerCertificateId),
CertName: aws.ToString(certItem.ServerCertificateName),
}, nil
}
if listServerCertificatesResp.Marker == nil || len(listServerCertificatesResp.ServerCertificateMetadataList) < int(listServerCertificatesMaxItems) {
if len(listServerCertificatesResp.ServerCertificateMetadataList) == 0 || listServerCertificatesResp.Marker == nil {
break
} else {
listServerCertificatesMarker = listServerCertificatesResp.Marker
}
listServerCertificatesMarker = listServerCertificatesResp.Marker
}
// 生成新证书名(需符合 AWS IAM 命名规则)
@@ -86,35 +86,35 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
return nil, fmt.Errorf("failed to execute sdk request 'keyvault.GetCertificates': %w", err)
}
for _, certProp := range page.Value {
// 先对比证书有效期
if certProp.Attributes == nil {
for _, certItem := range page.Value {
// 对比证书有效期
if certItem.Attributes == nil {
continue
}
if certProp.Attributes.NotBefore == nil || !certProp.Attributes.NotBefore.Equal(certX509.NotBefore) {
if certItem.Attributes.NotBefore == nil || !certItem.Attributes.NotBefore.Equal(certX509.NotBefore) {
continue
}
if certProp.Attributes.Expires == nil || !certProp.Attributes.Expires.Equal(certX509.NotAfter) {
if certItem.Attributes.Expires == nil || !certItem.Attributes.Expires.Equal(certX509.NotAfter) {
continue
}
// 再对比 Tag 中的通用名称
if v, ok := certProp.Tags[TAG_CERTCN]; !ok || v == nil {
// 对比 Tag 中的通用名称
if v, ok := certItem.Tags[TAG_CERTCN]; !ok || v == nil {
continue
} else if *v != certCN {
continue
}
// 再对比 Tag 中的序列号
if v, ok := certProp.Tags[TAG_CERTSN]; !ok || v == nil {
// 对比 Tag 中的序列号
if v, ok := certItem.Tags[TAG_CERTSN]; !ok || v == nil {
continue
} else if *v != certSN {
continue
}
// 最后对比证书内容
getCertificateResp, err := m.sdkClient.GetCertificate(context.TODO(), certProp.ID.Name(), certProp.ID.Version(), nil)
m.logger.Debug("sdk request 'keyvault.GetCertificate'", slog.String("request.certificateName", certProp.ID.Name()), slog.String("request.certificateVersion", certProp.ID.Version()), slog.Any("response", getCertificateResp))
// 对比证书内容
getCertificateResp, err := m.sdkClient.GetCertificate(context.TODO(), certItem.ID.Name(), certItem.ID.Version(), nil)
m.logger.Debug("sdk request 'keyvault.GetCertificate'", slog.String("request.certificateName", certItem.ID.Name()), slog.String("request.certificateVersion", certItem.ID.Version()), slog.Any("response", getCertificateResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'keyvault.GetCertificate': %w", err)
} else {
@@ -126,8 +126,8 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
// 如果以上信息都一致,则视为已存在相同证书,直接返回
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: string(*certProp.ID),
CertName: certProp.ID.Name(),
CertId: string(*certItem.ID),
CertName: certItem.ID.Name(),
}, nil
}
}
@@ -67,27 +67,27 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'cert.ListCertDetail': %w", err)
} else {
for _, certDetail := range listCertDetail.Certs {
// 先对比证书通用名称
if !strings.EqualFold(certX509.Subject.CommonName, certDetail.CertCommonName) {
for _, certItem := range listCertDetail.Certs {
// 对比证书通用名称
if !strings.EqualFold(certX509.Subject.CommonName, certItem.CertCommonName) {
continue
}
// 再对比证书有效期
oldCertNotBefore, _ := time.Parse("2006-01-02T15:04:05Z", certDetail.CertStartTime)
oldCertNotAfter, _ := time.Parse("2006-01-02T15:04:05Z", certDetail.CertStopTime)
// 对比证书有效期
oldCertNotBefore, _ := time.Parse("2006-01-02T15:04:05Z", certItem.CertStartTime)
oldCertNotAfter, _ := time.Parse("2006-01-02T15:04:05Z", certItem.CertStopTime)
if !certX509.NotBefore.Equal(oldCertNotBefore) || !certX509.NotAfter.Equal(oldCertNotAfter) {
continue
}
// 再对比证书多域名
if certDetail.CertDNSNames != strings.Join(certX509.DNSNames, ",") {
// 对比证书多域名
if certItem.CertDNSNames != strings.Join(certX509.DNSNames, ",") {
continue
}
// 最后对比证书内容
getCertDetailResp, err := m.sdkClient.GetCertRawData(certDetail.CertId)
m.logger.Debug("sdk request 'cert.GetCertRawData'", slog.Any("certId", certDetail.CertId), slog.Any("response", getCertDetailResp))
// 对比证书内容
getCertDetailResp, err := m.sdkClient.GetCertRawData(certItem.CertId)
m.logger.Debug("sdk request 'cert.GetCertRawData'", slog.Any("certId", certItem.CertId), slog.Any("response", getCertDetailResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'cert.GetCertRawData': %w", err)
} else {
@@ -99,8 +99,8 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
// 如果以上信息都一致,则视为已存在相同证书,直接返回
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: certDetail.CertId,
CertName: certDetail.CertName,
CertId: certItem.CertId,
CertName: certItem.CertName,
}, nil
}
}
@@ -65,14 +65,8 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
// 查询证书列表,避免重复上传
// REF: https://docs.byteplus.com/en/docs/byteplus-cdn/reference-listcertinfo
listCertInfoPageNum := int64(1)
listCertInfoPageSize := int64(100)
listCertInfoTotal := 0
listCertInfoReq := &bytepluscdn.ListCertInfoRequest{
PageNum: bytepluscdn.GetInt64Ptr(listCertInfoPageNum),
PageSize: bytepluscdn.GetInt64Ptr(listCertInfoPageSize),
Source: bytepluscdn.GetStrPtr("cert_center"),
}
listCertInfoPageNum := 1
listCertInfoPageSize := 100
for {
select {
case <-ctx.Done():
@@ -80,36 +74,43 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
default:
}
listCertInfoReq := &bytepluscdn.ListCertInfoRequest{
PageNum: bytepluscdn.GetInt64Ptr(int64(listCertInfoPageNum)),
PageSize: bytepluscdn.GetInt64Ptr(int64(listCertInfoPageSize)),
Source: bytepluscdn.GetStrPtr("cert_center"),
}
listCertInfoResp, err := m.sdkClient.ListCertInfo(listCertInfoReq)
m.logger.Debug("sdk request 'cdn.ListCertInfo'", slog.Any("request", listCertInfoReq), slog.Any("response", listCertInfoResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'cdn.ListCertInfo': %w", err)
}
if listCertInfoResp.Result.CertInfo != nil {
for _, certInfo := range listCertInfoResp.Result.CertInfo {
fingerprintSha1 := sha1.Sum(certX509.Raw)
fingerprintSha256 := sha256.Sum256(certX509.Raw)
isSameCert := strings.EqualFold(hex.EncodeToString(fingerprintSha1[:]), certInfo.CertFingerprint.Sha1) &&
strings.EqualFold(hex.EncodeToString(fingerprintSha256[:]), certInfo.CertFingerprint.Sha256)
// 如果已存在相同证书,直接返回
if isSameCert {
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: certInfo.CertId,
CertName: certInfo.Desc,
}, nil
}
for _, certItem := range listCertInfoResp.Result.CertInfo {
// 对比证书 SHA-1 摘要
fingerprintSha1 := sha1.Sum(certX509.Raw)
if !strings.EqualFold(hex.EncodeToString(fingerprintSha1[:]), certItem.CertFingerprint.Sha1) {
continue
}
// 对比证书 SHA-256 摘要
fingerprintSha256 := sha256.Sum256(certX509.Raw)
if !strings.EqualFold(hex.EncodeToString(fingerprintSha256[:]), certItem.CertFingerprint.Sha256) {
continue
}
// 如果以上信息都一致,则视为已存在相同证书,直接返回
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: certItem.CertId,
CertName: certItem.Desc,
}, nil
}
listCertInfoLen := len(listCertInfoResp.Result.CertInfo)
if listCertInfoLen < int(listCertInfoPageSize) || int(listCertInfoResp.Result.Total) <= listCertInfoTotal+listCertInfoLen {
if len(listCertInfoResp.Result.CertInfo) < listCertInfoPageSize {
break
} else {
listCertInfoPageNum++
listCertInfoTotal += listCertInfoLen
}
listCertInfoPageNum++
}
// 生成新证书名(需符合 BytePlus 命名规则)
@@ -65,8 +65,9 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
// 查询用户名下证书列表,避免重复上传
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=113&api=13175&data=174&isNormal=1&vid=167
listCertPage := int32(1)
listCertPerPage := int32(1000)
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=113&api=13015&data=174&isNormal=1&vid=167
listCertPage := 1
listCertPerPage := 1000
for {
select {
case <-ctx.Done():
@@ -75,8 +76,8 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
}
listCertsReq := &ctyunao.ListCertsRequest{
Page: lo.ToPtr(listCertPage),
PerPage: lo.ToPtr(listCertPerPage),
Page: lo.ToPtr(int32(listCertPage)),
PerPage: lo.ToPtr(int32(listCertPerPage)),
UsageMode: lo.ToPtr(int32(0)),
}
listCertsResp, err := m.sdkClient.ListCerts(listCertsReq)
@@ -85,55 +86,55 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
return nil, fmt.Errorf("failed to execute sdk request 'ao.ListCerts': %w", err)
}
if listCertsResp.ReturnObj != nil {
for _, certRecord := range listCertsResp.ReturnObj.Results {
// 对比证书通用名称
if !strings.EqualFold(certX509.Subject.CommonName, certRecord.CN) {
continue
}
// 对比证书扩展名称
if !slices.Equal(certX509.DNSNames, certRecord.SANs) {
continue
}
// 对比证书有效期
if !certX509.NotBefore.Equal(time.Unix(certRecord.IssueTime, 0).UTC()) {
continue
} else if !certX509.NotAfter.Equal(time.Unix(certRecord.ExpiresTime, 0).UTC()) {
continue
}
// 最后对比证书内容
// 查询证书详情
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=113&api=13015&data=174&isNormal=1&vid=167
queryCertReq := &ctyunao.QueryCertRequest{
Id: lo.ToPtr(certRecord.Id),
}
queryCertResp, err := m.sdkClient.QueryCert(queryCertReq)
m.logger.Debug("sdk request 'ao.QueryCert'", slog.Any("request", queryCertReq), slog.Any("response", queryCertResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'ao.QueryCert': %w", err)
} else if queryCertResp.ReturnObj != nil && queryCertResp.ReturnObj.Result != nil {
if !xcert.EqualCertificatesFromPEM(certPEM, queryCertResp.ReturnObj.Result.Certs) {
continue
}
}
// 如果以上信息都一致,则视为已存在相同证书,直接返回
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: fmt.Sprintf("%d", queryCertResp.ReturnObj.Result.Id),
CertName: queryCertResp.ReturnObj.Result.Name,
}, nil
}
}
if listCertsResp.ReturnObj == nil || len(listCertsResp.ReturnObj.Results) < int(listCertPerPage) {
if listCertsResp.ReturnObj == nil {
break
} else {
listCertPage++
}
for _, certItem := range listCertsResp.ReturnObj.Results {
// 对比证书通用名称
if !strings.EqualFold(certX509.Subject.CommonName, certItem.CN) {
continue
}
// 对比证书扩展名称
if !slices.Equal(certX509.DNSNames, certItem.SANs) {
continue
}
// 对比证书有效期
if !certX509.NotBefore.Equal(time.Unix(certItem.IssueTime, 0).UTC()) {
continue
} else if !certX509.NotAfter.Equal(time.Unix(certItem.ExpiresTime, 0).UTC()) {
continue
}
// 对比证书内容
queryCertReq := &ctyunao.QueryCertRequest{
Id: lo.ToPtr(certItem.Id),
}
queryCertResp, err := m.sdkClient.QueryCert(queryCertReq)
m.logger.Debug("sdk request 'ao.QueryCert'", slog.Any("request", queryCertReq), slog.Any("response", queryCertResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'ao.QueryCert': %w", err)
} else if queryCertResp.ReturnObj != nil && queryCertResp.ReturnObj.Result != nil {
if !xcert.EqualCertificatesFromPEM(certPEM, queryCertResp.ReturnObj.Result.Certs) {
continue
}
}
// 如果以上信息都一致,则视为已存在相同证书,直接返回
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: fmt.Sprintf("%d", queryCertResp.ReturnObj.Result.Id),
CertName: queryCertResp.ReturnObj.Result.Name,
}, nil
}
if len(listCertsResp.ReturnObj.Results) < listCertPerPage {
break
}
listCertPage++
}
// 生成新证书名(需符合天翼云命名规则)
@@ -65,8 +65,9 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
// 查询证书列表,避免重复上传
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=108&api=10901&data=161&isNormal=1&vid=154
queryCertListPage := int32(1)
queryCertListPerPage := int32(1000)
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=108&api=10899&data=161&isNormal=1&vid=154
queryCertListPage := 1
queryCertListPerPage := 1000
for {
select {
case <-ctx.Done():
@@ -75,8 +76,8 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
}
queryCertListReq := &ctyuncdn.QueryCertListRequest{
Page: lo.ToPtr(queryCertListPage),
PerPage: lo.ToPtr(queryCertListPerPage),
Page: lo.ToPtr(int32(queryCertListPage)),
PerPage: lo.ToPtr(int32(queryCertListPerPage)),
UsageMode: lo.ToPtr(int32(0)),
}
queryCertListResp, err := m.sdkClient.QueryCertList(queryCertListReq)
@@ -85,55 +86,55 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
return nil, fmt.Errorf("failed to execute sdk request 'cdn.QueryCertList': %w", err)
}
if queryCertListResp.ReturnObj != nil {
for _, certRecord := range queryCertListResp.ReturnObj.Results {
// 对比证书通用名称
if !strings.EqualFold(certX509.Subject.CommonName, certRecord.CN) {
continue
}
// 对比证书扩展名称
if !slices.Equal(certX509.DNSNames, certRecord.SANs) {
continue
}
// 对比证书有效期
if !certX509.NotBefore.Equal(time.Unix(certRecord.IssueTime, 0).UTC()) {
continue
} else if !certX509.NotAfter.Equal(time.Unix(certRecord.ExpiresTime, 0).UTC()) {
continue
}
// 最后对比证书内容
// 查询证书详情
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=108&api=10899&data=161&isNormal=1&vid=154
queryCertDetailReq := &ctyuncdn.QueryCertDetailRequest{
Id: lo.ToPtr(certRecord.Id),
}
queryCertDetailResp, err := m.sdkClient.QueryCertDetail(queryCertDetailReq)
m.logger.Debug("sdk request 'cdn.QueryCertDetail'", slog.Any("request", queryCertDetailReq), slog.Any("response", queryCertDetailResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'cdn.QueryCertDetail': %w", err)
} else if queryCertDetailResp.ReturnObj != nil && queryCertDetailResp.ReturnObj.Result != nil {
if !xcert.EqualCertificatesFromPEM(certPEM, queryCertDetailResp.ReturnObj.Result.Certs) {
continue
}
}
// 如果以上信息都一致,则视为已存在相同证书,直接返回
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: fmt.Sprintf("%d", queryCertDetailResp.ReturnObj.Result.Id),
CertName: queryCertDetailResp.ReturnObj.Result.Name,
}, nil
}
}
if queryCertListResp.ReturnObj == nil || len(queryCertListResp.ReturnObj.Results) < int(queryCertListPerPage) {
if queryCertListResp.ReturnObj == nil {
break
} else {
queryCertListPage++
}
for _, certItem := range queryCertListResp.ReturnObj.Results {
// 对比证书通用名称
if !strings.EqualFold(certX509.Subject.CommonName, certItem.CN) {
continue
}
// 对比证书扩展名称
if !slices.Equal(certX509.DNSNames, certItem.SANs) {
continue
}
// 对比证书有效期
if !certX509.NotBefore.Equal(time.Unix(certItem.IssueTime, 0).UTC()) {
continue
} else if !certX509.NotAfter.Equal(time.Unix(certItem.ExpiresTime, 0).UTC()) {
continue
}
// 对比证书内容
queryCertDetailReq := &ctyuncdn.QueryCertDetailRequest{
Id: lo.ToPtr(certItem.Id),
}
queryCertDetailResp, err := m.sdkClient.QueryCertDetail(queryCertDetailReq)
m.logger.Debug("sdk request 'cdn.QueryCertDetail'", slog.Any("request", queryCertDetailReq), slog.Any("response", queryCertDetailResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'cdn.QueryCertDetail': %w", err)
} else if queryCertDetailResp.ReturnObj != nil && queryCertDetailResp.ReturnObj.Result != nil {
if !xcert.EqualCertificatesFromPEM(certPEM, queryCertDetailResp.ReturnObj.Result.Certs) {
continue
}
}
// 如果以上信息都一致,则视为已存在相同证书,直接返回
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: fmt.Sprintf("%d", queryCertDetailResp.ReturnObj.Result.Id),
CertName: queryCertDetailResp.ReturnObj.Result.Name,
}, nil
}
if len(queryCertListResp.ReturnObj.Results) < queryCertListPerPage {
break
}
queryCertListPage++
}
// 生成新证书名(需符合天翼云命名规则)
@@ -59,7 +59,10 @@ func (m *SSLManagerProvider) SetLogger(logger *slog.Logger) {
func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkeyPEM string) (*core.SSLManageUploadResult, error) {
// 避免重复上传
if res, _ := m.findCertIfExists(ctx, certPEM); res != nil {
if res, err := m.tryFindCert(ctx, certPEM); err != nil {
return nil, err
} else if res != nil {
m.logger.Info("ssl certificate already exists")
return res, nil
}
@@ -85,7 +88,7 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
m.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 := m.findCertIfExists(ctx, certPEM); err != nil {
if res, err := m.tryFindCert(ctx, certPEM); err != nil {
return nil, err
} else if res == nil {
return nil, errors.New("ctyun cms: no certificate found")
@@ -99,16 +102,16 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
}
// 获取刚刚上传证书 ID
if res, err := m.findCertIfExists(ctx, certPEM); err != nil {
if res, err := m.tryFindCert(ctx, certPEM); err != nil {
return nil, err
} else if res == nil {
return nil, fmt.Errorf("no ssl certificate found, may be upload failed")
return nil, fmt.Errorf("could not find ssl certificate, may be upload failed")
} else {
return res, nil
}
}
func (m *SSLManagerProvider) findCertIfExists(ctx context.Context, certPEM string) (*core.SSLManageUploadResult, error) {
func (m *SSLManagerProvider) tryFindCert(ctx context.Context, certPEM string) (*core.SSLManageUploadResult, error) {
// 解析证书内容
certX509, err := xcert.ParseCertificateFromPEM(certPEM)
if err != nil {
@@ -117,8 +120,8 @@ func (m *SSLManagerProvider) findCertIfExists(ctx context.Context, certPEM strin
// 查询用户证书列表
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=152&api=17233&data=204&isNormal=1&vid=283
getCertificateListPageNum := int32(1)
getCertificateListPageSize := int32(10)
getCertificateListPageNum := 1
getCertificateListPageSize := 10
for {
select {
case <-ctx.Done():
@@ -127,8 +130,8 @@ func (m *SSLManagerProvider) findCertIfExists(ctx context.Context, certPEM strin
}
getCertificateListReq := &ctyuncms.GetCertificateListRequest{
PageNum: lo.ToPtr(getCertificateListPageNum),
PageSize: lo.ToPtr(getCertificateListPageSize),
PageNum: lo.ToPtr(int32(getCertificateListPageNum)),
PageSize: lo.ToPtr(int32(getCertificateListPageSize)),
Keyword: lo.ToPtr(certX509.Subject.CommonName),
Origin: lo.ToPtr("UPLOAD"),
}
@@ -138,44 +141,45 @@ func (m *SSLManagerProvider) findCertIfExists(ctx context.Context, certPEM strin
return nil, fmt.Errorf("failed to execute sdk request 'cms.GetCertificateList': %w", err)
}
if getCertificateListResp.ReturnObj != nil {
if getCertificateListResp.ReturnObj == nil {
break
}
for _, certItem := range getCertificateListResp.ReturnObj.List {
// 对比证书名称
if !strings.EqualFold(strings.Join(certX509.DNSNames, ","), certItem.DomainName) {
continue
}
// 对比证书有效期
oldCertNotBefore, _ := time.Parse("2006-01-02T15:04:05Z", certItem.IssueTime)
oldCertNotAfter, _ := time.Parse("2006-01-02T15:04:05Z", certItem.ExpireTime)
if !certX509.NotBefore.Equal(oldCertNotBefore) {
continue
} else if !certX509.NotAfter.Equal(oldCertNotAfter) {
continue
}
// 对比证书指纹
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
}
// 如果以上信息都一致,则视为已存在相同证书,直接返回
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: string(*&certRecord.Id),
CertName: certRecord.Name,
}, nil
if !strings.EqualFold(fingerprintHex, certItem.Fingerprint) {
continue
}
// 如果以上信息都一致,则视为已存在相同证书,直接返回
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: certItem.Id,
CertName: certItem.Name,
}, nil
}
if getCertificateListResp.ReturnObj == nil || len(getCertificateListResp.ReturnObj.List) < int(getCertificateListPageSize) {
if len(getCertificateListResp.ReturnObj.List) < getCertificateListPageSize {
break
} else {
getCertificateListPageNum++
}
getCertificateListPageNum++
}
return nil, nil
@@ -68,13 +68,13 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'elb.ListCertificates': %w", err)
} else {
for _, certRecord := range listCertificatesResp.ReturnObj {
for _, certItem := range listCertificatesResp.ReturnObj {
// 如果已存在相同证书,直接返回
if xcert.EqualCertificatesFromPEM(certPEM, certRecord.Certificate) {
if xcert.EqualCertificatesFromPEM(certPEM, certItem.Certificate) {
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: certRecord.ID,
CertName: certRecord.Name,
CertId: certItem.ID,
CertName: certItem.Name,
}, nil
}
}
@@ -65,8 +65,9 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
// 查询证书列表,避免重复上传
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=112&api=10838&data=173&isNormal=1&vid=166
queryCertListPage := int32(1)
queryCertListPerPage := int32(1000)
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=112&api=10837&data=173&isNormal=1&vid=166
queryCertListPage := 1
queryCertListPerPage := 1000
for {
select {
case <-ctx.Done():
@@ -75,8 +76,8 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
}
queryCertListReq := &ctyunicdn.QueryCertListRequest{
Page: lo.ToPtr(queryCertListPage),
PerPage: lo.ToPtr(queryCertListPerPage),
Page: lo.ToPtr(int32(queryCertListPage)),
PerPage: lo.ToPtr(int32(queryCertListPerPage)),
UsageMode: lo.ToPtr(int32(0)),
}
queryCertListResp, err := m.sdkClient.QueryCertList(queryCertListReq)
@@ -85,55 +86,55 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
return nil, fmt.Errorf("failed to execute sdk request 'icdn.QueryCertList': %w", err)
}
if queryCertListResp.ReturnObj != nil {
for _, certRecord := range queryCertListResp.ReturnObj.Results {
// 对比证书通用名称
if !strings.EqualFold(certX509.Subject.CommonName, certRecord.CN) {
continue
}
// 对比证书扩展名称
if !slices.Equal(certX509.DNSNames, certRecord.SANs) {
continue
}
// 对比证书有效期
if !certX509.NotBefore.Equal(time.Unix(certRecord.IssueTime, 0).UTC()) {
continue
} else if !certX509.NotAfter.Equal(time.Unix(certRecord.ExpiresTime, 0).UTC()) {
continue
}
// 最后对比证书内容
// 查询证书详情
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=112&api=10837&data=173&isNormal=1&vid=166
queryCertDetailReq := &ctyunicdn.QueryCertDetailRequest{
Id: lo.ToPtr(certRecord.Id),
}
queryCertDetailResp, err := m.sdkClient.QueryCertDetail(queryCertDetailReq)
m.logger.Debug("sdk request 'icdn.QueryCertDetail'", slog.Any("request", queryCertDetailReq), slog.Any("response", queryCertDetailResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'icdn.QueryCertDetail': %w", err)
} else if queryCertDetailResp.ReturnObj != nil && queryCertDetailResp.ReturnObj.Result != nil {
if !xcert.EqualCertificatesFromPEM(certPEM, queryCertDetailResp.ReturnObj.Result.Certs) {
continue
}
}
// 如果以上信息都一致,则视为已存在相同证书,直接返回
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: fmt.Sprintf("%d", queryCertDetailResp.ReturnObj.Result.Id),
CertName: queryCertDetailResp.ReturnObj.Result.Name,
}, nil
}
}
if queryCertListResp.ReturnObj == nil || len(queryCertListResp.ReturnObj.Results) < int(queryCertListPerPage) {
if queryCertListResp.ReturnObj == nil {
break
} else {
queryCertListPage++
}
for _, certItem := range queryCertListResp.ReturnObj.Results {
// 对比证书通用名称
if !strings.EqualFold(certX509.Subject.CommonName, certItem.CN) {
continue
}
// 对比证书扩展名称
if !slices.Equal(certX509.DNSNames, certItem.SANs) {
continue
}
// 对比证书有效期
if !certX509.NotBefore.Equal(time.Unix(certItem.IssueTime, 0).UTC()) {
continue
} else if !certX509.NotAfter.Equal(time.Unix(certItem.ExpiresTime, 0).UTC()) {
continue
}
// 对比证书内容
queryCertDetailReq := &ctyunicdn.QueryCertDetailRequest{
Id: lo.ToPtr(certItem.Id),
}
queryCertDetailResp, err := m.sdkClient.QueryCertDetail(queryCertDetailReq)
m.logger.Debug("sdk request 'icdn.QueryCertDetail'", slog.Any("request", queryCertDetailReq), slog.Any("response", queryCertDetailResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'icdn.QueryCertDetail': %w", err)
} else if queryCertDetailResp.ReturnObj != nil && queryCertDetailResp.ReturnObj.Result != nil {
if !xcert.EqualCertificatesFromPEM(certPEM, queryCertDetailResp.ReturnObj.Result.Certs) {
continue
}
}
// 如果以上信息都一致,则视为已存在相同证书,直接返回
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: fmt.Sprintf("%d", queryCertDetailResp.ReturnObj.Result.Id),
CertName: queryCertDetailResp.ReturnObj.Result.Name,
}, nil
}
if len(queryCertListResp.ReturnObj.Results) < queryCertListPerPage {
break
}
queryCertListPage++
}
// 生成新证书名(需符合天翼云命名规则)
@@ -65,8 +65,9 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
// 查询证书列表,避免重复上传
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=125&api=11452&data=183&isNormal=1&vid=261
queryCertListPage := int32(1)
queryCertListPerPage := int32(1000)
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=125&api=11449&data=183&isNormal=1&vid=261
queryCertListPage := 1
queryCertListPerPage := 1000
for {
select {
case <-ctx.Done():
@@ -75,8 +76,8 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
}
queryCertListReq := &ctyunlvdn.QueryCertListRequest{
Page: lo.ToPtr(queryCertListPage),
PerPage: lo.ToPtr(queryCertListPerPage),
Page: lo.ToPtr(int32(queryCertListPage)),
PerPage: lo.ToPtr(int32(queryCertListPerPage)),
UsageMode: lo.ToPtr(int32(0)),
}
queryCertListResp, err := m.sdkClient.QueryCertList(queryCertListReq)
@@ -85,55 +86,55 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
return nil, fmt.Errorf("failed to execute sdk request 'lvdn.QueryCertList': %w", err)
}
if queryCertListResp.ReturnObj != nil {
for _, certRecord := range queryCertListResp.ReturnObj.Results {
// 对比证书通用名称
if !strings.EqualFold(certX509.Subject.CommonName, certRecord.CN) {
continue
}
// 对比证书扩展名称
if !slices.Equal(certX509.DNSNames, certRecord.SANs) {
continue
}
// 对比证书有效期
if !certX509.NotBefore.Equal(time.Unix(certRecord.IssueTime, 0).UTC()) {
continue
} else if !certX509.NotAfter.Equal(time.Unix(certRecord.ExpiresTime, 0).UTC()) {
continue
}
// 最后对比证书内容
// 查询证书详情
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=125&api=11449&data=183&isNormal=1&vid=261
queryCertDetailReq := &ctyunlvdn.QueryCertDetailRequest{
Id: lo.ToPtr(certRecord.Id),
}
queryCertDetailResp, err := m.sdkClient.QueryCertDetail(queryCertDetailReq)
m.logger.Debug("sdk request 'lvdn.QueryCertDetail'", slog.Any("request", queryCertDetailReq), slog.Any("response", queryCertDetailResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'lvdn.QueryCertDetail': %w", err)
} else if queryCertDetailResp.ReturnObj != nil && queryCertDetailResp.ReturnObj.Result != nil {
if !xcert.EqualCertificatesFromPEM(certPEM, queryCertDetailResp.ReturnObj.Result.Certs) {
continue
}
}
// 如果以上信息都一致,则视为已存在相同证书,直接返回
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: fmt.Sprintf("%d", queryCertDetailResp.ReturnObj.Result.Id),
CertName: queryCertDetailResp.ReturnObj.Result.Name,
}, nil
}
}
if queryCertListResp.ReturnObj == nil || len(queryCertListResp.ReturnObj.Results) < int(queryCertListPerPage) {
if queryCertListResp.ReturnObj == nil {
break
} else {
queryCertListPage++
}
for _, certItem := range queryCertListResp.ReturnObj.Results {
// 对比证书通用名称
if !strings.EqualFold(certX509.Subject.CommonName, certItem.CN) {
continue
}
// 对比证书扩展名称
if !slices.Equal(certX509.DNSNames, certItem.SANs) {
continue
}
// 对比证书有效期
if !certX509.NotBefore.Equal(time.Unix(certItem.IssueTime, 0).UTC()) {
continue
} else if !certX509.NotAfter.Equal(time.Unix(certItem.ExpiresTime, 0).UTC()) {
continue
}
// 对比证书内容
queryCertDetailReq := &ctyunlvdn.QueryCertDetailRequest{
Id: lo.ToPtr(certItem.Id),
}
queryCertDetailResp, err := m.sdkClient.QueryCertDetail(queryCertDetailReq)
m.logger.Debug("sdk request 'lvdn.QueryCertDetail'", slog.Any("request", queryCertDetailReq), slog.Any("response", queryCertDetailResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'lvdn.QueryCertDetail': %w", err)
} else if queryCertDetailResp.ReturnObj != nil && queryCertDetailResp.ReturnObj.Result != nil {
if !xcert.EqualCertificatesFromPEM(certPEM, queryCertDetailResp.ReturnObj.Result.Certs) {
continue
}
}
// 如果以上信息都一致,则视为已存在相同证书,直接返回
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: fmt.Sprintf("%d", queryCertDetailResp.ReturnObj.Result.Id),
CertName: queryCertDetailResp.ReturnObj.Result.Name,
}, nil
}
if len(queryCertListResp.ReturnObj.Results) < queryCertListPerPage {
break
}
queryCertListPage++
}
// 生成新证书名(需符合天翼云命名规则)
@@ -69,8 +69,7 @@ func (m *SSLManagerProvider) SetLogger(logger *slog.Logger) {
func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkeyPEM string) (*core.SSLManageUploadResult, error) {
// 查询已有证书,避免重复上传
// REF: https://support.huaweicloud.com/api-elb/ListCertificates.html
listCertificatesLimit := int32(2000)
var listCertificatesMarker *string = nil
listCertificatesMarker := (*string)(nil)
for {
select {
case <-ctx.Done():
@@ -79,9 +78,9 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
}
listCertificatesReq := &hcelbmodel.ListCertificatesRequest{
Limit: lo.ToPtr(listCertificatesLimit),
Marker: listCertificatesMarker,
Type: &[]string{"server"},
Limit: lo.ToPtr(int32(2000)),
Type: lo.ToPtr([]string{"server"}),
}
listCertificatesResp, err := m.sdkClient.ListCertificates(listCertificatesReq)
m.logger.Debug("sdk request 'elb.ListCertificates'", slog.Any("request", listCertificatesReq), slog.Any("response", listCertificatesResp))
@@ -89,24 +88,26 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
return nil, fmt.Errorf("failed to execute sdk request 'elb.ListCertificates': %w", err)
}
if listCertificatesResp.Certificates != nil {
for _, certInfo := range *listCertificatesResp.Certificates {
// 如果已存在相同证书,直接返回
if xcert.EqualCertificatesFromPEM(certPEM, certInfo.Certificate) {
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: certInfo.Id,
CertName: certInfo.Name,
}, nil
}
if listCertificatesResp.Certificates == nil {
break
}
for _, certItem := range *listCertificatesResp.Certificates {
// 如果已存在相同证书,直接返回
if xcert.EqualCertificatesFromPEM(certPEM, certItem.Certificate) {
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: certItem.Id,
CertName: certItem.Name,
}, nil
}
}
if listCertificatesResp.Certificates == nil || len(*listCertificatesResp.Certificates) < int(listCertificatesLimit) {
if len(*listCertificatesResp.Certificates) == 0 || listCertificatesResp.PageInfo.NextMarker == nil {
break
} else {
listCertificatesMarker = listCertificatesResp.PageInfo.NextMarker
}
listCertificatesMarker = listCertificatesResp.PageInfo.NextMarker
}
// 获取项目 ID
@@ -73,8 +73,8 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
// 查询已有证书,避免重复上传
// REF: https://support.huaweicloud.com/api-ccm/ListCertificates.html
// REF: https://support.huaweicloud.com/api-ccm/ExportCertificate_0.html
listCertificatesLimit := int32(50)
listCertificatesOffset := int32(0)
listCertificatesLimit := 50
listCertificatesOffset := 0
for {
select {
case <-ctx.Done():
@@ -84,8 +84,8 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
listCertificatesReq := &hcscmmodel.ListCertificatesRequest{
EnterpriseProjectId: lo.EmptyableToPtr(m.config.EnterpriseProjectId),
Limit: lo.ToPtr(listCertificatesLimit),
Offset: lo.ToPtr(listCertificatesOffset),
Limit: lo.ToPtr(int32(listCertificatesLimit)),
Offset: lo.ToPtr(int32(listCertificatesOffset)),
SortDir: lo.ToPtr("DESC"),
SortKey: lo.ToPtr("certExpiredTime"),
}
@@ -95,51 +95,51 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
return nil, fmt.Errorf("failed to execute sdk request 'scm.ListCertificates': %w", err)
}
if listCertificatesResp.Certificates != nil {
for _, certDetail := range *listCertificatesResp.Certificates {
// 先对比证书通用名称
if !strings.EqualFold(certX509.Subject.CommonName, certDetail.Domain) {
continue
}
// 再对比证书有效期
if certX509.NotAfter.Local().Format(time.DateTime) != strings.TrimSuffix(certDetail.ExpireTime, ".0") {
continue
}
// 最后对比证书内容
// 导出证书
// REF: https://support.huaweicloud.com/api-ccm/ExportCertificate_0.html
exportCertificateReq := &hcscmmodel.ExportCertificateRequest{
CertificateId: certDetail.Id,
}
exportCertificateResp, err := m.sdkClient.ExportCertificate(exportCertificateReq)
m.logger.Debug("sdk request 'scm.ExportCertificate'", slog.Any("request", exportCertificateReq), slog.Any("response", exportCertificateResp))
if err != nil {
if exportCertificateResp != nil && exportCertificateResp.HttpStatusCode == 404 {
continue
}
return nil, fmt.Errorf("failed to execute sdk request 'scm.ExportCertificate': %w", err)
} else {
if !xcert.EqualCertificatesFromPEM(certPEM, lo.FromPtr(exportCertificateResp.Certificate)) {
continue
}
}
// 如果以上信息都一致,则视为已存在相同证书,直接返回
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: certDetail.Id,
CertName: certDetail.Name,
}, nil
}
}
if listCertificatesResp.Certificates == nil || len(*listCertificatesResp.Certificates) < int(listCertificatesLimit) {
if listCertificatesResp.Certificates == nil {
break
} else {
listCertificatesOffset += listCertificatesLimit
}
for _, certItem := range *listCertificatesResp.Certificates {
// 对比证书通用名称
if !strings.EqualFold(certX509.Subject.CommonName, certItem.Domain) {
continue
}
// 对比证书有效期
if certX509.NotAfter.Local().Format(time.DateTime) != strings.TrimSuffix(certItem.ExpireTime, ".0") {
continue
}
// 对比证书内容
exportCertificateReq := &hcscmmodel.ExportCertificateRequest{
CertificateId: certItem.Id,
}
exportCertificateResp, err := m.sdkClient.ExportCertificate(exportCertificateReq)
m.logger.Debug("sdk request 'scm.ExportCertificate'", slog.Any("request", exportCertificateReq), slog.Any("response", exportCertificateResp))
if err != nil {
if exportCertificateResp != nil && exportCertificateResp.HttpStatusCode == 404 {
continue
}
return nil, fmt.Errorf("failed to execute sdk request 'scm.ExportCertificate': %w", err)
} else {
if !xcert.EqualCertificatesFromPEM(certPEM, lo.FromPtr(exportCertificateResp.Certificate)) {
continue
}
}
// 如果以上信息都一致,则视为已存在相同证书,直接返回
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: certItem.Id,
CertName: certItem.Name,
}, nil
}
if len(*listCertificatesResp.Certificates) < listCertificatesLimit {
break
}
listCertificatesOffset += listCertificatesLimit
}
// 生成新证书名(需符合华为云命名规则)
@@ -70,8 +70,8 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
// 查询已有证书,避免重复上传
// REF: https://support.huaweicloud.com/api-waf/ListCertificates.html
// REF: https://support.huaweicloud.com/api-waf/ShowCertificate.html
listCertificatesPage := int32(1)
listCertificatesPageSize := int32(100)
listCertificatesPage := 1
listCertificatesPageSize := 100
for {
select {
case <-ctx.Done():
@@ -81,8 +81,8 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
listCertificatesReq := &hcwafmodel.ListCertificatesRequest{
EnterpriseProjectId: lo.EmptyableToPtr(m.config.EnterpriseProjectId),
Page: lo.ToPtr(listCertificatesPage),
Pagesize: lo.ToPtr(listCertificatesPageSize),
Page: lo.ToPtr(int32(listCertificatesPage)),
Pagesize: lo.ToPtr(int32(listCertificatesPageSize)),
}
listCertificatesResp, err := m.sdkClient.ListCertificates(listCertificatesReq)
m.logger.Debug("sdk request 'waf.ShowCertificate'", slog.Any("request", listCertificatesReq), slog.Any("response", listCertificatesResp))
@@ -90,34 +90,36 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
return nil, fmt.Errorf("failed to execute sdk request 'waf.ListCertificates': %w", err)
}
if listCertificatesResp.Items != nil {
for _, certItem := range *listCertificatesResp.Items {
showCertificateReq := &hcwafmodel.ShowCertificateRequest{
EnterpriseProjectId: lo.EmptyableToPtr(m.config.EnterpriseProjectId),
CertificateId: certItem.Id,
}
showCertificateResp, err := m.sdkClient.ShowCertificate(showCertificateReq)
m.logger.Debug("sdk request 'waf.ShowCertificate'", slog.Any("request", showCertificateReq), slog.Any("response", showCertificateResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'waf.ShowCertificate': %w", err)
}
if listCertificatesResp.Items == nil {
break
}
// 如果已存在相同证书,直接返回
if xcert.EqualCertificatesFromPEM(certPEM, lo.FromPtr(showCertificateResp.Content)) {
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: certItem.Id,
CertName: certItem.Name,
}, nil
}
for _, certItem := range *listCertificatesResp.Items {
showCertificateReq := &hcwafmodel.ShowCertificateRequest{
EnterpriseProjectId: lo.EmptyableToPtr(m.config.EnterpriseProjectId),
CertificateId: certItem.Id,
}
showCertificateResp, err := m.sdkClient.ShowCertificate(showCertificateReq)
m.logger.Debug("sdk request 'waf.ShowCertificate'", slog.Any("request", showCertificateReq), slog.Any("response", showCertificateResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'waf.ShowCertificate': %w", err)
}
// 如果已存在相同证书,直接返回
if xcert.EqualCertificatesFromPEM(certPEM, lo.FromPtr(showCertificateResp.Content)) {
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: certItem.Id,
CertName: certItem.Name,
}, nil
}
}
if listCertificatesResp.Items == nil || len(*listCertificatesResp.Items) < int(listCertificatesPageSize) {
if len(*listCertificatesResp.Items) < listCertificatesPageSize {
break
} else {
listCertificatesPage++
}
listCertificatesPage++
}
// 生成新证书名(需符合华为云命名规则)
@@ -92,36 +92,36 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
return nil, fmt.Errorf("failed to execute sdk request 'ssl.DescribeCerts': %w", err)
}
for _, certDetail := range describeCertsResp.Result.CertListDetails {
// 先对比证书通用名称
if !strings.EqualFold(certX509.Subject.CommonName, certDetail.CommonName) {
for _, certItem := range describeCertsResp.Result.CertListDetails {
// 对比证书通用名称
if !strings.EqualFold(certX509.Subject.CommonName, certItem.CommonName) {
continue
}
// 再对比证书多域名
if !strings.EqualFold(strings.Join(certX509.DNSNames, ","), strings.Join(certDetail.DnsNames, ",")) {
// 对比证书多域名
if !strings.EqualFold(strings.Join(certX509.DNSNames, ","), strings.Join(certItem.DnsNames, ",")) {
continue
}
// 再对比证书有效期
oldCertNotBefore, _ := time.Parse(time.RFC3339, certDetail.StartTime)
oldCertNotAfter, _ := time.Parse(time.RFC3339, certDetail.EndTime)
// 对比证书有效期
oldCertNotBefore, _ := time.Parse(time.RFC3339, certItem.StartTime)
oldCertNotAfter, _ := time.Parse(time.RFC3339, certItem.EndTime)
if !certX509.NotBefore.Equal(oldCertNotBefore) || !certX509.NotAfter.Equal(oldCertNotAfter) {
continue
}
// 最后对比私钥摘要
// 对比私钥 SHA-256 摘要
newKeyDigest := sha256.Sum256([]byte(privkeyPEM))
newKeyDigestHex := hex.EncodeToString(newKeyDigest[:])
if !strings.EqualFold(newKeyDigestHex, certDetail.Digest) {
if !strings.EqualFold(newKeyDigestHex, certItem.Digest) {
continue
}
// 如果以上信息都一致,则视为已存在相同证书,直接返回
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: certDetail.CertId,
CertName: certDetail.CertName,
CertId: certItem.CertId,
CertName: certItem.CertName,
}, nil
}
@@ -69,7 +69,6 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
// 查询已有证书,避免重复上传
getSslCertListMarker := ""
getSslCertListLimit := int32(200)
for {
select {
case <-ctx.Done():
@@ -77,62 +76,60 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
default:
}
getSslCertListResp, err := m.sdkClient.GetSslCertList(context.TODO(), getSslCertListMarker, getSslCertListLimit)
getSslCertListResp, err := m.sdkClient.GetSslCertList(context.TODO(), getSslCertListMarker, 200)
m.logger.Debug("sdk request 'sslcert.GetList'", slog.Any("request.marker", getSslCertListMarker), slog.Any("response", getSslCertListResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'sslcert.GetList': %w", err)
}
if getSslCertListResp.Certs != nil {
for _, sslCert := range getSslCertListResp.Certs {
// 先对比证书通用名称
if !strings.EqualFold(certX509.Subject.CommonName, sslCert.CommonName) {
continue
}
// 再对比证书多域名
if !slices.Equal(certX509.DNSNames, sslCert.DnsNames) {
continue
}
// 再对比证书有效期
if certX509.NotBefore.Unix() != sslCert.NotBefore || certX509.NotAfter.Unix() != sslCert.NotAfter {
continue
}
// 最后对比证书公钥算法
switch certX509.PublicKeyAlgorithm {
case x509.RSA:
if !strings.EqualFold(sslCert.Encrypt, "RSA") {
continue
}
case x509.ECDSA:
if !strings.EqualFold(sslCert.Encrypt, "ECDSA") {
continue
}
case x509.Ed25519:
if !strings.EqualFold(sslCert.Encrypt, "ED25519") {
continue
}
default:
// 未知算法,跳过
continue
}
// 如果以上信息都一致,则视为已存在相同证书,直接返回
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: sslCert.CertID,
CertName: sslCert.Name,
}, nil
for _, sslItem := range getSslCertListResp.Certs {
// 对比证书通用名称
if !strings.EqualFold(certX509.Subject.CommonName, sslItem.CommonName) {
continue
}
// 对比证书多域名
if !slices.Equal(certX509.DNSNames, sslItem.DnsNames) {
continue
}
// 对比证书有效期
if certX509.NotBefore.Unix() != sslItem.NotBefore || certX509.NotAfter.Unix() != sslItem.NotAfter {
continue
}
// 对比证书公钥算法
switch certX509.PublicKeyAlgorithm {
case x509.RSA:
if !strings.EqualFold(sslItem.Encrypt, "RSA") {
continue
}
case x509.ECDSA:
if !strings.EqualFold(sslItem.Encrypt, "ECDSA") {
continue
}
case x509.Ed25519:
if !strings.EqualFold(sslItem.Encrypt, "ED25519") {
continue
}
default:
// 未知算法,跳过
continue
}
// 如果以上信息都一致,则视为已存在相同证书,直接返回
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: sslItem.CertID,
CertName: sslItem.Name,
}, nil
}
if len(getSslCertListResp.Certs) < int(getSslCertListLimit) || getSslCertListResp.Marker == "" {
if len(getSslCertListResp.Certs) == 0 || getSslCertListResp.Marker == "" {
break
} else {
getSslCertListMarker = getSslCertListResp.Marker
}
getSslCertListMarker = getSslCertListResp.Marker
}
// 上传新证书
@@ -10,6 +10,7 @@ import (
"github.com/certimate-go/certimate/pkg/core"
rainyunsdk "github.com/certimate-go/certimate/pkg/sdk3rd/rainyun"
xcert "github.com/certimate-go/certimate/pkg/utils/cert"
"github.com/samber/lo"
)
type SSLManagerProviderConfig struct {
@@ -52,7 +53,7 @@ func (m *SSLManagerProvider) SetLogger(logger *slog.Logger) {
func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkeyPEM string) (*core.SSLManageUploadResult, error) {
// 避免重复上传
if res, err := m.findCertIfExists(ctx, certPEM); err != nil {
if res, err := m.tryFindCert(ctx, certPEM); err != nil {
return nil, err
} else if res != nil {
m.logger.Info("ssl certificate already exists")
@@ -72,16 +73,16 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
}
// 获取刚刚上传证书 ID
if res, err := m.findCertIfExists(ctx, certPEM); err != nil {
if res, err := m.tryFindCert(ctx, certPEM); err != nil {
return nil, err
} else if res == nil {
return nil, errors.New("no ssl certificate found, may be upload failed")
return nil, errors.New("could not find ssl certificate, may be upload failed")
} else {
return res, nil
}
}
func (m *SSLManagerProvider) findCertIfExists(ctx context.Context, certPEM string) (*core.SSLManageUploadResult, error) {
func (m *SSLManagerProvider) tryFindCert(ctx context.Context, certPEM string) (*core.SSLManageUploadResult, error) {
// 解析证书内容
certX509, err := xcert.ParseCertificateFromPEM(certPEM)
if err != nil {
@@ -91,8 +92,8 @@ func (m *SSLManagerProvider) findCertIfExists(ctx context.Context, certPEM strin
// 获取 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)
sslCenterListPerPage := int32(100)
sslCenterListPage := 1
sslCenterListPerPage := 100
for {
select {
case <-ctx.Done():
@@ -104,8 +105,8 @@ func (m *SSLManagerProvider) findCertIfExists(ctx context.Context, certPEM strin
Filters: &rainyunsdk.SslCenterListFilters{
Domain: &certX509.Subject.CommonName,
},
Page: &sslCenterListPage,
PerPage: &sslCenterListPerPage,
Page: lo.ToPtr(int32(sslCenterListPage)),
PerPage: lo.ToPtr(int32(sslCenterListPerPage)),
}
sslCenterListResp, err := m.sdkClient.SslCenterList(sslCenterListReq)
m.logger.Debug("sdk request 'sslcenter.List'", slog.Any("request", sslCenterListReq), slog.Any("response", sslCenterListResp))
@@ -113,40 +114,42 @@ func (m *SSLManagerProvider) findCertIfExists(ctx context.Context, certPEM strin
return nil, fmt.Errorf("failed to execute sdk request 'sslcenter.List': %w", err)
}
if sslCenterListResp.Data != nil && sslCenterListResp.Data.Records != nil {
for _, sslRecord := range sslCenterListResp.Data.Records {
// 先对比证书的多域名
if sslRecord.Domain != strings.Join(certX509.DNSNames, ", ") {
continue
}
// 再对比证书的有效期
if sslRecord.StartDate != certX509.NotBefore.Unix() || sslRecord.ExpireDate != certX509.NotAfter.Unix() {
continue
}
// 最后对比证书内容
sslCenterGetResp, err := m.sdkClient.SslCenterGet(sslRecord.ID)
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'sslcenter.Get': %w", err)
} else {
if !xcert.EqualCertificatesFromPEM(certPEM, sslCenterGetResp.Data.Cert) {
continue
}
}
// 如果以上信息都一致,则视为已存在相同证书,直接返回
return &core.SSLManageUploadResult{
CertId: fmt.Sprintf("%d", sslRecord.ID),
}, nil
}
}
if sslCenterListResp.Data == nil || len(sslCenterListResp.Data.Records) < int(sslCenterListPerPage) {
if sslCenterListResp.Data == nil {
break
} else {
sslCenterListPage++
}
for _, sslItem := range sslCenterListResp.Data.Records {
// 对比证书的多域名
if sslItem.Domain != strings.Join(certX509.DNSNames, ", ") {
continue
}
// 对比证书的有效期
if sslItem.StartDate != certX509.NotBefore.Unix() || sslItem.ExpireDate != certX509.NotAfter.Unix() {
continue
}
// 对比证书内容
sslCenterGetResp, err := m.sdkClient.SslCenterGet(sslItem.ID)
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'sslcenter.Get': %w", err)
} else {
if !xcert.EqualCertificatesFromPEM(certPEM, sslCenterGetResp.Data.Cert) {
continue
}
}
// 如果以上信息都一致,则视为已存在相同证书,直接返回
return &core.SSLManageUploadResult{
CertId: fmt.Sprintf("%d", sslItem.ID),
}, nil
}
if len(sslCenterListResp.Data.Records) < sslCenterListPerPage {
break
}
sslCenterListPage++
}
return nil, nil
@@ -86,10 +86,10 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
m.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 := m.findCertIfExists(ctx, certPEM); err != nil {
if res, err := m.tryFindCert(ctx, certPEM); err != nil {
return nil, err
} else if res == nil {
return nil, errors.New("ucloud ssl: no certificate found")
return nil, errors.New("could not find ssl certificate, may be upload failed")
} else {
m.logger.Info("ssl certificate already exists")
return res, nil
@@ -108,7 +108,7 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
}, nil
}
func (m *SSLManagerProvider) findCertIfExists(ctx context.Context, certPEM string) (*core.SSLManageUploadResult, error) {
func (m *SSLManagerProvider) tryFindCert(ctx context.Context, certPEM string) (*core.SSLManageUploadResult, error) {
// 解析证书内容
certX509, err := xcert.ParseCertificateFromPEM(certPEM)
if err != nil {
@@ -118,8 +118,8 @@ func (m *SSLManagerProvider) findCertIfExists(ctx context.Context, certPEM strin
// 查询用户证书列表
// REF: https://docs.ucloud.cn/api/usslcertificate-api/get_certificate_list
// REF: https://docs.ucloud.cn/api/usslcertificate-api/download_certificate
getCertificateListPage := int(1)
getCertificateListLimit := int(1000)
getCertificateListPage := 1
getCertificateListLimit := 1000
for {
select {
case <-ctx.Done():
@@ -142,90 +142,88 @@ func (m *SSLManagerProvider) findCertIfExists(ctx context.Context, certPEM strin
return nil, fmt.Errorf("failed to execute sdk request 'ussl.GetCertificateList': %w", err)
}
if getCertificateListResp.CertificateList != nil {
for _, certItem := range getCertificateListResp.CertificateList {
// 优刻得未提供可唯一标识证书的字段,只能通过多个字段尝试对比来判断是否为同一证书
// 先分别对比证书的多域名、品牌、有效期,再对比签名算法
for _, certItem := range getCertificateListResp.CertificateList {
// 优刻得未提供可唯一标识证书的字段,只能通过多个字段尝试对比来判断是否为同一证书
// 先分别对比证书的多域名、品牌、有效期,再对比签名算法
if len(certX509.DNSNames) == 0 || certItem.Domains != strings.Join(certX509.DNSNames, ",") {
continue
}
if len(certX509.Issuer.Organization) == 0 || certItem.Brand != certX509.Issuer.Organization[0] {
continue
}
if int64(certItem.NotBefore) != certX509.NotBefore.UnixMilli() || int64(certItem.NotAfter) != certX509.NotAfter.UnixMilli() {
continue
}
getCertificateDetailInfoReq := m.sdkClient.NewGetCertificateDetailInfoRequest()
getCertificateDetailInfoReq.CertificateID = ucloud.Int(certItem.CertificateID)
if m.config.ProjectId != "" {
getCertificateDetailInfoReq.ProjectId = ucloud.String(m.config.ProjectId)
}
getCertificateDetailInfoResp, err := m.sdkClient.GetCertificateDetailInfo(getCertificateDetailInfoReq)
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'ussl.GetCertificateDetailInfo': %w", err)
}
switch certX509.SignatureAlgorithm {
case x509.SHA256WithRSA:
if !strings.EqualFold(getCertificateDetailInfoResp.CertificateInfo.Algorithm, "SHA256-RSA") {
continue
}
case x509.SHA384WithRSA:
if !strings.EqualFold(getCertificateDetailInfoResp.CertificateInfo.Algorithm, "SHA384-RSA") {
continue
}
case x509.SHA512WithRSA:
if !strings.EqualFold(getCertificateDetailInfoResp.CertificateInfo.Algorithm, "SHA512-RSA") {
continue
}
case x509.SHA256WithRSAPSS:
if !strings.EqualFold(getCertificateDetailInfoResp.CertificateInfo.Algorithm, "SHA256-RSAPSS") {
continue
}
case x509.SHA384WithRSAPSS:
if !strings.EqualFold(getCertificateDetailInfoResp.CertificateInfo.Algorithm, "SHA384-RSAPSS") {
continue
}
case x509.SHA512WithRSAPSS:
if !strings.EqualFold(getCertificateDetailInfoResp.CertificateInfo.Algorithm, "SHA512-RSAPSS") {
continue
}
case x509.ECDSAWithSHA256:
if !strings.EqualFold(getCertificateDetailInfoResp.CertificateInfo.Algorithm, "ECDSA-SHA256") {
continue
}
case x509.ECDSAWithSHA384:
if !strings.EqualFold(getCertificateDetailInfoResp.CertificateInfo.Algorithm, "ECDSA-SHA384") {
continue
}
case x509.ECDSAWithSHA512:
if !strings.EqualFold(getCertificateDetailInfoResp.CertificateInfo.Algorithm, "ECDSA-SHA512") {
continue
}
default:
// 未知签名算法,跳过
continue
}
return &core.SSLManageUploadResult{
CertId: fmt.Sprintf("%d", certItem.CertificateID),
CertName: certItem.Name,
ExtendedData: map[string]any{
"ResourceId": certItem.CertificateSN,
},
}, nil
if len(certX509.DNSNames) == 0 || certItem.Domains != strings.Join(certX509.DNSNames, ",") {
continue
}
if len(certX509.Issuer.Organization) == 0 || certItem.Brand != certX509.Issuer.Organization[0] {
continue
}
if int64(certItem.NotBefore) != certX509.NotBefore.UnixMilli() || int64(certItem.NotAfter) != certX509.NotAfter.UnixMilli() {
continue
}
getCertificateDetailInfoReq := m.sdkClient.NewGetCertificateDetailInfoRequest()
getCertificateDetailInfoReq.CertificateID = ucloud.Int(certItem.CertificateID)
if m.config.ProjectId != "" {
getCertificateDetailInfoReq.ProjectId = ucloud.String(m.config.ProjectId)
}
getCertificateDetailInfoResp, err := m.sdkClient.GetCertificateDetailInfo(getCertificateDetailInfoReq)
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'ussl.GetCertificateDetailInfo': %w", err)
}
switch certX509.SignatureAlgorithm {
case x509.SHA256WithRSA:
if !strings.EqualFold(getCertificateDetailInfoResp.CertificateInfo.Algorithm, "SHA256-RSA") {
continue
}
case x509.SHA384WithRSA:
if !strings.EqualFold(getCertificateDetailInfoResp.CertificateInfo.Algorithm, "SHA384-RSA") {
continue
}
case x509.SHA512WithRSA:
if !strings.EqualFold(getCertificateDetailInfoResp.CertificateInfo.Algorithm, "SHA512-RSA") {
continue
}
case x509.SHA256WithRSAPSS:
if !strings.EqualFold(getCertificateDetailInfoResp.CertificateInfo.Algorithm, "SHA256-RSAPSS") {
continue
}
case x509.SHA384WithRSAPSS:
if !strings.EqualFold(getCertificateDetailInfoResp.CertificateInfo.Algorithm, "SHA384-RSAPSS") {
continue
}
case x509.SHA512WithRSAPSS:
if !strings.EqualFold(getCertificateDetailInfoResp.CertificateInfo.Algorithm, "SHA512-RSAPSS") {
continue
}
case x509.ECDSAWithSHA256:
if !strings.EqualFold(getCertificateDetailInfoResp.CertificateInfo.Algorithm, "ECDSA-SHA256") {
continue
}
case x509.ECDSAWithSHA384:
if !strings.EqualFold(getCertificateDetailInfoResp.CertificateInfo.Algorithm, "ECDSA-SHA384") {
continue
}
case x509.ECDSAWithSHA512:
if !strings.EqualFold(getCertificateDetailInfoResp.CertificateInfo.Algorithm, "ECDSA-SHA512") {
continue
}
default:
// 未知签名算法,跳过
continue
}
return &core.SSLManageUploadResult{
CertId: fmt.Sprintf("%d", certItem.CertificateID),
CertName: certItem.Name,
ExtendedData: map[string]any{
"ResourceId": certItem.CertificateSN,
},
}, nil
}
if getCertificateListResp.CertificateList == nil || len(getCertificateListResp.CertificateList) < int(getCertificateListLimit) {
if len(getCertificateListResp.CertificateList) < getCertificateListLimit {
break
} else {
getCertificateListPage++
}
getCertificateListPage++
}
return nil, nil
@@ -69,14 +69,8 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
// 查询证书列表,避免重复上传
// REF: https://www.volcengine.com/docs/6454/125709
listCertInfoPageNum := int32(1)
listCertInfoPageSize := int32(100)
listCertInfoTotal := 0
listCertInfoReq := &vecdn.ListCertInfoInput{
Source: ve.String("volc_cert_center"),
PageNum: ve.Int32(listCertInfoPageNum),
PageSize: ve.Int32(listCertInfoPageSize),
}
listCertInfoPageNum := 1
listCertInfoPageSize := 100
for {
select {
case <-ctx.Done():
@@ -84,40 +78,43 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
default:
}
listCertInfoReq := &vecdn.ListCertInfoInput{
Source: ve.String("volc_cert_center"),
PageNum: ve.Int32(int32(listCertInfoPageNum)),
PageSize: ve.Int32(int32(listCertInfoPageSize)),
}
listCertInfoResp, err := m.sdkClient.ListCertInfo(listCertInfoReq)
m.logger.Debug("sdk request 'cdn.ListCertInfo'", slog.Any("request", listCertInfoReq), slog.Any("response", listCertInfoResp))
if err != nil {
return nil, fmt.Errorf("failed to execute sdk request 'cdn.ListCertInfo': %w", err)
}
if listCertInfoResp.CertInfo != nil {
for _, certInfo := range listCertInfoResp.CertInfo {
fingerprintSha1 := sha1.Sum(certX509.Raw)
if !strings.EqualFold(hex.EncodeToString(fingerprintSha1[:]), ve.StringValue(certInfo.CertFingerprint.Sha1)) {
continue
}
fingerprintSha256 := sha256.Sum256(certX509.Raw)
if !strings.EqualFold(hex.EncodeToString(fingerprintSha256[:]), ve.StringValue(certInfo.CertFingerprint.Sha256)) {
continue
}
// 如果已存在相同证书,直接返回
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: ve.StringValue(certInfo.CertId),
CertName: ve.StringValue(certInfo.Desc),
}, nil
for _, certItem := range listCertInfoResp.CertInfo {
// 对比证书 SHA-1 摘要
fingerprintSha1 := sha1.Sum(certX509.Raw)
if !strings.EqualFold(hex.EncodeToString(fingerprintSha1[:]), ve.StringValue(certItem.CertFingerprint.Sha1)) {
continue
}
// 对比证书 SHA-256 摘要
fingerprintSha256 := sha256.Sum256(certX509.Raw)
if !strings.EqualFold(hex.EncodeToString(fingerprintSha256[:]), ve.StringValue(certItem.CertFingerprint.Sha256)) {
continue
}
// 如果以上信息都一致,则视为已存在相同证书,直接返回
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: ve.StringValue(certItem.CertId),
CertName: ve.StringValue(certItem.Desc),
}, nil
}
listCertInfoLen := len(listCertInfoResp.CertInfo)
if listCertInfoLen < int(listCertInfoPageSize) || int(ve.Int64Value(listCertInfoResp.Total)) <= listCertInfoTotal+listCertInfoLen {
if len(listCertInfoResp.CertInfo) < listCertInfoPageSize {
break
} else {
listCertInfoPageNum++
listCertInfoTotal += listCertInfoLen
}
listCertInfoPageNum++
}
// 生成新证书名(需符合火山引擎命名规则)
@@ -64,11 +64,11 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
return nil, fmt.Errorf("failed to execute sdk request 'live.ListCertV2': %w", err)
}
if listCertResp.Result.CertList != nil {
for _, certInfo := range listCertResp.Result.CertList {
for _, certItem := range listCertResp.Result.CertList {
// 查询证书详细信息
// REF: https://www.volcengine.com/docs/6469/1186278#%E6%9F%A5%E7%9C%8B%E8%AF%81%E4%B9%A6%E8%AF%A6%E6%83%85
describeCertDetailSecretReq := &velive.DescribeCertDetailSecretV2Body{
ChainID: ve.String(certInfo.ChainID),
ChainID: ve.String(certItem.ChainID),
}
describeCertDetailSecretResp, err := m.sdkClient.DescribeCertDetailSecretV2(ctx, describeCertDetailSecretReq)
m.logger.Debug("sdk request 'live.DescribeCertDetailSecretV2'", slog.Any("request", describeCertDetailSecretReq), slog.Any("response", describeCertDetailSecretResp))
@@ -81,8 +81,8 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
if xcert.EqualCertificatesFromPEM(certPEM, oldCertPEM) {
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: certInfo.ChainID,
CertName: certInfo.CertName,
CertId: certItem.ChainID,
CertName: certItem.CertName,
}, nil
}
}
@@ -72,16 +72,16 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
}
if listCertificatesResp.Certificates != nil {
for _, certRecord := range listCertificatesResp.Certificates {
for _, certItem := range listCertificatesResp.Certificates {
// 对比证书序列号
if !strings.EqualFold(certX509.SerialNumber.Text(16), certRecord.Serial) {
if !strings.EqualFold(certX509.SerialNumber.Text(16), certItem.Serial) {
continue
}
// 再对比证书有效期
cstzone := time.FixedZone("CST", 8*60*60)
oldCertNotBefore, _ := time.ParseInLocation(time.DateTime, certRecord.ValidityFrom, cstzone)
oldCertNotAfter, _ := time.ParseInLocation(time.DateTime, certRecord.ValidityTo, cstzone)
// 对比证书有效期
timezoneOfCST := time.FixedZone("CST", 8*60*60)
oldCertNotBefore, _ := time.ParseInLocation(time.DateTime, certItem.ValidityFrom, timezoneOfCST)
oldCertNotAfter, _ := time.ParseInLocation(time.DateTime, certItem.ValidityTo, timezoneOfCST)
if !certX509.NotBefore.Equal(oldCertNotBefore) || !certX509.NotAfter.Equal(oldCertNotAfter) {
continue
}
@@ -89,8 +89,8 @@ func (m *SSLManagerProvider) Upload(ctx context.Context, certPEM string, privkey
// 如果以上信息都一致,则视为已存在相同证书,直接返回
m.logger.Info("ssl certificate already exists")
return &core.SSLManageUploadResult{
CertId: certRecord.CertificateId,
CertName: certRecord.Name,
CertId: certItem.CertificateId,
CertName: certItem.Name,
}, nil
}
}
+55
View File
@@ -0,0 +1,55 @@
package baishan
import (
"context"
"encoding/json"
"fmt"
"net/http"
)
type GetDomainListRequest struct {
PageNumber *int32 `json:"page_number,omitempty"`
PageSize *int32 `json:"page_size,omitempty"`
DomainStatus *string `json:"domain_status,omitempty"`
}
type GetDomainListResponse struct {
apiResponseBase
Data []*struct {
List []*DomainRecord `json:"list"`
PageNumber json.Number `json:"page_number"`
PageSize json.Number `json:"page_size"`
TotalNumber json.Number `json:"total_number"`
} `json:"data,omitempty"`
}
func (c *Client) GetDomainList(req *GetDomainListRequest) (*GetDomainListResponse, error) {
return c.GetDomainListWithContext(context.Background(), req)
}
func (c *Client) GetDomainListWithContext(ctx context.Context, req *GetDomainListRequest) (*GetDomainListResponse, error) {
httpreq, err := c.newRequest(http.MethodGet, "/v2/domain/list")
if err != nil {
return nil, err
} else {
if req.PageNumber != nil {
httpreq.SetQueryParam("page_number", fmt.Sprintf("%d", *req.PageNumber))
}
if req.PageSize != nil {
httpreq.SetQueryParam("page_number", fmt.Sprintf("%d", *req.PageSize))
}
if req.DomainStatus != nil {
httpreq.SetQueryParam("domain_status", *req.DomainStatus)
}
httpreq.SetContext(ctx)
}
result := &GetDomainListResponse{}
if _, err := c.doRequestWithResult(httpreq, result); err != nil {
return result, err
}
return result, nil
}
+11
View File
@@ -30,6 +30,17 @@ func (r *apiResponseBase) GetMessage() string {
var _ apiResponse = (*apiResponseBase)(nil)
type DomainRecord struct {
Id string `json:"id"`
Domain string `json:"domain"`
Type string `json:"type"`
Status string `json:"status"`
Cname string `json:"cname"`
Area string `json:"area"`
CreateTime string `json:"create_time"`
UpdateTime string `json:"update_time"`
}
type DomainCertificate struct {
CertId json.Number `json:"cert_id"`
Name string `json:"name"`
@@ -1,5 +1,5 @@
import { getI18n, useTranslation } from "react-i18next";
import { Form, Input } from "antd";
import { Form, Input, Radio } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod";
@@ -7,6 +7,8 @@ import { validDomainName } from "@/utils/validators";
import { useFormNestedFieldsContext } from "./_context";
const DOMAIN_MATCH_PATTERN_EXACT = "exact" as const;
const BizDeployNodeConfigFieldsProviderBaishanCDN = () => {
const { i18n, t } = useTranslation();
@@ -15,10 +17,35 @@ const BizDeployNodeConfigFieldsProviderBaishanCDN = () => {
[parentNamePath]: getSchema({ i18n }),
});
const formRule = createSchemaFieldRule(formSchema);
const formInst = Form.useFormInstance();
const initialValues = getInitialValues();
const fieldDomainMatchPattern = Form.useWatch([parentNamePath, "domainMatchPattern"], { form: formInst, preserve: true });
return (
<>
<Form.Item
name={[parentNamePath, "domainMatchPattern"]}
initialValue={initialValues.domainMatchPattern}
label={t("workflow_node.deploy.form.shared_domain_match_pattern.label")}
extra={
fieldDomainMatchPattern === DOMAIN_MATCH_PATTERN_EXACT ? (
<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.shared_domain_match_pattern.help_wildcard") }}></span>
) : (
void 0
)
}
rules={[formRule]}
>
<Radio.Group
options={[DOMAIN_MATCH_PATTERN_EXACT].map((s) => ({
key: s,
label: t(`workflow_node.deploy.form.shared_domain_match_pattern.option.${s}.label`),
value: s,
}))}
/>
</Form.Item>
<Form.Item
name={[parentNamePath, "domain"]}
initialValue={initialValues.domain}
@@ -44,6 +71,7 @@ const BizDeployNodeConfigFieldsProviderBaishanCDN = () => {
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
return {
domainMatchPattern: DOMAIN_MATCH_PATTERN_EXACT,
domain: "",
};
};
@@ -51,16 +79,35 @@ const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
const getSchema = ({ i18n = getI18n() }: { i18n?: ReturnType<typeof getI18n> }) => {
const { t } = i18n;
return z.object({
domain: z.string().refine((v) => validDomainName(v, { allowWildcard: true }), t("common.errmsg.domain_invalid")),
certificateId: z
.union([z.string(), z.number().int()])
.nullish()
.refine((v) => {
if (!v) return true;
return /^\d+$/.test(v + "") && +v > 0;
}, t("workflow_node.deploy.form.baishan_cdn_certificate_id.placeholder")),
});
return z
.object({
domainMatchPattern: z.string().nonempty(t("workflow_node.deploy.form.shared_domain_match_pattern.placeholder")).default(DOMAIN_MATCH_PATTERN_EXACT),
domain: z.string().nullish(),
certificateId: z
.union([z.string(), z.number().int()])
.nullish()
.refine((v) => {
if (!v) return true;
return /^\d+$/.test(v + "") && +v > 0;
}, t("workflow_node.deploy.form.baishan_cdn_certificate_id.placeholder")),
})
.superRefine((values, ctx) => {
if (values.domainMatchPattern) {
switch (values.domainMatchPattern) {
case DOMAIN_MATCH_PATTERN_EXACT:
{
if (!validDomainName(values.domain!, { allowWildcard: true })) {
ctx.addIssue({
code: "custom",
message: t("common.errmsg.domain_invalid"),
path: ["domain"],
});
}
}
break;
}
}
});
};
const _default = Object.assign(BizDeployNodeConfigFieldsProviderBaishanCDN, {
@@ -1,5 +1,5 @@
import { getI18n, useTranslation } from "react-i18next";
import { Form } from "antd";
import { Form, Radio } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod";
@@ -10,6 +10,8 @@ import { useFormNestedFieldsContext } from "./_context";
const MULTIPLE_INPUT_SEPARATOR = ";";
const DOMAIN_MATCH_PATTERN_EXACT = "exact" as const;
const BizDeployNodeConfigFieldsProviderWangsuCDN = () => {
const { i18n, t } = useTranslation();
@@ -18,10 +20,35 @@ const BizDeployNodeConfigFieldsProviderWangsuCDN = () => {
[parentNamePath]: getSchema({ i18n }),
});
const formRule = createSchemaFieldRule(formSchema);
const formInst = Form.useFormInstance();
const initialValues = getInitialValues();
const fieldDomainMatchPattern = Form.useWatch([parentNamePath, "domainMatchPattern"], { form: formInst, preserve: true });
return (
<>
<Form.Item
name={[parentNamePath, "domainMatchPattern"]}
initialValue={initialValues.domainMatchPattern}
label={t("workflow_node.deploy.form.shared_domain_match_pattern.label")}
extra={
fieldDomainMatchPattern === DOMAIN_MATCH_PATTERN_EXACT ? (
<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.shared_domain_match_pattern.help_wildcard") }}></span>
) : (
void 0
)
}
rules={[formRule]}
>
<Radio.Group
options={[DOMAIN_MATCH_PATTERN_EXACT].map((s) => ({
key: s,
label: t(`workflow_node.deploy.form.shared_domain_match_pattern.option.${s}.label`),
value: s,
}))}
/>
</Form.Item>
<Form.Item
name={[parentNamePath, "domains"]}
initialValue={initialValues.domains}
@@ -43,6 +70,7 @@ const BizDeployNodeConfigFieldsProviderWangsuCDN = () => {
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
return {
domainMatchPattern: DOMAIN_MATCH_PATTERN_EXACT,
domains: "",
};
};
@@ -50,14 +78,33 @@ const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
const getSchema = ({ i18n = getI18n() }: { i18n?: ReturnType<typeof getI18n> }) => {
const { t } = i18n;
return z.object({
domains: z.string().refine((v) => {
if (!v) return false;
return String(v)
.split(MULTIPLE_INPUT_SEPARATOR)
.every((e) => validDomainName(e, { allowWildcard: true }));
}, t("workflow_node.deploy.form.wangsu_cdn_domains.placeholder")),
});
return z
.object({
domainMatchPattern: z.string().nonempty(t("workflow_node.deploy.form.shared_domain_match_pattern.placeholder")).default(DOMAIN_MATCH_PATTERN_EXACT),
domains: z.string().nullish(),
})
.superRefine((values, ctx) => {
if (values.domainMatchPattern) {
switch (values.domainMatchPattern) {
case DOMAIN_MATCH_PATTERN_EXACT:
{
const v =
values.domains &&
String(values.domains)
.split(MULTIPLE_INPUT_SEPARATOR)
.every((e) => validDomainName(e, { allowWildcard: true }));
if (!v) {
ctx.addIssue({
code: "custom",
message: t("common.errmsg.domain_invalid"),
path: ["domains"],
});
}
}
break;
}
}
});
};
const _default = Object.assign(BizDeployNodeConfigFieldsProviderWangsuCDN, {
@@ -1,5 +1,5 @@
import { getI18n, useTranslation } from "react-i18next";
import { Form, Input, Select } from "antd";
import { Form, Input, Radio, Select } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod";
@@ -10,6 +10,8 @@ import { useFormNestedFieldsContext } from "./_context";
const ENVIRONMENT_PRODUCTION = "production" as const;
const ENVIRONMENT_STAGING = "stating" as const;
const DOMAIN_MATCH_PATTERN_EXACT = "exact" as const;
const BizDeployNodeConfigFieldsProviderWangsuCDNPro = () => {
const { i18n, t } = useTranslation();
@@ -18,8 +20,11 @@ const BizDeployNodeConfigFieldsProviderWangsuCDNPro = () => {
[parentNamePath]: getSchema({ i18n }),
});
const formRule = createSchemaFieldRule(formSchema);
const formInst = Form.useFormInstance();
const initialValues = getInitialValues();
const fieldDomainMatchPattern = Form.useWatch([parentNamePath, "domainMatchPattern"], { form: formInst, preserve: true });
return (
<>
<Form.Item
@@ -38,6 +43,28 @@ const BizDeployNodeConfigFieldsProviderWangsuCDNPro = () => {
</Select>
</Form.Item>
<Form.Item
name={[parentNamePath, "domainMatchPattern"]}
initialValue={initialValues.domainMatchPattern}
label={t("workflow_node.deploy.form.shared_domain_match_pattern.label")}
extra={
fieldDomainMatchPattern === DOMAIN_MATCH_PATTERN_EXACT ? (
<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.shared_domain_match_pattern.help_wildcard") }}></span>
) : (
void 0
)
}
rules={[formRule]}
>
<Radio.Group
options={[DOMAIN_MATCH_PATTERN_EXACT].map((s) => ({
key: s,
label: t(`workflow_node.deploy.form.shared_domain_match_pattern.option.${s}.label`),
value: s,
}))}
/>
</Form.Item>
<Form.Item
name={[parentNamePath, "domain"]}
initialValue={initialValues.domain}
@@ -74,6 +101,7 @@ const BizDeployNodeConfigFieldsProviderWangsuCDNPro = () => {
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
return {
environment: ENVIRONMENT_PRODUCTION,
domainMatchPattern: DOMAIN_MATCH_PATTERN_EXACT,
domain: "",
};
};
@@ -81,12 +109,31 @@ const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
const getSchema = ({ i18n = getI18n() }: { i18n?: ReturnType<typeof getI18n> }) => {
const { t } = i18n;
return z.object({
environment: z.literal([ENVIRONMENT_PRODUCTION, ENVIRONMENT_STAGING], t("workflow_node.deploy.form.wangsu_cdnpro_environment.placeholder")),
domain: z.string().refine((v) => validDomainName(v, { allowWildcard: true }), t("common.errmsg.domain_invalid")),
certificateId: z.string().nullish(),
webhookId: z.string().nullish(),
});
return z
.object({
environment: z.literal([ENVIRONMENT_PRODUCTION, ENVIRONMENT_STAGING], t("workflow_node.deploy.form.wangsu_cdnpro_environment.placeholder")),
domainMatchPattern: z.string().nonempty(t("workflow_node.deploy.form.shared_domain_match_pattern.placeholder")).default(DOMAIN_MATCH_PATTERN_EXACT),
domain: z.string().nullish(),
certificateId: z.string().nullish(),
webhookId: z.string().nullish(),
})
.superRefine((values, ctx) => {
if (values.domainMatchPattern) {
switch (values.domainMatchPattern) {
case DOMAIN_MATCH_PATTERN_EXACT:
{
if (!validDomainName(values.domain!, { allowWildcard: true })) {
ctx.addIssue({
code: "custom",
message: t("common.errmsg.domain_invalid"),
path: ["domain"],
});
}
}
break;
}
}
});
};
const _default = Object.assign(BizDeployNodeConfigFieldsProviderWangsuCDNPro, {