mirror of
https://github.com/glanceapp/glance.git
synced 2025-02-22 05:10:54 +01:00
Allow inserting env variables anywhere in the config
This commit is contained in:
parent
8d2639b349
commit
dbcc13a5cf
@ -2,7 +2,6 @@ package glance
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -112,61 +111,6 @@ func (d *durationField) UnmarshalYAML(node *yaml.Node) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var optionalEnvFieldPattern = regexp.MustCompile(`(^|.)\$\{([A-Z0-9_]+)\}`)
|
||||
|
||||
type optionalEnvField string
|
||||
|
||||
func (f *optionalEnvField) UnmarshalYAML(node *yaml.Node) error {
|
||||
var value string
|
||||
|
||||
err := node.Decode(&value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
replaced := optionalEnvFieldPattern.ReplaceAllStringFunc(value, func(match string) string {
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
groups := optionalEnvFieldPattern.FindStringSubmatch(match)
|
||||
|
||||
if len(groups) != 3 {
|
||||
return match
|
||||
}
|
||||
|
||||
prefix, key := groups[1], groups[2]
|
||||
|
||||
if prefix == `\` {
|
||||
if len(match) >= 2 {
|
||||
return match[1:]
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
value, found := os.LookupEnv(key)
|
||||
if !found {
|
||||
err = fmt.Errorf("environment variable %s not found", key)
|
||||
return ""
|
||||
}
|
||||
|
||||
return prefix + value
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*f = optionalEnvField(replaced)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *optionalEnvField) String() string {
|
||||
return string(*f)
|
||||
}
|
||||
|
||||
type customIconField struct {
|
||||
URL string
|
||||
IsFlatIcon bool
|
||||
|
@ -69,10 +69,15 @@ type page struct {
|
||||
}
|
||||
|
||||
func newConfigFromYAML(contents []byte) (*config, error) {
|
||||
contents, err := parseConfigEnvVariables(contents)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config := &config{}
|
||||
config.Server.Port = 8080
|
||||
|
||||
err := yaml.Unmarshal(contents, config)
|
||||
err = yaml.Unmarshal(contents, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -94,6 +99,46 @@ func newConfigFromYAML(contents []byte) (*config, error) {
|
||||
return config, nil
|
||||
}
|
||||
|
||||
var configEnvVariablePattern = regexp.MustCompile(`(^|.)\$\{([A-Z0-9_]+)\}`)
|
||||
|
||||
func parseConfigEnvVariables(contents []byte) ([]byte, error) {
|
||||
var err error
|
||||
|
||||
replaced := configEnvVariablePattern.ReplaceAllFunc(contents, func(match []byte) []byte {
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
groups := configEnvVariablePattern.FindSubmatch(match)
|
||||
if len(groups) != 3 {
|
||||
return match
|
||||
}
|
||||
|
||||
prefix, key := string(groups[1]), string(groups[2])
|
||||
if prefix == `\` {
|
||||
if len(match) >= 2 {
|
||||
return match[1:]
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
value, found := os.LookupEnv(key)
|
||||
if !found {
|
||||
err = fmt.Errorf("environment variable %s not found", key)
|
||||
return nil
|
||||
}
|
||||
|
||||
return []byte(prefix + value)
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return replaced, nil
|
||||
}
|
||||
|
||||
func formatWidgetInitError(err error, w widget) error {
|
||||
return fmt.Errorf("%s widget: %v", w.GetType(), err)
|
||||
}
|
||||
|
@ -13,7 +13,7 @@
|
||||
<img class="bookmarks-icon{{ if .Icon.IsFlatIcon }} flat-icon{{ end }}" src="{{ .Icon.URL }}" alt="" loading="lazy">
|
||||
</div>
|
||||
{{ end }}
|
||||
<a href="{{ .URL.String | safeURL }}" class="bookmarks-link {{ if .HideArrow }}bookmarks-link-no-arrow {{ end }}color-highlight size-h4" {{ if not .SameTab }}target="_blank"{{ end }} rel="noreferrer">{{ .Title }}</a>
|
||||
<a href="{{ .URL | safeURL }}" class="bookmarks-link {{ if .HideArrow }}bookmarks-link-no-arrow {{ end }}color-highlight size-h4" {{ if not .SameTab }}target="_blank"{{ end }} rel="noreferrer">{{ .Title }}</a>
|
||||
</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
|
@ -21,7 +21,7 @@
|
||||
{{ end }}
|
||||
|
||||
{{ define "site" }}
|
||||
<a class="size-title-dynamic color-highlight text-truncate block grow" href="{{ .URL.String | safeURL }}" {{ if not .SameTab }}target="_blank"{{ end }} rel="noreferrer">{{ .Title }}</a>
|
||||
<a class="size-title-dynamic color-highlight text-truncate block grow" href="{{ .URL | safeURL }}" {{ if not .SameTab }}target="_blank"{{ end }} rel="noreferrer">{{ .Title }}</a>
|
||||
{{ if not .Status.TimedOut }}<div>{{ .Status.ResponseTime.Milliseconds | formatNumber }}ms</div>{{ end }}
|
||||
{{ if eq .StatusStyle "ok" }}
|
||||
<div class="monitor-site-status-icon-compact" title="{{ .Status.Code }}">
|
||||
|
@ -25,7 +25,7 @@
|
||||
<img class="monitor-site-icon{{ if .Icon.IsFlatIcon }} flat-icon{{ end }}" src="{{ .Icon.URL }}" alt="" loading="lazy">
|
||||
{{ end }}
|
||||
<div class="min-width-0">
|
||||
<a class="size-h3 color-highlight text-truncate block" href="{{ .URL.String | safeURL }}" {{ if not .SameTab }}target="_blank"{{ end }} rel="noreferrer">{{ .Title }}</a>
|
||||
<a class="size-h3 color-highlight text-truncate block" href="{{ .URL | safeURL }}" {{ if not .SameTab }}target="_blank"{{ end }} rel="noreferrer">{{ .Title }}</a>
|
||||
<ul class="list-horizontal-text">
|
||||
{{ if not .Status.Error }}
|
||||
<li title="{{ .Status.Code }}">{{ .StatusText }}</li>
|
||||
|
@ -13,11 +13,11 @@ type bookmarksWidget struct {
|
||||
Title string `yaml:"title"`
|
||||
Color *hslColorField `yaml:"color"`
|
||||
Links []struct {
|
||||
Title string `yaml:"title"`
|
||||
URL optionalEnvField `yaml:"url"`
|
||||
Icon customIconField `yaml:"icon"`
|
||||
SameTab bool `yaml:"same-tab"`
|
||||
HideArrow bool `yaml:"hide-arrow"`
|
||||
Title string `yaml:"title"`
|
||||
URL string `yaml:"url"`
|
||||
Icon customIconField `yaml:"icon"`
|
||||
SameTab bool `yaml:"same-tab"`
|
||||
HideArrow bool `yaml:"hide-arrow"`
|
||||
} `yaml:"links"`
|
||||
} `yaml:"groups"`
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ type changeDetectionWidget struct {
|
||||
ChangeDetections changeDetectionWatchList `yaml:"-"`
|
||||
WatchUUIDs []string `yaml:"watches"`
|
||||
InstanceURL string `yaml:"instance-url"`
|
||||
Token optionalEnvField `yaml:"token"`
|
||||
Token string `yaml:"token"`
|
||||
Limit int `yaml:"limit"`
|
||||
CollapseAfter int `yaml:"collapse-after"`
|
||||
}
|
||||
|
@ -18,13 +18,13 @@ var customAPIWidgetTemplate = mustParseTemplate("custom-api.html", "widget-base.
|
||||
|
||||
type customAPIWidget struct {
|
||||
widgetBase `yaml:",inline"`
|
||||
URL optionalEnvField `yaml:"url"`
|
||||
Template string `yaml:"template"`
|
||||
Frameless bool `yaml:"frameless"`
|
||||
Headers map[string]optionalEnvField `yaml:"headers"`
|
||||
APIRequest *http.Request `yaml:"-"`
|
||||
compiledTemplate *template.Template `yaml:"-"`
|
||||
CompiledHTML template.HTML `yaml:"-"`
|
||||
URL string `yaml:"url"`
|
||||
Template string `yaml:"template"`
|
||||
Frameless bool `yaml:"frameless"`
|
||||
Headers map[string]string `yaml:"headers"`
|
||||
APIRequest *http.Request `yaml:"-"`
|
||||
compiledTemplate *template.Template `yaml:"-"`
|
||||
CompiledHTML template.HTML `yaml:"-"`
|
||||
}
|
||||
|
||||
func (widget *customAPIWidget) initialize() error {
|
||||
@ -45,13 +45,13 @@ func (widget *customAPIWidget) initialize() error {
|
||||
|
||||
widget.compiledTemplate = compiledTemplate
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, widget.URL.String(), nil)
|
||||
req, err := http.NewRequest(http.MethodGet, widget.URL, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for key, value := range widget.Headers {
|
||||
req.Header.Add(key, value.String())
|
||||
req.Header.Add(key, value)
|
||||
}
|
||||
|
||||
widget.APIRequest = req
|
||||
|
@ -20,13 +20,13 @@ type dnsStatsWidget struct {
|
||||
TimeLabels [8]string `yaml:"-"`
|
||||
Stats *dnsStats `yaml:"-"`
|
||||
|
||||
HourFormat string `yaml:"hour-format"`
|
||||
Service string `yaml:"service"`
|
||||
AllowInsecure bool `yaml:"allow-insecure"`
|
||||
URL optionalEnvField `yaml:"url"`
|
||||
Token optionalEnvField `yaml:"token"`
|
||||
Username optionalEnvField `yaml:"username"`
|
||||
Password optionalEnvField `yaml:"password"`
|
||||
HourFormat string `yaml:"hour-format"`
|
||||
Service string `yaml:"service"`
|
||||
AllowInsecure bool `yaml:"allow-insecure"`
|
||||
URL string `yaml:"url"`
|
||||
Token string `yaml:"token"`
|
||||
Username string `yaml:"username"`
|
||||
Password string `yaml:"password"`
|
||||
}
|
||||
|
||||
func makeDNSWidgetTimeLabels(format string) [8]string {
|
||||
|
@ -109,9 +109,9 @@ func statusCodeToStyle(status int, altStatusCodes []int) string {
|
||||
}
|
||||
|
||||
type SiteStatusRequest struct {
|
||||
URL optionalEnvField `yaml:"url"`
|
||||
CheckURL optionalEnvField `yaml:"check-url"`
|
||||
AllowInsecure bool `yaml:"allow-insecure"`
|
||||
URL string `yaml:"url"`
|
||||
CheckURL string `yaml:"check-url"`
|
||||
AllowInsecure bool `yaml:"allow-insecure"`
|
||||
}
|
||||
|
||||
type siteStatus struct {
|
||||
@ -123,10 +123,10 @@ type siteStatus struct {
|
||||
|
||||
func fetchSiteStatusTask(statusRequest *SiteStatusRequest) (siteStatus, error) {
|
||||
var url string
|
||||
if statusRequest.CheckURL.String() != "" {
|
||||
url = statusRequest.CheckURL.String()
|
||||
if statusRequest.CheckURL != "" {
|
||||
url = statusRequest.CheckURL
|
||||
} else {
|
||||
url = statusRequest.URL.String()
|
||||
url = statusRequest.URL
|
||||
}
|
||||
request, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
|
@ -20,8 +20,8 @@ type releasesWidget struct {
|
||||
Releases appReleaseList `yaml:"-"`
|
||||
releaseRequests []*releaseRequest `yaml:"-"`
|
||||
Repositories []string `yaml:"repositories"`
|
||||
Token optionalEnvField `yaml:"token"`
|
||||
GitLabToken optionalEnvField `yaml:"gitlab-token"`
|
||||
Token string `yaml:"token"`
|
||||
GitLabToken string `yaml:"gitlab-token"`
|
||||
Limit int `yaml:"limit"`
|
||||
CollapseAfter int `yaml:"collapse-after"`
|
||||
ShowSourceIcon bool `yaml:"show-source-icon"`
|
||||
@ -38,8 +38,8 @@ func (widget *releasesWidget) initialize() error {
|
||||
widget.CollapseAfter = 5
|
||||
}
|
||||
|
||||
var tokenAsString = widget.Token.String()
|
||||
var gitLabTokenAsString = widget.GitLabToken.String()
|
||||
var tokenAsString = widget.Token
|
||||
var gitLabTokenAsString = widget.GitLabToken
|
||||
|
||||
for _, repository := range widget.Repositories {
|
||||
parts := strings.SplitN(repository, ":", 2)
|
||||
|
@ -14,12 +14,12 @@ var repositoryWidgetTemplate = mustParseTemplate("repository.html", "widget-base
|
||||
|
||||
type repositoryWidget struct {
|
||||
widgetBase `yaml:",inline"`
|
||||
RequestedRepository string `yaml:"repository"`
|
||||
Token optionalEnvField `yaml:"token"`
|
||||
PullRequestsLimit int `yaml:"pull-requests-limit"`
|
||||
IssuesLimit int `yaml:"issues-limit"`
|
||||
CommitsLimit int `yaml:"commits-limit"`
|
||||
Repository repository `yaml:"-"`
|
||||
RequestedRepository string `yaml:"repository"`
|
||||
Token string `yaml:"token"`
|
||||
PullRequestsLimit int `yaml:"pull-requests-limit"`
|
||||
IssuesLimit int `yaml:"issues-limit"`
|
||||
CommitsLimit int `yaml:"commits-limit"`
|
||||
Repository repository `yaml:"-"`
|
||||
}
|
||||
|
||||
func (widget *repositoryWidget) initialize() error {
|
||||
|
@ -139,7 +139,7 @@ func shortenFeedDescriptionLen(description string, maxLen int) string {
|
||||
}
|
||||
|
||||
type rssFeedRequest struct {
|
||||
URL optionalEnvField `yaml:"url"`
|
||||
URL string `yaml:"url"`
|
||||
Title string `yaml:"title"`
|
||||
HideCategories bool `yaml:"hide-categories"`
|
||||
HideDescription bool `yaml:"hide-description"`
|
||||
@ -161,7 +161,7 @@ func (f rssFeedItemList) sortByNewest() rssFeedItemList {
|
||||
var feedParser = gofeed.NewParser()
|
||||
|
||||
func fetchItemsFromRSSFeedTask(request rssFeedRequest) ([]rssFeedItem, error) {
|
||||
req, err := http.NewRequest("GET", request.URL.String(), nil)
|
||||
req, err := http.NewRequest("GET", request.URL, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -206,7 +206,7 @@ func fetchItemsFromRSSFeedTask(request rssFeedRequest) ([]rssFeedItem, error) {
|
||||
} else {
|
||||
parsedUrl, err := url.Parse(feed.Link)
|
||||
if err != nil {
|
||||
parsedUrl, err = url.Parse(request.URL.String())
|
||||
parsedUrl, err = url.Parse(request.URL)
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
|
Loading…
Reference in New Issue
Block a user