Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aos
GitHub Repository: aos/grafana-agent
Path: blob/main/pkg/agentctl/sync.go
4094 views
1
package agentctl
2
3
import (
4
"context"
5
"errors"
6
"fmt"
7
"os"
8
"path/filepath"
9
"strings"
10
11
"github.com/go-kit/log"
12
"github.com/go-kit/log/level"
13
"github.com/grafana/agent/pkg/client"
14
"github.com/grafana/agent/pkg/metrics/instance"
15
)
16
17
// ConfigSync loads YAML files from a directory and syncs them to the
18
// provided PrometheusClient API. All YAML files will be synced and
19
// must be valid.
20
//
21
// The base name of the YAML file (i.e., without the file extension)
22
// is used as the config name.
23
//
24
// ConfigSync will completely overwrite the set of active configs
25
// present in the provided PrometheusClient - configs present in the
26
// API but not in the directory will be deleted.
27
func ConfigSync(logger log.Logger, cli client.PrometheusClient, dir string, dryRun bool) error {
28
if logger == nil {
29
logger = log.NewNopLogger()
30
}
31
32
ctx := context.Background()
33
cfgs, err := ConfigsFromDirectory(dir)
34
if err != nil {
35
return err
36
}
37
38
if dryRun {
39
level.Info(logger).Log("msg", "config files validated successfully")
40
return nil
41
}
42
43
uploaded := make(map[string]struct{}, len(cfgs))
44
var hadErrors bool
45
46
for _, cfg := range cfgs {
47
level.Info(logger).Log("msg", "uploading config", "name", cfg.Name)
48
err := cli.PutConfiguration(ctx, cfg.Name, cfg)
49
if err != nil {
50
level.Error(logger).Log("msg", "failed to upload config", "name", cfg.Name, "err", err)
51
hadErrors = true
52
}
53
uploaded[cfg.Name] = struct{}{}
54
}
55
56
existing, err := cli.ListConfigs(ctx)
57
if err != nil {
58
return fmt.Errorf("could not list configs: %w", err)
59
}
60
61
// Delete configs from the existing API list that we didn't upload.
62
for _, existing := range existing.Configs {
63
if _, existsLocally := uploaded[existing]; !existsLocally {
64
level.Info(logger).Log("msg", "deleting config", "name", existing)
65
err := cli.DeleteConfiguration(ctx, existing)
66
if err != nil {
67
level.Error(logger).Log("msg", "failed to delete outdated config", "name", existing, "err", err)
68
hadErrors = true
69
}
70
}
71
}
72
73
if hadErrors {
74
return errors.New("one or more configurations failed to be modified; check the logs for more details")
75
}
76
77
return nil
78
}
79
80
// ConfigsFromDirectory parses all YAML files from a directory and
81
// loads each as an instance.Config.
82
func ConfigsFromDirectory(dir string) ([]*instance.Config, error) {
83
var files []string
84
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
85
if err != nil {
86
return err
87
}
88
if info.IsDir() {
89
if dir == path {
90
return nil
91
}
92
return filepath.SkipDir
93
}
94
95
if strings.HasSuffix(path, ".yaml") || strings.HasSuffix(path, ".yml") {
96
files = append(files, path)
97
}
98
return nil
99
})
100
if err != nil {
101
return nil, err
102
}
103
104
var configs []*instance.Config
105
for _, file := range files {
106
cfg, err := configFromFile(file)
107
if err != nil {
108
return nil, err
109
}
110
configs = append(configs, cfg)
111
}
112
113
return configs, nil
114
}
115
116
func configFromFile(path string) (*instance.Config, error) {
117
var (
118
fileName = filepath.Base(path)
119
configName = strings.TrimSuffix(fileName, filepath.Ext(fileName))
120
)
121
122
f, err := os.Open(path)
123
if f != nil {
124
defer f.Close()
125
}
126
if err != nil {
127
return nil, err
128
}
129
130
cfg, err := instance.UnmarshalConfig(f)
131
if err != nil {
132
return nil, err
133
}
134
cfg.Name = configName
135
return cfg, nil
136
}
137
138