1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-07-24 15:59:41 +02:00

feat(api): revamp scheduling to introduce system schedules (#2433)

* feat(api): revamp scheduling to introduce system schedules

* fix(api): fix linting issues

* fix(api): fix lint issues

* refactor(api): fix lint issues
This commit is contained in:
Anthony Lapenna 2018-11-06 22:49:48 +13:00 committed by GitHub
parent dbbea0a20f
commit 110fcc46a6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 475 additions and 297 deletions

View file

@ -6,7 +6,6 @@ import (
"github.com/gorilla/mux"
httperror "github.com/portainer/libhttp/error"
"github.com/portainer/portainer"
"github.com/portainer/portainer/cron"
"github.com/portainer/portainer/http/security"
)
@ -39,13 +38,3 @@ func NewHandler(bouncer *security.RequestBouncer) *Handler {
return h
}
func (handler *Handler) createTaskExecutionContext(scheduleID portainer.ScheduleID, endpoints []portainer.EndpointID) *cron.ScriptTaskContext {
return &cron.ScriptTaskContext{
JobService: handler.JobService,
EndpointService: handler.EndpointService,
FileService: handler.FileService,
ScheduleID: scheduleID,
TargetEndpoints: endpoints,
}
}

View file

@ -142,20 +142,27 @@ func (handler *Handler) createSchedule(name, image, cronExpression string, endpo
return nil, err
}
taskContext := handler.createTaskExecutionContext(scheduleIdentifier, endpoints)
task := cron.NewScriptTask(image, scriptPath, taskContext)
err = handler.JobScheduler.ScheduleTask(cronExpression, task)
if err != nil {
return nil, err
job := &portainer.ScriptExecutionJob{
Endpoints: endpoints,
Image: image,
ScriptPath: scriptPath,
ScheduleID: scheduleIdentifier,
}
schedule := &portainer.Schedule{
ID: scheduleIdentifier,
Name: name,
Endpoints: endpoints,
CronExpression: cronExpression,
Task: task,
ID: scheduleIdentifier,
Name: name,
CronExpression: cronExpression,
JobType: portainer.ScriptExecutionJobType,
ScriptExecutionJob: job,
}
jobContext := cron.NewScriptExecutionJobContext(handler.JobService, handler.EndpointService, handler.FileService)
jobRunner := cron.NewScriptExecutionJobRunner(job, jobContext)
err = handler.JobScheduler.CreateSchedule(schedule, jobRunner)
if err != nil {
return nil, err
}
err = handler.ScheduleService.CreateSchedule(schedule)

View file

@ -1,6 +1,7 @@
package schedules
import (
"errors"
"net/http"
httperror "github.com/portainer/libhttp/error"
@ -15,7 +16,16 @@ func (handler *Handler) scheduleDelete(w http.ResponseWriter, r *http.Request) *
return &httperror.HandlerError{http.StatusBadRequest, "Invalid schedule identifier route variable", err}
}
handler.JobScheduler.UnscheduleTask(portainer.ScheduleID(scheduleID))
schedule, err := handler.ScheduleService.Schedule(portainer.ScheduleID(scheduleID))
if err == portainer.ErrObjectNotFound {
return &httperror.HandlerError{http.StatusNotFound, "Unable to find a schedule with the specified identifier inside the database", err}
} else if err != nil {
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to find a schedule with the specified identifier inside the database", err}
}
if schedule.JobType == portainer.SnapshotJobType || schedule.JobType == portainer.EndpointSyncJobType {
return &httperror.HandlerError{http.StatusBadRequest, "Cannot remove system schedules", errors.New("Cannot remove system schedule")}
}
scheduleFolder := handler.FileService.GetScheduleFolder(portainer.ScheduleID(scheduleID))
err = handler.FileService.RemoveDirectory(scheduleFolder)

View file

@ -40,14 +40,14 @@ func (handler *Handler) scheduleUpdate(w http.ResponseWriter, r *http.Request) *
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to find a schedule with the specified identifier inside the database", err}
}
updateTaskSchedule := updateSchedule(schedule, &payload)
if updateTaskSchedule {
taskContext := handler.createTaskExecutionContext(schedule.ID, schedule.Endpoints)
schedule.Task.(cron.ScriptTask).SetContext(taskContext)
updateJobSchedule := updateSchedule(schedule, &payload)
if updateJobSchedule {
err := handler.JobScheduler.UpdateScheduledTask(schedule.ID, schedule.CronExpression, schedule.Task)
jobContext := cron.NewScriptExecutionJobContext(handler.JobService, handler.EndpointService, handler.FileService)
jobRunner := cron.NewScriptExecutionJobRunner(schedule.ScriptExecutionJob, jobContext)
err := handler.JobScheduler.UpdateSchedule(schedule, jobRunner)
if err != nil {
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to update task scheduler", err}
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to update job scheduler", err}
}
}
@ -60,28 +60,26 @@ func (handler *Handler) scheduleUpdate(w http.ResponseWriter, r *http.Request) *
}
func updateSchedule(schedule *portainer.Schedule, payload *scheduleUpdatePayload) bool {
updateTaskSchedule := false
updateJobSchedule := false
if payload.Name != nil {
schedule.Name = *payload.Name
}
if payload.Endpoints != nil {
schedule.Endpoints = payload.Endpoints
updateTaskSchedule = true
schedule.ScriptExecutionJob.Endpoints = payload.Endpoints
updateJobSchedule = true
}
if payload.CronExpression != nil {
schedule.CronExpression = *payload.CronExpression
updateTaskSchedule = true
updateJobSchedule = true
}
if payload.Image != nil {
t := schedule.Task.(cron.ScriptTask)
t.Image = *payload.Image
updateTaskSchedule = true
schedule.ScriptExecutionJob.Image = *payload.Image
updateJobSchedule = true
}
return updateTaskSchedule
return updateJobSchedule
}

View file

@ -16,6 +16,7 @@ type Handler struct {
LDAPService portainer.LDAPService
FileService portainer.FileService
JobScheduler portainer.JobScheduler
ScheduleService portainer.ScheduleService
}
// NewHandler creates a handler to manage settings operations.

View file

@ -8,7 +8,6 @@ import (
"github.com/portainer/libhttp/request"
"github.com/portainer/libhttp/response"
"github.com/portainer/portainer"
"github.com/portainer/portainer/cron"
"github.com/portainer/portainer/filesystem"
)
@ -78,11 +77,9 @@ func (handler *Handler) settingsUpdate(w http.ResponseWriter, r *http.Request) *
}
if payload.SnapshotInterval != nil && *payload.SnapshotInterval != settings.SnapshotInterval {
settings.SnapshotInterval = *payload.SnapshotInterval
err := handler.JobScheduler.UpdateScheduledTask(0, "@every "+*payload.SnapshotInterval, cron.NewSnapshotTask(nil))
err := handler.updateSnapshotInterval(settings, *payload.SnapshotInterval)
if err != nil {
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to update task scheduler", err}
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to update snapshot interval", err}
}
}
@ -99,6 +96,27 @@ func (handler *Handler) settingsUpdate(w http.ResponseWriter, r *http.Request) *
return response.JSON(w, settings)
}
func (handler *Handler) updateSnapshotInterval(settings *portainer.Settings, snapshotInterval string) error {
settings.SnapshotInterval = snapshotInterval
schedules, err := handler.ScheduleService.SchedulesByJobType(portainer.SnapshotJobType)
if err != nil {
return err
}
if len(schedules) != 0 {
snapshotSchedule := schedules[0]
snapshotSchedule.CronExpression = "@every " + snapshotInterval
err := handler.JobScheduler.UpdateSchedule(&snapshotSchedule, nil)
if err != nil {
return err
}
}
return nil
}
func (handler *Handler) updateTLS(settings *portainer.Settings) *httperror.HandlerError {
if (settings.LDAPSettings.TLSConfig.TLS || settings.LDAPSettings.StartTLS) && !settings.LDAPSettings.TLSConfig.TLSSkipVerify {
caCertPath, _ := handler.FileService.GetPathForTLSFile(filesystem.LDAPStorePath, portainer.TLSFileCA)