Skip to content

Commit

Permalink
feat: added config validation
Browse files Browse the repository at this point in the history
  • Loading branch information
FMotalleb committed Jun 4, 2024
1 parent 8de6f91 commit 99a7275
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 47 deletions.
8 changes: 8 additions & 0 deletions abstraction/validatable.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package abstraction

type (
ValidatableStr string
Validatable interface {
Validate() error
}
)
2 changes: 1 addition & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ func initConfig() {
"Cannot unmarshal the config file: %s",
)
panicOnErr(
CFG.Initialize(),
CFG.Validate(),
"Failed to initialize config file: %s",
)
}
64 changes: 19 additions & 45 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,23 @@ type (
}

JobConfig struct {
Name string `mapstructure:"name" json:"name,omitempty"`
Description string `mapstructure:"description" json:"description,omitempty"`
Enabled bool `mapstructure:"enabled" json:"enabled,omitempty"`
Tasks []Task `mapstructure:"tasks" json:"tasks,omitempty"`
Scheduler JobScheduler `mapstructure:"scheduler" json:"scheduler"`
Retries int `mapstructure:"retries" json:"retries,omitempty"`
RetryDelay time.Duration `mapstructure:"retry-delay" json:"retry_delay,omitempty"`
Timeout time.Duration `mapstructure:"timeout" json:"timeout,omitempty"`
Hooks JobHooks `mapstructure:"hooks" json:"hooks,omitempty"`
Env EnvVariables `mapstructure:"env" json:"env,omitempty"`
Metadata JobMetadata `mapstructure:"metadata" json:"metadata,omitempty"`
Name string `mapstructure:"name" json:"name,omitempty"`
Description string `mapstructure:"description" json:"description,omitempty"`
Enabled bool `mapstructure:"enabled" json:"enabled,omitempty"`
Tasks []Task `mapstructure:"tasks" json:"tasks,omitempty"`
Schedulers []JobScheduler `mapstructure:"schedulers" json:"schedulers"`
Retries uint `mapstructure:"retries" json:"retries,omitempty"`
RetryDelay time.Duration `mapstructure:"retry-delay" json:"retry_delay,omitempty"`
Timeout time.Duration `mapstructure:"timeout" json:"timeout,omitempty"`
Hooks JobHooks `mapstructure:"hooks" json:"hooks,omitempty"`
Env EnvVariables `mapstructure:"env" json:"env,omitempty"`
Metadata JobMetadata `mapstructure:"metadata" json:"metadata,omitempty"`
}

JobScheduler struct {
Cron string `mapstructure:"cron" json:"cron,omitempty"`
Interval time.Duration `mapstructure:"interval" json:"interval,omitempty"`
At time.Time `mapstructure:"at" json:"at,omitempty"`
At *time.Time `mapstructure:"at" json:"at,omitempty"`
}

JobHooks struct {
Expand All @@ -45,38 +45,12 @@ type (
}

Task struct {
Post string `mapstructure:"get" json:"post,omitempty"`
Get string `mapstructure:"post" json:"get,omitempty"`
Command string `mapstructure:"command" json:"command,omitempty"`
Args []string `mapstructure:"args" json:"args,omitempty"`
Headers map[string]string `mapstructure:"headers" json:"headers,omitempty"`
Data map[string]any `mapstructure:"data" json:"data,omitempty"`
Post string `mapstructure:"get" json:"post,omitempty"`
Get string `mapstructure:"post" json:"get,omitempty"`
Command string `mapstructure:"command" json:"command,omitempty"`
Args []string `mapstructure:"args" json:"args,omitempty"`
WorkingDirectory string `mapstructure:"working_directory" json:"working_directory,omitempty"`
Headers map[string]string `mapstructure:"headers" json:"headers,omitempty"`
Data map[string]any `mapstructure:"data" json:"data,omitempty"`
}
)

func (t *Task) Initialize() error {
return nil
}

