Vasiliy Tolstov c1103c714a allow to work with multiple configs
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2024-11-20 00:35:04 +03:00

163 lines
5.2 KiB
Go

package config
import (
"fmt"
"io"
"io/fs"
"os"
"path/filepath"
"github.com/google/uuid"
yamlcodec "go.unistack.org/micro-codec-yaml/v3"
mtime "go.unistack.org/micro/v3/util/time"
)
var Filesytem fs.FS
func init() {
dir, _ := os.Getwd()
Filesytem = os.DirFS(dir)
}
type Config struct {
App *AppConfig `json:"app,omitempty" yaml:"app,omitempty"`
Meter *MeterConfig `json:"meter,omitempty" yaml:"meter,omitempty"`
}
type AppConfig struct {
ChecksFiles []string `json:"checks_files,omitempty" yaml:"checks_files,omitempty"`
Checks []*CheckConfig `json:"checks,omitempty" yaml:"checks,omitempty"`
MultiUser bool `json:"multi_user,omitempty" yaml:"multi_user,omitempty"`
}
type MeterConfig struct {
Addr string `json:"addr,omitempty" yaml:"addr,omitempty"`
Path string `json:"path,omitempty" yaml:"path,omitempty"`
}
type CheckConfig struct {
Name string `json:"name,omitempty" yaml:"name,omitempty"`
User string `json:"user,omitempty" yaml:"user,omitempty"`
Tasks []*TaskConfig `json:"tasks,omitempty" yaml:"tasks,omitempty"`
TasksFiles []string `json:"tasks_files,omitempty" yaml:"tasks_files,omitempty"`
Timeout mtime.Duration `json:"timeout,omitempty" yaml:"timeout,omitempty"`
Interval mtime.Duration `json:"interval,omitempty" yaml:"interval,omitempty"`
Active bool `json:"active,omitempty" yaml:"active,omitempty"`
}
type HTTPConfig struct {
Metadata map[string]string `json:"metadata,omitempty" yaml:"metadata,omitempty"`
Endpoint string `json:"endpoint,omitempty" yaml:"endpoint,omitempty"`
Data string `json:"data,omitempty" yaml:"data,omitempty"`
Addr string `json:"addr,omitempty" yaml:"addr,omitempty"`
OpenAPI string `json:"openapi,omitempty" yaml:"openapi,omitempty"`
Method string `json:"method,omitempty" yaml:"method,omitempty"`
}
type GRPCConfig struct {
Metadata map[string]string `json:"metadata,omitempty" yaml:"metadata,omitempty"`
Endpoint string `json:"endpoint,omitempty" yaml:"endpoint,omitempty"`
Data string `json:"data,omitempty" yaml:"data,omitempty"`
Addr string `json:"addr,omitempty" yaml:"addr,omitempty"`
Protoset string `json:"protoset,omitempty" yaml:"protoset,omitempty"`
}
type GraphQLConfig struct {
Metadata map[string]string `json:"metadata,omitempty" yaml:"metadata,omitempty"`
Endpoint string `json:"endpoint,omitempty" yaml:"endpoint,omitempty"`
Data string `json:"data,omitempty" yaml:"data,omitempty"`
Addr string `json:"addr,omitempty" yaml:"addr,omitempty"`
}
type TaskConfig struct {
HTTP *HTTPConfig `json:"http,omitempty" yaml:"http,omitempty"`
GRPC *GRPCConfig `json:"grpc,omitempty" yaml:"grpc,omitempty"`
GraphQL *GraphQLConfig `json:"graphql,omitempty" yaml:"graphql"`
TLSVerify *bool `json:"tls_verify,omitempty" yaml:"tls_verify,omitempty"`
Name string `json:"name,omitempty" yaml:"name,omitempty"`
Timeout mtime.Duration `json:"timeout,omitempty" yaml:"timeout,omitempty"`
Active bool `json:"active,omitempty" yaml:"active,omitempty"`
}
func Load(fileSystem fs.FS, name string, cfg *Config) error {
if err := load(fileSystem, name, cfg); err != nil {
return err
}
for _, checksPatternFile := range cfg.App.ChecksFiles {
checkRoot := filepath.Dir(checksPatternFile)
checksFiles := fsWalkDir(fileSystem, checkRoot, checksPatternFile)
for _, checkFile := range checksFiles {
checks := []*CheckConfig{}
if err := load(fileSystem, checkFile, &checks); err != nil {
return err
}
for ckecksIdx := range checks {
for _, tasksPatternFile := range checks[ckecksIdx].TasksFiles {
taskRoot := filepath.Join(filepath.Dir(checksPatternFile), filepath.Dir(tasksPatternFile))
tasksFiles := fsWalkDir(fileSystem, taskRoot, filepath.Join(filepath.Dir(checksPatternFile), tasksPatternFile))
for tasksIdx := range tasksFiles {
tasks := []*TaskConfig{}
if err := load(fileSystem, tasksFiles[tasksIdx], &tasks); err != nil {
return err
}
checks[ckecksIdx].Tasks = append(checks[ckecksIdx].Tasks, tasks...)
}
}
cfg.App.Checks = append(cfg.App.Checks, checks[ckecksIdx])
}
}
}
if !cfg.App.MultiUser {
for _, check := range cfg.App.Checks {
check.User = uuid.Nil.String()
}
}
return nil
}
func fsWalkDir(fileSystem fs.FS, root string, pattern string) []string {
var files []string
fs.WalkDir(fileSystem, root, func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
if d.IsDir() || !d.Type().IsRegular() {
return nil
}
var ok bool
if ok, err = filepath.Match(pattern, path); err == nil && ok {
files = append(files, path)
} else {
return err
}
return nil
})
return files
}
func load(fileSystem fs.FS, name string, cfg interface{}) error {
f, err := fileSystem.Open(name)
if err != nil {
return err
}
c := yamlcodec.NewCodec()
var buf []byte
if buf, err = io.ReadAll(f); err == nil {
if err = f.Close(); err == nil {
err = c.Unmarshal(buf, cfg)
}
}
if err != nil {
return fmt.Errorf("failed to load config %w", err)
}
return nil
}