Gestionnaire de jobs et workflows
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

220 lines
5.2 KiB

/*
------------------------------------------------------------------------------------------------------------------------
####### dune ####### Copyright (c) 2021-2022 losyme ################################################ MIT License #######
------------------------------------------------------------------------------------------------------------------------
*/
package model
import (
"time"
"forge.chapril.org/dune/jw"
"forge.chapril.org/losyme/errors"
"forge.chapril.org/losyme/uuid"
)
func validateID(id *string) error {
if *id == "" {
*id = uuid.New()
} else if !uuid.IsValid(*id) {
return errors.New( /////////////////////////////////////////////////////////////////////////////////////////////
"this identifier is not a UUID",
"id", *id,
)
}
return nil
}
func validatePriority(p *jw.Priority) {
if *p < jw.PriorityNone {
*p = jw.PriorityNone
} else if *p > jw.PriorityCritical {
*p = jw.PriorityCritical
}
}
func (m *model) validateJob(job *jw.Job) error {
if err := m.cs.Storage().ValidateJob(job); err != nil {
return err
}
if err := validateID(&job.ID); err != nil {
return err
}
if job.Name == "" {
job.Name = "?"
}
if job.Namespace == "" {
return errors.New("namespace must not be empty") ///////////////////////////////////////////////////////////////
}
if job.Type == "" {
return errors.New("type must not be empty") ////////////////////////////////////////////////////////////////////
}
if job.Origin == "" {
job.Origin = "?"
}
validatePriority(&job.Priority)
if job.Public == nil {
job.Public = make(map[string]interface{})
}
if job.Private == nil {
job.Private = make(map[string]interface{})
}
if job.MaxAttempts < 0 {
job.MaxAttempts = 0
}
if job.MaxOccurrences < 0 {
job.MaxOccurrences = 0
}
job.Workflow = nil
job.CreatedAt = time.Now()
job.Status = jw.StatusTodo
job.Attempt = 0
job.Session = 0
job.Result = nil
job.FinishedAt = nil
job.TimeReference = job.CreatedAt
job.Weight = 0
job.ErrorCounter = 0
job.LastError = nil
return nil
}
func validateNext(wf *jw.Workflow, next map[string]interface{}) error {
if next == nil {
return nil
}
for key, v := range next {
switch value := v.(type) {
case nil:
// ok
case string:
if _, ok := wf.AllSteps[value]; !ok {
return errors.New( /////////////////////////////////////////////////////////////////////////////////////
"the step associated with this key does not exist",
"key", key,
"step", value,
)
}
case map[string]interface{}:
for k, v := range value {
switch k {
case "config":
// ok
case "step":
s, ok := v.(string)
if !ok {
return errors.New( /////////////////////////////////////////////////////////////////////////////
"the 'step' key must be a string",
"key", key,
)
}
if _, ok := wf.AllSteps[s]; !ok {
return errors.New( /////////////////////////////////////////////////////////////////////////////
"the step associated with these keys does not exist",
"keys", key+"/"+k,
"step", s,
)
}
default:
return errors.New( /////////////////////////////////////////////////////////////////////////////////
"the last of these keys is not known",
"keys", key+"/"+k,
)
}
}
default:
return errors.New( /////////////////////////////////////////////////////////////////////////////////////////
"the value associated with this key is not valid",
"key", key,
)
}
}
return nil
}
func validateStep(wf *jw.Workflow, step *jw.Step) error {
if step.Namespace == "" {
return errors.New("namespace must not be empty") ///////////////////////////////////////////////////////////////
}
if step.Type == "" {
return errors.New("type must not be empty") ////////////////////////////////////////////////////////////////////
}
return validateNext(wf, step.Next)
}
func (m *model) validateWorkflow(wf *jw.Workflow) error {
if err := m.cs.Storage().ValidateWorkflow(wf); err != nil {
return err
}
if err := validateID(&wf.ID); err != nil {
return err
}
if wf.Name == "" {
wf.Name = "?"
}
if wf.Description == "" {
wf.Description = "?"
}
if wf.Origin == "" {
wf.Origin = "?"
}
if wf.FirstStep == "" {
return errors.New("first step must not be empty") //////////////////////////////////////////////////////////////
}
if len(wf.AllSteps) == 0 {
return errors.New("there are no steps") ////////////////////////////////////////////////////////////////////////
}
if _, ok := wf.AllSteps[wf.FirstStep]; !ok {
return errors.New("first step does not match any step") ////////////////////////////////////////////////////////
}
for name, step := range wf.AllSteps {
if err := validateStep(wf, step); err != nil {
return errors.WithMessage( /////////////////////////////////////////////////////////////////////////////////
err,
"this step is not valid",
"name", name,
)
}
}
if wf.Data == nil {
wf.Data = make(map[string]interface{})
}
wf.CreatedAt = time.Now()
wf.Status = jw.StatusRunning
wf.FinishedAt = nil
return nil
}
/*
######################################################################################################## @(°_°)@ #######
*/