mirror of
https://github.com/crazy-max/diun.git
synced 2026-01-01 02:27:26 +01:00
Configuration transposed into environment variables (#82)
Configuration file not required anymore DIUN_DB env var renamed DIUN_DB_PATH Only accept duration as timeout value (10 becomes 10s) Add getting started doc Enhanced documentation Add note about test notifications (#79) Improve configuration management Fix telegram init All fields in configuration now camelCased Improve configuration validation Update doc Update FAQ Co-authored-by: CrazyMax <crazy-max@users.noreply.github.com>
This commit is contained in:
@@ -3,92 +3,91 @@ package config
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/crazy-max/diun/v3/internal/model"
|
||||
"github.com/crazy-max/diun/v3/pkg/utl"
|
||||
"github.com/crazy-max/diun/v3/third_party/traefik/config/env"
|
||||
"github.com/crazy-max/diun/v3/third_party/traefik/config/file"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/pkg/errors"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
// Config holds configuration details
|
||||
type Config struct {
|
||||
Cli model.Cli
|
||||
App model.App
|
||||
Db model.Db `yaml:"db,omitempty"`
|
||||
Watch model.Watch `yaml:"watch,omitempty"`
|
||||
Notif *model.Notif `yaml:"notif,omitempty"`
|
||||
RegOpts map[string]model.RegOpts `yaml:"regopts,omitempty"`
|
||||
Providers *model.Providers `yaml:"providers,omitempty"`
|
||||
Db *model.Db `yaml:"db,omitempty" json:"db,omitempty"`
|
||||
Watch *model.Watch `yaml:"watch,omitempty" json:"watch,omitempty"`
|
||||
Notif *model.Notif `yaml:"notif,omitempty" json:"notif,omitempty"`
|
||||
RegOpts map[string]*model.RegOpts `yaml:"regopts,omitempty" json:"regopts,omitempty" validate:"unique"`
|
||||
Providers *model.Providers `yaml:"providers,omitempty" json:"providers,omitempty" validate:"required"`
|
||||
}
|
||||
|
||||
// Load returns Configuration struct
|
||||
func Load(cli model.Cli, version string) (*Config, error) {
|
||||
var err error
|
||||
var cfg = Config{
|
||||
Cli: cli,
|
||||
App: model.App{
|
||||
ID: "diun",
|
||||
Name: "Diun",
|
||||
Desc: "Docker image update notifier",
|
||||
URL: "https://github.com/crazy-max/diun",
|
||||
Author: "CrazyMax",
|
||||
Version: version,
|
||||
},
|
||||
Db: model.Db{
|
||||
Path: "diun.db",
|
||||
},
|
||||
Watch: model.Watch{
|
||||
Workers: 10,
|
||||
Schedule: "0 * * * *",
|
||||
FirstCheckNotif: utl.NewFalse(),
|
||||
},
|
||||
func Load(cfgfile string) (*Config, error) {
|
||||
cfg := Config{
|
||||
Db: (&model.Db{}).GetDefaults(),
|
||||
Watch: (&model.Watch{}).GetDefaults(),
|
||||
}
|
||||
|
||||
if _, err = os.Lstat(cli.Cfgfile); err != nil {
|
||||
return nil, fmt.Errorf("unable to open config file, %s", err)
|
||||
if err := cfg.loadFile(cfgfile, &cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bytes, err := ioutil.ReadFile(cli.Cfgfile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to read config file, %s", err)
|
||||
if err := cfg.loadEnv(&cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := yaml.UnmarshalStrict(bytes, &cfg); err != nil {
|
||||
return nil, fmt.Errorf("unable to decode into struct, %v", err)
|
||||
}
|
||||
|
||||
if err := cfg.validate(); err != nil {
|
||||
validate := validator.New()
|
||||
if err := validate.Struct(&cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &cfg, nil
|
||||
}
|
||||
|
||||
func (cfg *Config) validate() error {
|
||||
cfg.Db.Path = utl.GetEnv("DIUN_DB", cfg.Db.Path)
|
||||
if cfg.Db.Path == "" {
|
||||
return errors.New("database path is required")
|
||||
func (cfg *Config) loadFile(cfgfile string, out interface{}) error {
|
||||
if len(cfgfile) == 0 {
|
||||
return nil
|
||||
}
|
||||
cfg.Db.Path = path.Clean(cfg.Db.Path)
|
||||
|
||||
if err := cfg.validateNotif(); err != nil {
|
||||
return err
|
||||
if _, err := os.Lstat(cfgfile); os.IsNotExist(err) {
|
||||
return fmt.Errorf("config file %s not found", cfgfile)
|
||||
}
|
||||
if err := cfg.validateRegopts(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cfg.validateProviders(); err != nil {
|
||||
return err
|
||||
|
||||
if err := file.Decode(cfgfile, out); err != nil {
|
||||
return errors.Wrap(err, "failed to decode configuration from file")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Display configuration in a pretty JSON format
|
||||
func (cfg *Config) Display() string {
|
||||
func (cfg *Config) loadEnv(out interface{}) error {
|
||||
var envvars []string
|
||||
for _, envvar := range env.FindPrefixedEnvVars(os.Environ(), "DIUN_", out) {
|
||||
envvars = append(envvars, envvar)
|
||||
}
|
||||
if len(envvars) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := env.Decode(envvars, "DIUN_", out); err != nil {
|
||||
return errors.Wrap(err, "failed to decode configuration from environment variables")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cfg *Config) GetRegOpts(id string) (*model.RegOpts, error) {
|
||||
if len(id) == 0 {
|
||||
return (&model.RegOpts{}).GetDefaults(), nil
|
||||
}
|
||||
if regopts, ok := cfg.RegOpts[id]; ok {
|
||||
return regopts, nil
|
||||
}
|
||||
return (&model.RegOpts{}).GetDefaults(), fmt.Errorf("%s not found", id)
|
||||
}
|
||||
|
||||
// String returns the string representation of configuration
|
||||
func (cfg *Config) String() string {
|
||||
b, _ := json.MarshalIndent(cfg, "", " ")
|
||||
return string(b)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user