master
go 123 lines 2.92 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package secretstore
4
5 import (
6 "fmt"
7 "os"
8 "path/filepath"
9 "strings"
10
11 "github.com/netdata/netdata/go/plugins/pkg/pluginconfig"
12 "github.com/netdata/netdata/go/plugins/plugin/framework/confgroup"
13 "gopkg.in/yaml.v2"
14 )
15
16 type fileRootConfig struct {
17 Jobs []map[string]any `yaml:"jobs"`
18 }
19
20 func LoadFileConfigs(roots []string) ([]Config, []error) {
21 var cfgs []Config
22 var errs []error
23
24 for _, root := range roots {
25 root = strings.TrimSpace(root)
26 if root == "" {
27 continue
28 }
29
30 dir := filepath.Join(root, "ss")
31 entries, err := os.ReadDir(dir)
32 if err != nil {
33 continue
34 }
35
36 for _, entry := range entries {
37 if !entry.Type().IsRegular() {
38 continue
39 }
40
41 ext := strings.ToLower(filepath.Ext(entry.Name()))
42 if ext != ".conf" && ext != ".yaml" && ext != ".yml" {
43 continue
44 }
45
46 path := filepath.Join(dir, entry.Name())
47 stem := strings.TrimSpace(strings.TrimSuffix(entry.Name(), filepath.Ext(entry.Name())))
48
49 jobs, jobErrs := loadFileConfigJobs(path)
50 errs = append(errs, jobErrs...)
51 if len(jobs) == 0 {
52 continue
53 }
54
55 sourceType := fileConfigSourceType(path)
56 source := "file=" + path
57 for i, job := range jobs {
58 cfg := Config(job)
59 if strings.TrimSpace(cfg.Name()) == "" {
60 errs = append(errs, fmt.Errorf("secretstore file config '%s' job %d: store name is required", path, i+1))
61 continue
62 }
63 if cfg.Kind() == "" {
64 cfg.SetKind(StoreKind(stem))
65 }
66 cfg.SetSource(source)
67 cfg.SetSourceType(sourceType)
68 if err := validateFileConfig(cfg); err != nil {
69 errs = append(errs, fmt.Errorf("secretstore file config '%s' job %d: %w", path, i+1, err))
70 continue
71 }
72 cfgs = append(cfgs, cfg)
73 }
74 }
75 }
76
77 return cfgs, errs
78 }
79
80 func loadFileConfigJobs(path string) ([]map[string]any, []error) {
81 data, err := os.ReadFile(path)
82 if err != nil {
83 return nil, []error{fmt.Errorf("secretstore file config '%s': %w", path, err)}
84 }
85
86 var root fileRootConfig
87 if err := yaml.Unmarshal(data, &root); err != nil {
88 return nil, []error{fmt.Errorf("secretstore file config '%s': %w", path, err)}
89 }
90
91 return root.Jobs, nil
92 }
93
94 func fileConfigSourceType(path string) string {
95 if pluginconfig.IsStock(path) {
96 return confgroup.TypeStock
97 }
98 return confgroup.TypeUser
99 }
100
101 func validateFileConfig(cfg Config) error {
102 if cfg == nil {
103 return fmt.Errorf("store config is nil")
104 }
105 if strings.TrimSpace(cfg.Name()) == "" {
106 return fmt.Errorf("store name is required")
107 }
108 if err := validateStoreName(cfg.Name()); err != nil {
109 return fmt.Errorf("invalid store name '%s': %w", cfg.Name(), err)
110 }
111 if strings.TrimSpace(string(cfg.Kind())) == "" {
112 return fmt.Errorf("store kind is required")
113 }
114 if strings.TrimSpace(cfg.Source()) == "" {
115 return fmt.Errorf("store source is required")
116 }
117 switch cfg.SourceType() {
118 case confgroup.TypeUser, confgroup.TypeStock:
119 return nil
120 default:
121 return fmt.Errorf("invalid store source type '%s'", cfg.SourceType())
122 }
123 }