first version

This commit is contained in:
2026-02-08 22:29:45 +01:00
commit d1e54774a7
15 changed files with 1355 additions and 0 deletions

125
config/config.go Normal file
View File

@@ -0,0 +1,125 @@
package config
import (
"encoding/json"
"fmt"
"log/slog"
"os"
"github.com/robfig/cron/v3"
)
type (
Configuration struct {
GlobalContainerConfiguration ContainerConfiguration `json:"containers"`
DaemonConfiguration DaemonConfiguration `json:"daemon"`
IgnoreRunningUnspecifiedContainers bool `json:"ignore_running_unspecified_containers"`
StrictValidation bool `json:"strict_validation"`
}
DaemonConfiguration struct {
PullInterval uint `json:"pull_interval"`
}
ContainerConfiguration struct {
Enabled bool `json:"enabled"`
Schedule string `json:"schedule"`
}
)
func Load(configPath string) (Configuration, error) {
file, err := os.OpenFile(configPath, os.O_RDONLY, 0)
if err != nil {
slog.Warn("no configuration found, loading the default one", "thread", "main", "path", configPath)
return Default(), nil
}
defer file.Close()
var c map[string]any
d := json.NewDecoder(file)
if err := d.Decode(&c); err != nil {
return Configuration{}, fmt.Errorf("unable to parse the configuration file: %s", err)
}
return parseConfiguration(c)
}
func Default() Configuration {
return Configuration{
GlobalContainerConfiguration: ContainerConfiguration{
Enabled: false,
Schedule: "* * * * *",
},
DaemonConfiguration: DaemonConfiguration{
PullInterval: 2,
},
IgnoreRunningUnspecifiedContainers: true,
StrictValidation: false,
}
}
func parseConfiguration(currentConfig map[string]any) (Configuration, error) {
c := Default()
if defaultContainerConfiguration, ok := currentConfig["containers"]; ok {
if defaultContainerData, ok := defaultContainerConfiguration.(map[string]any); ok {
if schedule, ok := defaultContainerData["schedule"]; ok {
if data, ok := schedule.(string); ok {
c.GlobalContainerConfiguration.Schedule = data
} else {
return Configuration{}, fmt.Errorf("configuration parsing: invalid containers.schedule value, expected a string")
}
}
if enabled, ok := defaultContainerData["enabled"]; ok {
if data, ok := enabled.(bool); ok {
c.GlobalContainerConfiguration.Enabled = data
} else {
return Configuration{}, fmt.Errorf("configuration parsing: invalid containers.enabled value, expected a bool")
}
}
} else {
return Configuration{}, fmt.Errorf("configuration parsing: invalid containers section, expected an object")
}
}
if daemonConfiguration, ok := currentConfig["daemon"]; ok {
if daemonData, ok := daemonConfiguration.(map[string]any); ok {
if pullInterval, ok := daemonData["pull_interval"]; ok {
if data, ok := pullInterval.(uint); ok {
c.DaemonConfiguration.PullInterval = data
}
} else {
return Configuration{}, fmt.Errorf("configuration parsing: invalid daemon.pull_interval value, expected an unsigned integer")
}
} else {
return Configuration{}, fmt.Errorf("configuration parsing: invalid daemon section, expected an object")
}
}
if ignoreRunningUnspecifiedContainers, ok := currentConfig["ignore_running_unspecified_containers"]; ok {
if data, ok := ignoreRunningUnspecifiedContainers.(bool); ok {
c.IgnoreRunningUnspecifiedContainers = data
} else {
return Configuration{}, fmt.Errorf("configuration parsing: invalid ignore_running_unspecified_containers value, expected a bool")
}
}
if strictValidation, ok := currentConfig["strict_validation"]; ok {
if data, ok := strictValidation.(bool); ok {
c.StrictValidation = data
} else {
return Configuration{}, fmt.Errorf("configuration parsing: invalid strict_validation value, expected a bool")
}
}
return c, nil
}
func (c Configuration) Validate() error {
_, err := cron.ParseStandard(c.GlobalContainerConfiguration.Schedule)
if err != nil {
return fmt.Errorf("failed to validate: invalid schedule: %s", err)
}
return nil
}