2021-09-06 13:05:10 +02:00
|
|
|
package schedules
|
|
|
|
|
|
|
|
import (
|
2021-09-06 14:01:38 +02:00
|
|
|
log "github.com/Sirupsen/logrus"
|
2021-09-06 13:05:10 +02:00
|
|
|
"github.com/ansible-semaphore/semaphore/db"
|
2022-01-30 18:43:15 +01:00
|
|
|
"github.com/ansible-semaphore/semaphore/lib"
|
2022-01-29 19:00:21 +01:00
|
|
|
"github.com/ansible-semaphore/semaphore/services/tasks"
|
2021-09-06 13:05:10 +02:00
|
|
|
"github.com/robfig/cron/v3"
|
2021-09-06 17:45:43 +02:00
|
|
|
"sync"
|
2021-09-06 13:05:10 +02:00
|
|
|
)
|
|
|
|
|
2021-09-06 14:01:38 +02:00
|
|
|
type ScheduleRunner struct {
|
2022-01-31 11:43:13 +01:00
|
|
|
projectID int
|
|
|
|
scheduleID int
|
|
|
|
pool *SchedulePool
|
2021-09-06 13:05:10 +02:00
|
|
|
}
|
|
|
|
|
2022-01-31 11:43:13 +01:00
|
|
|
func (r ScheduleRunner) tryUpdateScheduleCommitHash(schedule db.Schedule) (updated bool, err error) {
|
|
|
|
repo, err := r.pool.store.GetRepository(schedule.ProjectID, *schedule.RepositoryID)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2022-01-30 18:43:15 +01:00
|
|
|
|
2022-02-06 13:17:08 +01:00
|
|
|
err = repo.SSHKey.DeserializeSecret()
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-01-31 11:43:13 +01:00
|
|
|
remoteHash, err := lib.GitRepository{
|
|
|
|
Logger: nil,
|
|
|
|
TemplateID: schedule.TemplateID,
|
|
|
|
Repository: repo,
|
|
|
|
}.GetLastRemoteCommitHash()
|
2022-01-30 18:43:15 +01:00
|
|
|
|
2022-01-31 11:43:13 +01:00
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2022-01-30 18:43:15 +01:00
|
|
|
|
2022-01-31 11:43:13 +01:00
|
|
|
if schedule.LastCommitHash != nil && remoteHash == *schedule.LastCommitHash {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
err = r.pool.store.SetScheduleCommitHash(schedule.ProjectID, schedule.ID, remoteHash)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
updated = true
|
|
|
|
return
|
|
|
|
}
|
2022-01-30 18:43:15 +01:00
|
|
|
|
2022-01-31 11:43:13 +01:00
|
|
|
func (r ScheduleRunner) Run() {
|
2022-11-09 17:30:35 +01:00
|
|
|
if !r.pool.store.KeepConnection() {
|
|
|
|
r.pool.store.Connect("schedule")
|
|
|
|
defer r.pool.store.Close("schedule")
|
|
|
|
}
|
2022-01-31 11:43:13 +01:00
|
|
|
schedule, err := r.pool.store.GetSchedule(r.projectID, r.scheduleID)
|
|
|
|
if err != nil {
|
|
|
|
log.Error(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if schedule.RepositoryID != nil {
|
|
|
|
var updated bool
|
|
|
|
updated, err = r.tryUpdateScheduleCommitHash(schedule)
|
2022-01-30 18:43:15 +01:00
|
|
|
if err != nil {
|
|
|
|
log.Error(err)
|
|
|
|
return
|
|
|
|
}
|
2022-01-31 11:43:13 +01:00
|
|
|
if !updated {
|
|
|
|
return
|
|
|
|
}
|
2022-01-30 18:43:15 +01:00
|
|
|
}
|
|
|
|
|
2022-01-31 11:43:13 +01:00
|
|
|
_, err = r.pool.taskPool.AddTask(db.Task{
|
|
|
|
TemplateID: schedule.TemplateID,
|
|
|
|
ProjectID: schedule.ProjectID,
|
|
|
|
}, nil, schedule.ProjectID)
|
2022-01-30 18:43:15 +01:00
|
|
|
|
2021-09-06 14:01:38 +02:00
|
|
|
if err != nil {
|
|
|
|
log.Error(err)
|
|
|
|
}
|
2021-09-06 13:05:10 +02:00
|
|
|
}
|
|
|
|
|
2021-09-06 14:01:38 +02:00
|
|
|
type SchedulePool struct {
|
2022-01-29 19:00:21 +01:00
|
|
|
cron *cron.Cron
|
|
|
|
locker sync.Locker
|
|
|
|
store db.Store
|
|
|
|
taskPool *tasks.TaskPool
|
2021-09-06 13:05:10 +02:00
|
|
|
}
|
|
|
|
|
2021-09-06 17:45:43 +02:00
|
|
|
func (p *SchedulePool) init() {
|
2021-09-06 13:05:10 +02:00
|
|
|
p.cron = cron.New()
|
2021-09-06 17:45:43 +02:00
|
|
|
p.locker = &sync.Mutex{}
|
|
|
|
}
|
2021-09-06 13:05:10 +02:00
|
|
|
|
2022-01-29 19:00:21 +01:00
|
|
|
func (p *SchedulePool) Refresh() {
|
2021-09-07 10:42:06 +02:00
|
|
|
defer p.locker.Unlock()
|
|
|
|
|
2022-01-29 19:00:21 +01:00
|
|
|
schedules, err := p.store.GetSchedules()
|
2021-09-06 13:05:10 +02:00
|
|
|
|
|
|
|
if err != nil {
|
2021-09-06 14:01:38 +02:00
|
|
|
log.Error(err)
|
2021-09-06 13:05:10 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-09-06 17:45:43 +02:00
|
|
|
p.locker.Lock()
|
|
|
|
p.clear()
|
2021-09-06 13:05:10 +02:00
|
|
|
for _, schedule := range schedules {
|
2021-09-06 17:45:43 +02:00
|
|
|
_, err := p.addRunner(ScheduleRunner{
|
2022-01-31 11:43:13 +01:00
|
|
|
projectID: schedule.ProjectID,
|
|
|
|
scheduleID: schedule.ID,
|
|
|
|
pool: p,
|
|
|
|
}, schedule.CronFormat)
|
2021-09-06 13:05:10 +02:00
|
|
|
if err != nil {
|
2021-09-06 14:01:38 +02:00
|
|
|
log.Error(err)
|
2021-09-06 13:05:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-31 11:43:13 +01:00
|
|
|
func (p *SchedulePool) addRunner(runner ScheduleRunner, cronFormat string) (int, error) {
|
|
|
|
id, err := p.cron.AddJob(cronFormat, runner)
|
2021-09-06 17:45:43 +02:00
|
|
|
|
2021-09-06 13:05:10 +02:00
|
|
|
if err != nil {
|
2021-09-06 17:45:43 +02:00
|
|
|
return 0, err
|
2021-09-06 13:05:10 +02:00
|
|
|
}
|
2021-09-06 17:45:43 +02:00
|
|
|
|
|
|
|
return int(id), nil
|
2021-09-06 13:05:10 +02:00
|
|
|
}
|
|
|
|
|
2021-09-06 14:01:38 +02:00
|
|
|
func (p *SchedulePool) Run() {
|
2021-09-06 13:05:10 +02:00
|
|
|
p.cron.Run()
|
|
|
|
}
|
|
|
|
|
2021-09-06 17:45:43 +02:00
|
|
|
func (p *SchedulePool) clear() {
|
2021-09-06 14:01:38 +02:00
|
|
|
runners := p.cron.Entries()
|
|
|
|
for _, r := range runners {
|
|
|
|
p.cron.Remove(r.ID)
|
|
|
|
}
|
2021-09-06 17:45:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (p *SchedulePool) Destroy() {
|
2021-09-07 10:42:06 +02:00
|
|
|
defer p.locker.Unlock()
|
2021-09-06 17:45:43 +02:00
|
|
|
p.locker.Lock()
|
|
|
|
p.cron.Stop()
|
|
|
|
p.clear()
|
2021-09-06 14:01:38 +02:00
|
|
|
p.cron = nil
|
|
|
|
}
|
2021-09-06 13:05:10 +02:00
|
|
|
|
2022-01-29 19:00:21 +01:00
|
|
|
func CreateSchedulePool(store db.Store, taskPool *tasks.TaskPool) SchedulePool {
|
|
|
|
pool := SchedulePool{
|
|
|
|
store: store,
|
|
|
|
taskPool: taskPool,
|
|
|
|
}
|
2021-09-06 17:45:43 +02:00
|
|
|
pool.init()
|
2022-01-29 19:00:21 +01:00
|
|
|
pool.Refresh()
|
|
|
|
return pool
|
2021-09-06 13:05:10 +02:00
|
|
|
}
|
2021-09-06 17:45:43 +02:00
|
|
|
|
|
|
|
func ValidateCronFormat(cronFormat string) error {
|
|
|
|
_, err := cron.ParseStandard(cronFormat)
|
|
|
|
return err
|
2022-01-29 19:00:21 +01:00
|
|
|
}
|