mirror of
				https://github.com/TeaOSLab/EdgeAPI.git
				synced 2025-11-04 16:00:24 +08:00 
			
		
		
		
	[SSL证书]增加提前自动更新证书功能
This commit is contained in:
		@@ -76,9 +76,11 @@ func (this *DNSDomainDAO) FindDNSDomainName(id int64) (string, error) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 创建域名
 | 
					// 创建域名
 | 
				
			||||||
func (this *DNSDomainDAO) CreateDomain(providerId int64, name string) (int64, error) {
 | 
					func (this *DNSDomainDAO) CreateDomain(adminId int64, userId int64, providerId int64, name string) (int64, error) {
 | 
				
			||||||
	op := NewDNSDomainOperator()
 | 
						op := NewDNSDomainOperator()
 | 
				
			||||||
	op.ProviderId = providerId
 | 
						op.ProviderId = providerId
 | 
				
			||||||
 | 
						op.AdminId = adminId
 | 
				
			||||||
 | 
						op.UserId = userId
 | 
				
			||||||
	op.Name = name
 | 
						op.Name = name
 | 
				
			||||||
	op.State = DNSDomainStateEnabled
 | 
						op.State = DNSDomainStateEnabled
 | 
				
			||||||
	op.IsOn = true
 | 
						op.IsOn = true
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,12 +25,15 @@ const (
 | 
				
			|||||||
type MessageType = string
 | 
					type MessageType = string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	MessageTypeHealthCheckFailed    MessageType = "HealthCheckFailed"
 | 
						MessageTypeHealthCheckFailed      MessageType = "HealthCheckFailed"
 | 
				
			||||||
	MessageTypeHealthCheckNodeUp    MessageType = "HealthCheckNodeUp"
 | 
						MessageTypeHealthCheckNodeUp      MessageType = "HealthCheckNodeUp"
 | 
				
			||||||
	MessageTypeHealthCheckNodeDown  MessageType = "HealthCheckNodeDown"
 | 
						MessageTypeHealthCheckNodeDown    MessageType = "HealthCheckNodeDown"
 | 
				
			||||||
	MessageTypeNodeInactive         MessageType = "NodeInactive"
 | 
						MessageTypeNodeInactive           MessageType = "NodeInactive"
 | 
				
			||||||
	MessageTypeNodeActive           MessageType = "NodeActive"
 | 
						MessageTypeNodeActive             MessageType = "NodeActive"
 | 
				
			||||||
	MessageTypeClusterDNSSyncFailed MessageType = "ClusterDNSSyncFailed"
 | 
						MessageTypeClusterDNSSyncFailed   MessageType = "ClusterDNSSyncFailed"
 | 
				
			||||||
 | 
						MessageTypeSSLCertExpiring        MessageType = "SSLCertExpiring"        // SSL证书即将过期
 | 
				
			||||||
 | 
						MessageTypeSSLCertACMETaskFailed  MessageType = "SSLCertACMETaskFailed"  // SSL证书任务执行失败
 | 
				
			||||||
 | 
						MessageTypeSSLCertACMETaskSuccess MessageType = "SSLCertACMETaskSuccess" // SSL证书任务执行成功
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type MessageDAO dbs.DAO
 | 
					type MessageDAO dbs.DAO
 | 
				
			||||||
@@ -96,6 +99,30 @@ func (this *MessageDAO) CreateNodeMessage(clusterId int64, nodeId int64, message
 | 
				
			|||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 创建普通消息
 | 
				
			||||||
 | 
					func (this *MessageDAO) CreateMessage(adminId int64, userId int64, messageType MessageType, level string, body string, paramsJSON []byte) error {
 | 
				
			||||||
 | 
						h := md5.New()
 | 
				
			||||||
 | 
						h.Write([]byte(body))
 | 
				
			||||||
 | 
						h.Write(paramsJSON)
 | 
				
			||||||
 | 
						hash := fmt.Sprintf("%x", h.Sum(nil))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						op := NewMessageOperator()
 | 
				
			||||||
 | 
						op.AdminId = adminId
 | 
				
			||||||
 | 
						op.UserId = userId
 | 
				
			||||||
 | 
						op.Type = messageType
 | 
				
			||||||
 | 
						op.Level = level
 | 
				
			||||||
 | 
						op.Body = body
 | 
				
			||||||
 | 
						if len(paramsJSON) > 0 {
 | 
				
			||||||
 | 
							op.Params = paramsJSON
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						op.State = MessageStateEnabled
 | 
				
			||||||
 | 
						op.IsRead = false
 | 
				
			||||||
 | 
						op.Day = timeutil.Format("Ymd")
 | 
				
			||||||
 | 
						op.Hash = hash
 | 
				
			||||||
 | 
						_, err := this.Save(op)
 | 
				
			||||||
 | 
						return err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 删除某天之前的消息
 | 
					// 删除某天之前的消息
 | 
				
			||||||
func (this *MessageDAO) DeleteMessagesBeforeDay(dayTime time.Time) error {
 | 
					func (this *MessageDAO) DeleteMessagesBeforeDay(dayTime time.Time) error {
 | 
				
			||||||
	day := timeutil.Format("Ymd", dayTime)
 | 
						day := timeutil.Format("Ymd", dayTime)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -101,7 +101,7 @@ func (this *NodeClusterDAO) FindAllEnableClusters() (result []*NodeCluster, err
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 创建集群
 | 
					// 创建集群
 | 
				
			||||||
func (this *NodeClusterDAO) CreateCluster(name string, grantId int64, installDir string, dnsDomainId int64, dnsName string) (clusterId int64, err error) {
 | 
					func (this *NodeClusterDAO) CreateCluster(adminId int64, name string, grantId int64, installDir string, dnsDomainId int64, dnsName string) (clusterId int64, err error) {
 | 
				
			||||||
	uniqueId, err := this.genUniqueId()
 | 
						uniqueId, err := this.genUniqueId()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return 0, err
 | 
							return 0, err
 | 
				
			||||||
@@ -114,6 +114,7 @@ func (this *NodeClusterDAO) CreateCluster(name string, grantId int64, installDir
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	op := NewNodeClusterOperator()
 | 
						op := NewNodeClusterOperator()
 | 
				
			||||||
 | 
						op.AdminId = adminId
 | 
				
			||||||
	op.Name = name
 | 
						op.Name = name
 | 
				
			||||||
	op.GrantId = grantId
 | 
						op.GrantId = grantId
 | 
				
			||||||
	op.InstallDir = installDir
 | 
						op.InstallDir = installDir
 | 
				
			||||||
@@ -522,6 +523,14 @@ func (this *NodeClusterDAO) CheckClusterDNS(cluster *NodeCluster) (issues []*pb.
 | 
				
			|||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 查找集群所属管理员
 | 
				
			||||||
 | 
					func (this *NodeClusterDAO) FindClusterAdminId(clusterId int64) (int64, error) {
 | 
				
			||||||
 | 
						return this.Query().
 | 
				
			||||||
 | 
							Pk(clusterId).
 | 
				
			||||||
 | 
							Result("adminId").
 | 
				
			||||||
 | 
							FindInt64Col(0)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 生成唯一ID
 | 
					// 生成唯一ID
 | 
				
			||||||
func (this *NodeClusterDAO) genUniqueId() (string, error) {
 | 
					func (this *NodeClusterDAO) genUniqueId() (string, error) {
 | 
				
			||||||
	for {
 | 
						for {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -80,7 +80,7 @@ func (this *NodeDAO) FindNodeName(id uint32) (string, error) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 创建节点
 | 
					// 创建节点
 | 
				
			||||||
func (this *NodeDAO) CreateNode(name string, clusterId int64, groupId int64) (nodeId int64, err error) {
 | 
					func (this *NodeDAO) CreateNode(adminId int64, name string, clusterId int64, groupId int64) (nodeId int64, err error) {
 | 
				
			||||||
	uniqueId, err := this.genUniqueId()
 | 
						uniqueId, err := this.genUniqueId()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return 0, err
 | 
							return 0, err
 | 
				
			||||||
@@ -95,6 +95,7 @@ func (this *NodeDAO) CreateNode(name string, clusterId int64, groupId int64) (no
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	op := NewNodeOperator()
 | 
						op := NewNodeOperator()
 | 
				
			||||||
 | 
						op.AdminId = adminId
 | 
				
			||||||
	op.Name = name
 | 
						op.Name = name
 | 
				
			||||||
	op.UniqueId = uniqueId
 | 
						op.UniqueId = uniqueId
 | 
				
			||||||
	op.Secret = secret
 | 
						op.Secret = secret
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ import (
 | 
				
			|||||||
	"github.com/iwind/TeaGo/Tea"
 | 
						"github.com/iwind/TeaGo/Tea"
 | 
				
			||||||
	"github.com/iwind/TeaGo/dbs"
 | 
						"github.com/iwind/TeaGo/dbs"
 | 
				
			||||||
	"github.com/iwind/TeaGo/types"
 | 
						"github.com/iwind/TeaGo/types"
 | 
				
			||||||
 | 
						timeutil "github.com/iwind/TeaGo/utils/time"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -283,3 +284,32 @@ func (this *SSLCertDAO) UpdateCertACME(certId int64, acmeTaskId int64) error {
 | 
				
			|||||||
	_, err := this.Save(op)
 | 
						_, err := this.Save(op)
 | 
				
			||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 查找需要自动更新的任务
 | 
				
			||||||
 | 
					// 这里我们只返回有限的字段以节省内存
 | 
				
			||||||
 | 
					func (this *SSLCertDAO) FindAllExpiringCerts(days int) (result []*SSLCert, err error) {
 | 
				
			||||||
 | 
						if days < 0 {
 | 
				
			||||||
 | 
							days = 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						deltaSeconds := int64(days * 86400)
 | 
				
			||||||
 | 
						_, err = this.Query().
 | 
				
			||||||
 | 
							State(SSLCertStateEnabled).
 | 
				
			||||||
 | 
							Where("FROM_UNIXTIME(timeEndAt, '%Y-%m-%d')=:day AND FROM_UNIXTIME(notifiedAt, '%Y-%m-%d')!=:today").
 | 
				
			||||||
 | 
							Param("day", timeutil.FormatTime("Y-m-d", time.Now().Unix()+deltaSeconds)).
 | 
				
			||||||
 | 
							Param("today", timeutil.Format("Y-m-d")).
 | 
				
			||||||
 | 
							Result("id", "adminId", "userId", "timeEndAt", "name", "dnsNames", "notifiedAt", "acmeTaskId").
 | 
				
			||||||
 | 
							Slice(&result).
 | 
				
			||||||
 | 
							AscPk().
 | 
				
			||||||
 | 
							FindAll()
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 设置当前证书事件通知时间
 | 
				
			||||||
 | 
					func (this *SSLCertDAO) UpdateCertNotifiedAt(certId int64) error {
 | 
				
			||||||
 | 
						_, err := this.Query().
 | 
				
			||||||
 | 
							Pk(certId).
 | 
				
			||||||
 | 
							Set("notifiedAt", time.Now().Unix()).
 | 
				
			||||||
 | 
							Update()
 | 
				
			||||||
 | 
						return err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,6 +22,7 @@ type SSLCert struct {
 | 
				
			|||||||
	CommonNames string `field:"commonNames"` // 发行单位列表
 | 
						CommonNames string `field:"commonNames"` // 发行单位列表
 | 
				
			||||||
	IsACME      uint8  `field:"isACME"`      // 是否为ACME自动生成的
 | 
						IsACME      uint8  `field:"isACME"`      // 是否为ACME自动生成的
 | 
				
			||||||
	AcmeTaskId  uint64 `field:"acmeTaskId"`  // ACME任务ID
 | 
						AcmeTaskId  uint64 `field:"acmeTaskId"`  // ACME任务ID
 | 
				
			||||||
 | 
						NotifiedAt  uint64 `field:"notifiedAt"`  // 最后通知时间
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type SSLCertOperator struct {
 | 
					type SSLCertOperator struct {
 | 
				
			||||||
@@ -45,6 +46,7 @@ type SSLCertOperator struct {
 | 
				
			|||||||
	CommonNames interface{} // 发行单位列表
 | 
						CommonNames interface{} // 发行单位列表
 | 
				
			||||||
	IsACME      interface{} // 是否为ACME自动生成的
 | 
						IsACME      interface{} // 是否为ACME自动生成的
 | 
				
			||||||
	AcmeTaskId  interface{} // ACME任务ID
 | 
						AcmeTaskId  interface{} // ACME任务ID
 | 
				
			||||||
 | 
						NotifiedAt  interface{} // 最后通知时间
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewSSLCertOperator() *SSLCertOperator {
 | 
					func NewSSLCertOperator() *SSLCertOperator {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,18 @@ import (
 | 
				
			|||||||
type BaseService struct {
 | 
					type BaseService struct {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 校验管理员
 | 
				
			||||||
 | 
					func (this *BaseService) ValidateAdmin(ctx context.Context, reqAdminId int64) (adminId int64, err error) {
 | 
				
			||||||
 | 
						_, reqUserId, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeAdmin)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if reqAdminId > 0 && reqUserId != reqAdminId {
 | 
				
			||||||
 | 
							return 0, this.PermissionError()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return reqUserId, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 校验管理员和用户
 | 
					// 校验管理员和用户
 | 
				
			||||||
func (this *BaseService) ValidateAdminAndUser(ctx context.Context, reqUserId int64) (adminId int64, userId int64, err error) {
 | 
					func (this *BaseService) ValidateAdminAndUser(ctx context.Context, reqUserId int64) (adminId int64, userId int64, err error) {
 | 
				
			||||||
	reqUserType, reqUserId, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeAdmin, rpcutils.UserTypeUser)
 | 
						reqUserType, reqUserId, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeAdmin, rpcutils.UserTypeUser)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,7 +21,7 @@ type DNSDomainService struct {
 | 
				
			|||||||
// 创建域名
 | 
					// 创建域名
 | 
				
			||||||
func (this *DNSDomainService) CreateDNSDomain(ctx context.Context, req *pb.CreateDNSDomainRequest) (*pb.CreateDNSDomainResponse, error) {
 | 
					func (this *DNSDomainService) CreateDNSDomain(ctx context.Context, req *pb.CreateDNSDomainRequest) (*pb.CreateDNSDomainResponse, error) {
 | 
				
			||||||
	// 校验请求
 | 
						// 校验请求
 | 
				
			||||||
	_, _, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeAdmin)
 | 
						adminId, userId, err := this.ValidateAdminAndUser(ctx, 0)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -39,7 +39,7 @@ func (this *DNSDomainService) CreateDNSDomain(ctx context.Context, req *pb.Creat
 | 
				
			|||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	domainId, err := models.SharedDNSDomainDAO.CreateDomain(req.DnsProviderId, req.Name)
 | 
						domainId, err := models.SharedDNSDomainDAO.CreateDomain(adminId, userId, req.DnsProviderId, req.Name)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,12 +38,12 @@ type NodeService struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// 创建节点
 | 
					// 创建节点
 | 
				
			||||||
func (this *NodeService) CreateNode(ctx context.Context, req *pb.CreateNodeRequest) (*pb.CreateNodeResponse, error) {
 | 
					func (this *NodeService) CreateNode(ctx context.Context, req *pb.CreateNodeRequest) (*pb.CreateNodeResponse, error) {
 | 
				
			||||||
	_, _, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeAdmin)
 | 
						adminId, err := this.ValidateAdmin(ctx, 0)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	nodeId, err := models.SharedNodeDAO.CreateNode(req.Name, req.ClusterId, req.GroupId)
 | 
						nodeId, err := models.SharedNodeDAO.CreateNode(adminId, req.Name, req.ClusterId, req.GroupId)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -87,7 +87,12 @@ func (this *NodeService) RegisterClusterNode(ctx context.Context, req *pb.Regist
 | 
				
			|||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	nodeId, err := models.SharedNodeDAO.CreateNode(req.Name, clusterId, 0)
 | 
						adminId, err := models.SharedNodeClusterDAO.FindClusterAdminId(clusterId)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						nodeId, err := models.SharedNodeDAO.CreateNode(adminId, req.Name, clusterId, 0)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,12 +19,12 @@ type NodeClusterService struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// 创建集群
 | 
					// 创建集群
 | 
				
			||||||
func (this *NodeClusterService) CreateNodeCluster(ctx context.Context, req *pb.CreateNodeClusterRequest) (*pb.CreateNodeClusterResponse, error) {
 | 
					func (this *NodeClusterService) CreateNodeCluster(ctx context.Context, req *pb.CreateNodeClusterRequest) (*pb.CreateNodeClusterResponse, error) {
 | 
				
			||||||
	_, _, err := rpcutils.ValidateRequest(ctx, rpcutils.UserTypeAdmin)
 | 
						adminId, err := this.ValidateAdmin(ctx, 0)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	clusterId, err := models.SharedNodeClusterDAO.CreateCluster(req.Name, req.GrantId, req.InstallDir, req.DnsDomainId, req.DnsName)
 | 
						clusterId, err := models.SharedNodeClusterDAO.CreateCluster(adminId, req.Name, req.GrantId, req.InstallDir, req.DnsDomainId, req.DnsName)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -57,11 +57,29 @@ func upgradeV0_0_3(db *dbs.DB) error {
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 升级edgeDNSDomains
 | 
				
			||||||
 | 
						_, err = db.Exec("UPDATE edgeDNSDomains SET adminId=? WHERE adminId=0 AND userId=0", adminId)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 升级edgeSSLCerts
 | 
						// 升级edgeSSLCerts
 | 
				
			||||||
	_, err = db.Exec("UPDATE edgeSSLCerts SET adminId=? WHERE adminId=0 AND userId=0", adminId)
 | 
						_, err = db.Exec("UPDATE edgeSSLCerts SET adminId=? WHERE adminId=0 AND userId=0", adminId)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 升级edgeNodeClusters
 | 
				
			||||||
 | 
						_, err = db.Exec("UPDATE edgeNodeClusters SET adminId=? WHERE adminId=0 AND userId=0", adminId)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 升级edgeNodes
 | 
				
			||||||
 | 
						_, err = db.Exec("UPDATE edgeNodes SET adminId=? WHERE adminId=0 AND userId=0", adminId)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										204
									
								
								internal/tasks/ssl_cert_expire_check_executor.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										204
									
								
								internal/tasks/ssl_cert_expire_check_executor.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,204 @@
 | 
				
			|||||||
 | 
					package tasks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/db/models"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/dbs"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/logs"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/maps"
 | 
				
			||||||
 | 
						timeutil "github.com/iwind/TeaGo/utils/time"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						dbs.OnReady(func() {
 | 
				
			||||||
 | 
							go NewSSLCertExpireCheckExecutor().Start()
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 证书检查任务
 | 
				
			||||||
 | 
					type SSLCertExpireCheckExecutor struct {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewSSLCertExpireCheckExecutor() *SSLCertExpireCheckExecutor {
 | 
				
			||||||
 | 
						return &SSLCertExpireCheckExecutor{}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 启动任务
 | 
				
			||||||
 | 
					func (this *SSLCertExpireCheckExecutor) Start() {
 | 
				
			||||||
 | 
						seconds := int64(3600)
 | 
				
			||||||
 | 
						ticker := time.NewTicker(time.Duration(seconds) * time.Second)
 | 
				
			||||||
 | 
						for range ticker.C {
 | 
				
			||||||
 | 
							err := this.loop(seconds)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								logs.Println("[ERROR][SSLCertExpireCheckExecutor]" + err.Error())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 单次执行
 | 
				
			||||||
 | 
					func (this *SSLCertExpireCheckExecutor) loop(seconds int64) error {
 | 
				
			||||||
 | 
						// 检查上次运行时间,防止重复运行
 | 
				
			||||||
 | 
						settingKey := "sslCertExpiringCheck"
 | 
				
			||||||
 | 
						timestamp := time.Now().Unix()
 | 
				
			||||||
 | 
						c, err := models.SharedSysSettingDAO.CompareInt64Setting(settingKey, timestamp-seconds)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if c > 0 {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 记录时间
 | 
				
			||||||
 | 
						err = models.SharedSysSettingDAO.UpdateSetting(settingKey, []byte(numberutils.FormatInt64(timestamp)))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 查找需要自动更新的证书
 | 
				
			||||||
 | 
						// 30, 14 ... 是到期的天数
 | 
				
			||||||
 | 
						for _, days := range []int{30, 14, 7} {
 | 
				
			||||||
 | 
							certs, err := models.SharedSSLCertDAO.FindAllExpiringCerts(days)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for _, cert := range certs {
 | 
				
			||||||
 | 
								// 发送消息
 | 
				
			||||||
 | 
								msg := "SSL证书\"" + cert.Name + "\"(" + cert.DnsNames + ")在" + strconv.Itoa(days) + "天后将到期,"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// 是否有自动更新任务
 | 
				
			||||||
 | 
								if cert.AcmeTaskId > 0 {
 | 
				
			||||||
 | 
									task, err := models.SharedACMETaskDAO.FindEnabledACMETask(int64(cert.AcmeTaskId))
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
 | 
										return err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if task != nil {
 | 
				
			||||||
 | 
										if task.AutoRenew == 1 {
 | 
				
			||||||
 | 
											msg += "此证书是免费申请的证书,且已设置了自动续期,将会在到期前三天自动尝试续期。"
 | 
				
			||||||
 | 
										} else {
 | 
				
			||||||
 | 
											msg += "此证书是免费申请的证书,没有设置自动续期,请在到期前手动执行续期任务。"
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									msg += "请及时更新证书。"
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								err = models.SharedMessageDAO.CreateMessage(int64(cert.AdminId), int64(cert.UserId), models.MessageTypeSSLCertExpiring, models.MessageLevelWarning, msg, maps.Map{
 | 
				
			||||||
 | 
									"certId":     cert.Id,
 | 
				
			||||||
 | 
									"acmeTaskId": cert.AcmeTaskId,
 | 
				
			||||||
 | 
								}.AsJSON())
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// 设置最后通知时间
 | 
				
			||||||
 | 
								err = models.SharedSSLCertDAO.UpdateCertNotifiedAt(int64(cert.Id))
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 自动续期
 | 
				
			||||||
 | 
						for _, days := range []int{3, 2, 1} {
 | 
				
			||||||
 | 
							certs, err := models.SharedSSLCertDAO.FindAllExpiringCerts(days)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for _, cert := range certs {
 | 
				
			||||||
 | 
								// 发送消息
 | 
				
			||||||
 | 
								msg := "SSL证书\"" + cert.Name + "\"(" + cert.DnsNames + ")在" + strconv.Itoa(days) + "天后将到期,"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// 是否有自动更新任务
 | 
				
			||||||
 | 
								if cert.AcmeTaskId > 0 {
 | 
				
			||||||
 | 
									task, err := models.SharedACMETaskDAO.FindEnabledACMETask(int64(cert.AcmeTaskId))
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
 | 
										return err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if task != nil {
 | 
				
			||||||
 | 
										if task.AutoRenew == 1 {
 | 
				
			||||||
 | 
											isOk, errMsg, _ := models.SharedACMETaskDAO.RunTask(int64(cert.AcmeTaskId))
 | 
				
			||||||
 | 
											if isOk {
 | 
				
			||||||
 | 
												// 发送成功通知
 | 
				
			||||||
 | 
												msg = "系统已成功为你自动更新了证书\"" + cert.Name + "\"(" + cert.DnsNames + ")。"
 | 
				
			||||||
 | 
												err = models.SharedMessageDAO.CreateMessage(int64(cert.AdminId), int64(cert.UserId), models.MessageTypeSSLCertACMETaskSuccess, models.MessageLevelSuccess, msg, maps.Map{
 | 
				
			||||||
 | 
													"certId":     cert.Id,
 | 
				
			||||||
 | 
													"acmeTaskId": cert.AcmeTaskId,
 | 
				
			||||||
 | 
												}.AsJSON())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
												// 更新通知时间
 | 
				
			||||||
 | 
												err = models.SharedSSLCertDAO.UpdateCertNotifiedAt(int64(cert.Id))
 | 
				
			||||||
 | 
												if err != nil {
 | 
				
			||||||
 | 
													return err
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
											} else {
 | 
				
			||||||
 | 
												// 发送失败通知
 | 
				
			||||||
 | 
												msg = "系统在尝试自动更新证书\"" + cert.Name + "\"(" + cert.DnsNames + ")时发生错误:" + errMsg + "。请检查系统设置并修复错误。"
 | 
				
			||||||
 | 
												err = models.SharedMessageDAO.CreateMessage(int64(cert.AdminId), int64(cert.UserId), models.MessageTypeSSLCertACMETaskFailed, models.MessageLevelError, msg, maps.Map{
 | 
				
			||||||
 | 
													"certId":     cert.Id,
 | 
				
			||||||
 | 
													"acmeTaskId": cert.AcmeTaskId,
 | 
				
			||||||
 | 
												}.AsJSON())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
												// 更新通知时间
 | 
				
			||||||
 | 
												err = models.SharedSSLCertDAO.UpdateCertNotifiedAt(int64(cert.Id))
 | 
				
			||||||
 | 
												if err != nil {
 | 
				
			||||||
 | 
													return err
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											// 中止不发送消息
 | 
				
			||||||
 | 
											continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										} else {
 | 
				
			||||||
 | 
											msg += "此证书是免费申请的证书,没有设置自动续期,请在到期前手动执行续期任务。"
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									msg += "请及时更新证书。"
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								err = models.SharedMessageDAO.CreateMessage(int64(cert.AdminId), int64(cert.UserId), models.MessageTypeSSLCertExpiring, models.MessageLevelWarning, msg, maps.Map{
 | 
				
			||||||
 | 
									"certId":     cert.Id,
 | 
				
			||||||
 | 
									"acmeTaskId": cert.AcmeTaskId,
 | 
				
			||||||
 | 
								}.AsJSON())
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// 设置最后通知时间
 | 
				
			||||||
 | 
								err = models.SharedSSLCertDAO.UpdateCertNotifiedAt(int64(cert.Id))
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 当天过期
 | 
				
			||||||
 | 
						for _, days := range []int{0} {
 | 
				
			||||||
 | 
							certs, err := models.SharedSSLCertDAO.FindAllExpiringCerts(days)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for _, cert := range certs {
 | 
				
			||||||
 | 
								// 发送消息
 | 
				
			||||||
 | 
								today := timeutil.Format("Y-m-d")
 | 
				
			||||||
 | 
								msg := "SSL证书\"" + cert.Name + "\"(" + cert.DnsNames + ")在今天(" + today + ")过期,请及时更新证书,之后将不再重复提醒。"
 | 
				
			||||||
 | 
								err = models.SharedMessageDAO.CreateMessage(int64(cert.AdminId), int64(cert.UserId), models.MessageTypeSSLCertExpiring, models.MessageLevelWarning, msg, maps.Map{
 | 
				
			||||||
 | 
									"certId":     cert.Id,
 | 
				
			||||||
 | 
									"acmeTaskId": cert.AcmeTaskId,
 | 
				
			||||||
 | 
								}.AsJSON())
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// 设置最后通知时间
 | 
				
			||||||
 | 
								err = models.SharedSSLCertDAO.UpdateCertNotifiedAt(int64(cert.Id))
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										25
									
								
								internal/tasks/ssl_cert_expire_check_executor_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								internal/tasks/ssl_cert_expire_check_executor_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					package tasks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/dbs"
 | 
				
			||||||
 | 
						timeutil "github.com/iwind/TeaGo/utils/time"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestSSLCertExpireCheckExecutor_loop(t *testing.T) {
 | 
				
			||||||
 | 
						dbs.NotifyReady()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						t.Log("30 days later: ", timeutil.FormatTime("Y-m-d", time.Now().Unix()+30*86400), time.Now().Unix()+30*86400)
 | 
				
			||||||
 | 
						t.Log("14 days later: ", timeutil.FormatTime("Y-m-d", time.Now().Unix()+14*86400), time.Now().Unix()+14*86400)
 | 
				
			||||||
 | 
						t.Log("7 days later: ", timeutil.FormatTime("Y-m-d", time.Now().Unix()+7*86400), time.Now().Unix()+7*86400)
 | 
				
			||||||
 | 
						t.Log("3 days later: ", timeutil.FormatTime("Y-m-d", time.Now().Unix()+3*86400), time.Now().Unix()+3*86400)
 | 
				
			||||||
 | 
						t.Log("today: ", timeutil.FormatTime("Y-m-d", time.Now().Unix()), time.Now().Unix())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						executor := NewSSLCertExpireCheckExecutor()
 | 
				
			||||||
 | 
						err := executor.loop(0)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						t.Log("ok")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user