The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/pkg/setting/expanders.go

149 lines
3.0 KiB

package setting
import (
"fmt"
"io/ioutil"
"os"
"regexp"
"sort"
"strings"
"gopkg.in/ini.v1"
)
type Expander interface {
SetupExpander(file *ini.File) error
Expand(string) (string, error)
}
type registeredExpander struct {
name string
priority int64
expander Expander
}
var expanders = []registeredExpander{
{
name: "env",
priority: -10,
expander: envExpander{},
},
{
name: "file",
priority: -5,
expander: fileExpander{},
},
}
func AddExpander(name string, priority int64, e Expander) {
expanders = append(expanders, registeredExpander{
name: name,
priority: priority,
expander: e,
})
}
var regex = regexp.MustCompile(`\$(|__\w+){([^}]+)}`)
func expandConfig(file *ini.File) error {
sort.Slice(expanders, func(i, j int) bool {
return expanders[i].priority < expanders[j].priority
})
for _, expander := range expanders {
err := expander.expander.SetupExpander(file)
if err != nil {
return fmt.Errorf("got error during initilazation of expander '%s': %w", expander.name, err)
}
for _, section := range file.Sections() {
for _, key := range section.Keys() {
updated, err := applyExpander(key.Value(), expander)
if err != nil {
return fmt.Errorf("got error while expanding %s.%s with expander '%s': %w",
section.Name(),
key.Name(),
expander.name,
err)
}
key.SetValue(updated)
}
}
}
return nil
}
func ExpandVar(s string) (string, error) {
for _, expander := range expanders {
var err error
s, err = applyExpander(s, expander)
if err != nil {
return "", fmt.Errorf("got error while expanding expander %s: %w", expander.name, err)
}
}
return s, nil
}
func applyExpander(s string, e registeredExpander) (string, error) {
matches := regex.FindAllStringSubmatch(s, -1)
for _, match := range matches {
if len(match) < 3 {
return "", fmt.Errorf("regex error, got %d results back for match, expected 3", len(match))
}
_, isEnv := e.expander.(envExpander)
if match[1] == "__"+e.name || (match[1] == "" && isEnv) {
updated, err := e.expander.Expand(match[2])
if err != nil {
return "", err
}
s = strings.Replace(s, match[0], updated, 1)
}
}
return s, nil
}
type envExpander struct {
}
func (e envExpander) SetupExpander(file *ini.File) error {
return nil
}
func (e envExpander) Expand(s string) (string, error) {
envValue := os.Getenv(s)
// if env variable is hostname and it is empty use os.Hostname as default
if s == "HOSTNAME" && envValue == "" {
return os.Hostname()
}
return os.Getenv(s), nil
}
type fileExpander struct {
}
func (e fileExpander) SetupExpander(file *ini.File) error {
return nil
}
func (e fileExpander) Expand(s string) (string, error) {
_, err := os.Stat(s)
if err != nil {
return "", err
}
// nolint:gosec
// We can ignore the gosec G304 warning on this one because `s` comes from configuration section keys
f, err := ioutil.ReadFile(s)
if err != nil {
return "", err
}
return strings.TrimSpace(string(f)), nil
}