grafana/pkg/setting/expanders.go
Daniel Lee 33a32df47b
imagestorage: fix templating of public_url option for webdav (#74885)
* spelling in error message

* imguploader: fix template for webdav url

Since a few years ago, when loading the config file, the  template gets replaced in the expanding
env var phase (see ##25075) and introduced a bug in the webdav public_url config option. This commit
changes the template syntax to be {{file}}. This doesn't get expanded and removed when the config file
is loaded.

* devenv: add a block for a WebDAV server

* Adding alerting as codeowners for webdav

---------

Co-authored-by: Timur Olzhabayev <timur.olzhabayev@grafana.com>
2023-09-28 00:35:10 +03:00

154 lines
3.2 KiB
Go

package setting
import (
"fmt"
"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+){([^}]+)}`)
// Slightly hacky function to avoid code duplication. If this is eventually called in multiple places, consider refactoring or potentially adding more general helper functions to this package
func GetExpanderRegex() *regexp.Regexp {
return regex
}
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 initialization 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 := os.ReadFile(s)
if err != nil {
return "", err
}
return strings.TrimSpace(string(f)), nil
}