Browse Source

更新证书处理逻辑并增强日志记录

在 `UpdateCDNHttps` 函数中增加了对已存在证书的处理,尝试检测并更新 CDN 证书记录;同时改进了数据库查询和日志记录,确保按创建时间降序获取最新的证书记录。
SongZihuan 3 months ago
parent
commit
8b55c38670
5 changed files with 110 additions and 40 deletions
  1. 29 13
      src/aliyun/main.go
  2. 7 7
      src/aliyun/operation.go
  3. 47 5
      src/database/db.go
  4. 20 8
      src/database/module.go
  5. 7 7
      src/server/server.go

+ 29 - 13
src/aliyun/main.go

@@ -50,23 +50,39 @@ func UpdateCDNHttpsByFilePath(domainList []string, cert string, prikey string) e
 
 func UpdateCDNHttps(domainList []string, certData []byte, privateKeyData []byte) error {
 	certID, certName, subject, err := uploadCert(certData, privateKeyData)
-	if err != nil && errors.Is(err, ErrCertExists) {
-		logger.Warnf("证书已存在, 不在重新更新CDN(%s)", strings.Join(domainList, ", "))
+	if err != nil && errors.Is(err, ErrCertExists) && certName != "" {
+		logger.Warnf("证书已存在, 尝试检测CDN证书记录并更新(%s)", strings.Join(domainList, ", "))
+
+		for _, domain := range domainList {
+			cert, need, err := database.CheckNeedUpdateDomain(certName, domain)
+			if err != nil {
+				logger.Errorf("check aliyun cloud cdn domain ssl status from sqlite error: %s", err.Error())
+			} else if need && cert != nil {
+				setDomainServerCertificateNotError(domain, cert.CertID, cert.Name)
+				err = database.UpdateDomain(cert.CertID, cert.Name, cert.Subject, domain)
+				if err != nil {
+					logger.Error("aliyun cloud ssl domain save to sqlite error: %s", err.Error())
+				}
+			} else {
+				// 无需更新
+			}
+		}
+
 		return nil
 	} else if err != nil {
 		return fmt.Errorf("aliyun cloud ssl cert/key upload error: %s", err.Error())
-	}
-
-	err = database.UpdateCert(certID, certName, subject)
-	if err != nil {
-		logger.Errorf("aliyun cloud ssl cert/key save to sqlite error: %s", err.Error())
-	}
-
-	for _, domain := range domainList {
-		setDomainServerCertificateNotError(domain, certID, certName)
-		err = database.UpdateDomain(certID, certName, subject, domain)
+	} else {
+		err = database.UpdateCert(certID, certName, subject)
 		if err != nil {
-			logger.Error("aliyun cloud ssl domain save to sqlite error: %s", err.Error())
+			logger.Errorf("aliyun cloud ssl cert/key save to sqlite error: %s", err.Error())
+		}
+
+		for _, domain := range domainList {
+			setDomainServerCertificateNotError(domain, certID, certName)
+			err = database.UpdateDomain(certID, certName, subject, domain)
+			if err != nil {
+				logger.Error("aliyun cloud ssl domain save to sqlite error: %s", err.Error())
+			}
 		}
 	}
 

+ 7 - 7
src/aliyun/operation.go

@@ -83,13 +83,13 @@ func setDomainServerCertificate(domainName string, certID int64, certName string
 
 func setDomainServerCertificateNotError(domainName string, certID int64, certName string) {
 	defer func() {
-		//if r := recover(); r != nil {
-		//	if err, ok := r.(error); ok {
-		//		logger.Panicf("aliyun update CDN HTTPS by domains/collection (%s) panic: %s", domainName, err.Error())
-		//	} else {
-		//		logger.Panicf("aliyun update CDN HTTPS by domains/collection (%s) panic: %v", domainName, r)
-		//	}
-		//}
+		if r := recover(); r != nil {
+			if err, ok := r.(error); ok {
+				logger.Panicf("aliyun update CDN HTTPS by domains/collection (%s) panic: %s", domainName, err.Error())
+			} else {
+				logger.Panicf("aliyun update CDN HTTPS by domains/collection (%s) panic: %v", domainName, r)
+			}
+		}
 	}()
 
 	err := setDomainServerCertificate(domainName, certID, certName)

+ 47 - 5
src/database/db.go

@@ -10,7 +10,7 @@ import (
 func UpdateCert(certID int64, name string, subject string) error {
 	err := db.Transaction(func(tx *gorm.DB) error {
 		var cert CertRecord
-		err := tx.Model(&CertRecord{}).Where("name = ?", name).First(&cert).Error
+		err := tx.Model(&CertRecord{}).Where("name = ?", name).Order("created_at desc").First(&cert).Error
 		if errors.Is(err, gorm.ErrRecordNotFound) {
 			cert = CertRecord{
 				CertID:  certID,
@@ -56,13 +56,13 @@ func UpdateCert(certID int64, name string, subject string) error {
 func UpdateDomain(certID int64, name string, subject string, domain string) error {
 	err := db.Transaction(func(tx *gorm.DB) error {
 		var cert CertRecord
-		err := tx.Model(&CertRecord{}).Where("name = ?", name).First(&cert).Error
+		err := tx.Model(&CertRecord{}).Where("name = ?", name).Order("created_at desc").First(&cert).Error
 		if errors.Is(err, gorm.ErrRecordNotFound) {
-			return fmt.Errorf("update CDN domain SSL record failed: cert record not found")
+			return fmt.Errorf("update CDN domain SSL record to SQLite failed: cert record not found")
 		} else if err != nil {
 			return err
 		} else if cert.CertID != certID || cert.Name != name || cert.Subject != subject {
-			logger.Errorf("Update CDN domain SSL record failed: information does not match (sqlite: cert-id=%d; name=%s; subject=%s) (be given: cert-id=%d; name=%s; subject=%s)", cert.CertID, cert.Name, cert.Subject, certID, name, subject)
+			logger.Errorf("Update CDN domain SSL record to SQLite failed: information does not match (sqlite: cert-id=%d; name=%s; subject=%s) (be given: cert-id=%d; name=%s; subject=%s)", cert.CertID, cert.Name, cert.Subject, certID, name, subject)
 		}
 
 		record := DomainRecord{
@@ -71,9 +71,10 @@ func UpdateDomain(certID int64, name string, subject string, domain string) erro
 			Name:         cert.Name,
 			Subject:      cert.Subject,
 			Domain:       domain,
+			CertUpdateAt: cert.UpdatedAt,
 		}
 
-		err = tx.Save(&record).Error
+		err = tx.Create(&record).Error
 		if err != nil {
 			return err
 		}
@@ -86,3 +87,44 @@ func UpdateDomain(certID int64, name string, subject string, domain string) erro
 
 	return nil
 }
+
+func CheckNeedUpdateDomain(certName string, domainName string) (cr *CertRecord, res bool, err error) {
+	defer func() {
+		if err != nil {
+			res = false
+			cr = nil
+		}
+	}()
+
+	var cert CertRecord
+
+	err = db.Transaction(func(tx *gorm.DB) error {
+		err := tx.Model(&CertRecord{}).Where("name = ?", certName).Order("created_at desc").First(&cert).Error
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return fmt.Errorf("check CDN domain SSL record from SQLite failed: cert record not found")
+		} else if err != nil {
+			return err
+		}
+
+		var domain DomainRecord
+		err = tx.Model(&DomainRecord{}).Where("domain = ?", domainName).Order("created_at desc").First(&domain).Error
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			res = true
+			return nil
+		} else if err != nil {
+			res = false
+			return err
+		} else if cert.UpdatedAt.After(domain.CertUpdateAt) {
+			res = true
+			return nil
+		} else {
+			res = false
+			return nil
+		}
+	})
+	if err != nil {
+		return nil, false, fmt.Errorf("check CDN domain SSL record from SQLite failed: %s", err.Error())
+	}
+
+	return &cert, res, nil
+}

+ 20 - 8
src/database/module.go

@@ -1,9 +1,20 @@
 package database
 
-import "gorm.io/gorm"
+import (
+	"gorm.io/gorm"
+	"time"
+)
+
+// Model gorm.Model的仿写,明确了键名
+type Model struct {
+	ID        uint           `gorm:"column:id;primarykey"`
+	CreatedAt time.Time      `gorm:"column:created_at;autoCreateTime;primarykey"`
+	UpdatedAt time.Time      `gorm:"column:updated_at;autoUpdateTime;primarykey"`
+	DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;index"`
+}
 
 type CertRecord struct {
-	gorm.Model
+	Model
 	CertID  int64  `gorm:"column:cert_id;not null;uniqueIndex:unq_idx_cert"`
 	Name    string `gorm:"column:name;type:VARCHAR(100);not null;uniqueIndex:unq_idx_cert"`
 	Subject string `gorm:"column:subject;type:VARCHAR(100);not null;"`
@@ -14,12 +25,13 @@ func (*CertRecord) TableName() string {
 }
 
 type DomainRecord struct {
-	gorm.Model
-	CertRecordID uint   `gorm:"column:cert_record_id;not null;"`
-	CertID       int64  `gorm:"column:cert_id;not null"`
-	Name         string `gorm:"column:name;type:VARCHAR(100);not null"`
-	Subject      string `gorm:"column:subject;type:VARCHAR(100);not null;"`
-	Domain       string `gorm:"type:VARCHAR(100);not null;"` // 允许多次重复记录
+	Model
+	CertRecordID uint      `gorm:"column:cert_record_id;not null;"`
+	CertID       int64     `gorm:"column:cert_id;not null"`
+	Name         string    `gorm:"column:name;type:VARCHAR(100);not null"`
+	Subject      string    `gorm:"column:subject;type:VARCHAR(100);not null;"`
+	Domain       string    `gorm:"type:VARCHAR(100);not null;"` // 允许多次重复记录
+	CertUpdateAt time.Time `gorm:"column:cert_update_time;not null"`
 }
 
 func (*DomainRecord) TableName() string {

+ 7 - 7
src/server/server.go

@@ -14,13 +14,13 @@ func Server() error {
 	for index, collection := range cfg.Collection {
 		func() {
 			defer func() {
-				//if r := recover(); r != nil {
-				//	if err, ok := r.(error); ok {
-				//		logger.Panicf("aliyun update CDN HTTPS by domains/collection (%s / %d) panic: %s", strings.Join(collection.Domain, ", "), index, err.Error())
-				//	} else {
-				//		logger.Panicf("aliyun update CDN HTTPS by domains/collection (%s / %d) panic: %v", strings.Join(collection.Domain, ", "), index, r)
-				//	}
-				//}
+				if r := recover(); r != nil {
+					if err, ok := r.(error); ok {
+						logger.Panicf("aliyun update CDN HTTPS by domains/collection (%s / %d) panic: %s", strings.Join(collection.Domain, ", "), index, err.Error())
+					} else {
+						logger.Panicf("aliyun update CDN HTTPS by domains/collection (%s / %d) panic: %v", strings.Join(collection.Domain, ", "), index, r)
+					}
+				}
 			}()
 
 			certPath, prikeyPath := collection.GetFilePath()