func (h *JobHooks) Initialize() error {
return nil
}

func (s *JobScheduler) Initialize() error {
return nil
}

func (j *JobConfig) Initialize() error {
return nil
}

func (cfg *Config) Initialize() error {
if cfg.LogFormat == "" {
cfg.LogFormat = enums.AnsiLogger
}
if err := cfg.LogFormat.Validate(); err != nil {
return err
}

return nil
}
122 changes: 122 additions & 0 deletions config/validators.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package config

import (
"fmt"
"time"

"github.com/robfig/cron/v3"
)

var cronParser = cron.NewParser(cron.SecondOptional)

func (cfg *Config) Validate() error {
if err := cfg.LogFormat.Validate(); err != nil {
return err
}
if err := cfg.LogLevel.Validate(); err != nil {
return err
}
for _, job := range cfg.Jobs {
if err := job.Validate(); err != nil {
return err
}
}
return nil
}

func (c *JobConfig) Validate() error {
if c.Enabled == false {
return nil
}
if c.Timeout < 0 {
return fmt.Errorf(
"timeout for jobs cannot be negative received `%s` for `%s`",
c.Timeout,
c.Name,
)
}

if c.RetryDelay < 0 {
return fmt.Errorf(
"retry delay for jobs cannot be negative received `%s` for `%s`",
c.RetryDelay,
c.Name,
)
}
for _, s := range c.Schedulers {
if err := s.Validate(); err != nil {
return err
}
}
for _, t := range c.Tasks {
if err := t.Validate(); err != nil {
return err
}
}
for _, t := range c.Hooks.Done {
if err := t.Validate(); err != nil {
return err
}
}
for _, t := range c.Hooks.Failed {
if err := t.Validate(); err != nil {
return err
}
}
return nil
}

func (c *Task) Validate() error {
actions := []bool{
c.Get != "",
c.Command != "",
c.Post != "",
}
activeActions := 0
for _, t := range actions {
if t {
activeActions++
}
}
if activeActions != 1 {
return fmt.Errorf(
"a single task should have one of (get,post,command) fields, received:(command: `%s`, get: `%s`, post: `%s`)",
c.Command,
c.Get,
c.Post,
)
}
return nil
}

func (s *JobScheduler) Validate() error {
if s.At != nil {
if s.At.Before(time.Now()) {
fmt.Println("you've set the time in the scheduler that is before now, received:", s.At, "Given time will be ignored")
}
} else if s.Interval < 0 {
return fmt.Errorf("received a negative time in interval: `%v`", s.Interval)
} else if _, err := cronParser.Parse(s.Cron); err != nil {
return err
}
schedules := []bool{
s.At != nil,
s.Interval != 0,
s.Cron != "",
}
activeSchedules := 0
for _, t := range schedules {
if t {
activeSchedules++
}
}
if activeSchedules != 1 {
return fmt.Errorf(
"a single scheduler must have one of (at,interval,cron) field, received:(cron: `%s`, interval: `%s`, at: `%s`)",
s.Cron,
s.Interval,
s.At,
)
}
return nil
}
15 changes: 14 additions & 1 deletion enums/log_level.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package enums

import "github.com/sirupsen/logrus"
import (
"fmt"

"github.com/sirupsen/logrus"
)

type LogLevel string

Expand All @@ -13,6 +17,15 @@ const (
PanicLevel = LogLevel("panic")
)

func (l LogLevel) Validate() error {
switch l {
case TraceLevel, DebugLevel, InfoLevel, WarnLevel, FatalLevel, PanicLevel:
return nil
default:
return fmt.Errorf("LogLevel must be one of (trace,debug,info,warn,fatal,panic) but received `%s`", l)
}
}

func (l LogLevel) ToLogrusLevel() (logrus.Level, error) {
return logrus.ParseLevel(string(l))
}

0 comments on commit 99a7275

Please sign in to comment.