2014-10-05 09:50:04 -05:00
// Copyright 2014 Unknwon
// Copyright 2014 Torkel Ödegaard
2014-10-04 06:33:20 -05:00
package setting
import (
2015-04-09 05:16:59 -05:00
"bytes"
2022-09-26 15:25:34 -05:00
"crypto/tls"
2021-07-21 10:54:05 -05:00
"encoding/json"
2020-10-13 05:30:09 -05:00
"errors"
2015-02-12 06:31:41 -06:00
"fmt"
2022-09-26 15:25:34 -05:00
"io/fs"
2019-02-01 04:47:21 -06:00
"net/http"
2014-10-04 06:33:20 -05:00
"net/url"
"os"
"path"
"path/filepath"
2021-11-30 04:28:52 -06:00
"regexp"
2021-03-19 04:14:49 -05:00
"runtime"
2021-03-12 07:30:21 -06:00
"strconv"
2014-10-04 06:33:20 -05:00
"strings"
2018-07-02 06:33:39 -05:00
"time"
2021-03-12 07:30:21 -06:00
"github.com/grafana/grafana-aws-sdk/pkg/awsds"
2022-04-04 04:23:13 -05:00
"github.com/grafana/grafana-azure-sdk-go/azsettings"
2021-09-21 06:08:52 -05:00
"github.com/grafana/grafana-plugin-sdk-go/backend/gtime"
2021-11-24 13:56:07 -06:00
2019-05-13 01:45:54 -05:00
"github.com/grafana/grafana/pkg/infra/log"
2015-04-19 02:14:50 -05:00
"github.com/grafana/grafana/pkg/util"
2021-09-16 09:33:51 -05:00
"github.com/gobwas/glob"
"github.com/prometheus/common/model"
"gopkg.in/ini.v1"
2014-10-04 06:33:20 -05:00
)
type Scheme string
const (
2020-10-02 08:45:45 -05:00
HTTPScheme Scheme = "http"
HTTPSScheme Scheme = "https"
HTTP2Scheme Scheme = "h2"
SocketScheme Scheme = "socket"
2014-10-04 06:33:20 -05:00
)
2014-12-16 05:04:08 -06:00
const (
2021-05-10 10:03:10 -05:00
RedactedPassword = "*********"
2020-10-02 08:45:45 -05:00
DefaultHTTPAddr = "0.0.0.0"
Dev = "development"
Prod = "production"
Test = "test"
2021-08-25 08:11:22 -05:00
ApplicationName = "Grafana"
2014-12-16 05:04:08 -06:00
)
2021-03-19 04:14:49 -05:00
// zoneInfo names environment variable for setting the path to look for the timezone database in go
const zoneInfo = "ZONEINFO"
2014-10-04 06:33:20 -05:00
var (
// App settings.
2020-10-02 08:45:45 -05:00
Env = Dev
2019-05-27 10:47:29 -05:00
AppUrl string
AppSubUrl string
ServeFromSubPath bool
InstanceName string
2014-10-04 06:33:20 -05:00
2015-01-05 03:46:58 -06:00
// build
2021-08-25 08:11:22 -05:00
BuildVersion string
BuildCommit string
BuildBranch string
BuildStamp int64
IsEnterprise bool
2015-01-05 03:46:58 -06:00
2018-11-15 07:42:09 -06:00
// packaging
Packaging = "unknown"
2015-04-09 05:16:59 -05:00
// Paths
2018-05-01 08:51:15 -05:00
HomePath string
CustomInitPath = "conf/custom.ini"
2015-04-09 05:16:59 -05:00
2020-11-13 02:52:38 -06:00
// HTTP server options
2021-07-15 07:30:06 -05:00
StaticRootPath string
2014-10-05 09:50:04 -05:00
2015-01-27 03:09:54 -06:00
// Security settings.
2020-12-11 04:44:44 -06:00
SecretKey string
DisableGravatar bool
DataProxyWhiteList map [ string ] bool
CookieSecure bool
CookieSameSiteDisabled bool
CookieSameSiteMode http . SameSite
2015-01-27 03:09:54 -06:00
2015-10-14 09:39:57 -05:00
// Snapshots
2016-09-23 09:56:12 -05:00
ExternalSnapshotUrl string
ExternalSnapshotName string
ExternalEnabled bool
SnapShotRemoveExpired bool
2015-10-14 09:39:57 -05:00
2017-11-14 04:34:27 -06:00
// Dashboard history
DashboardVersionsToKeep int
2020-02-28 07:32:01 -06:00
MinRefreshInterval string
2017-11-14 04:34:27 -06:00
2015-03-11 10:19:29 -05:00
// User settings
2017-07-31 07:39:33 -05:00
AllowUserSignUp bool
AllowUserOrgCreate bool
AutoAssignOrg bool
2018-07-13 14:14:40 -05:00
AutoAssignOrgId int
2017-07-31 07:39:33 -05:00
AutoAssignOrgRole string
VerifyEmailEnabled bool
LoginHint string
2019-03-07 16:00:04 -06:00
PasswordHint string
2017-07-31 07:39:33 -05:00
DisableLoginForm bool
DisableSignoutMenu bool
2018-05-27 07:52:50 -05:00
SignoutRedirectUrl string
2017-07-31 07:39:33 -05:00
ExternalUserMngLinkUrl string
ExternalUserMngLinkName string
ExternalUserMngInfo string
2018-05-28 09:16:48 -05:00
OAuthAutoLogin bool
2017-12-13 11:53:42 -06:00
ViewersCanEdit bool
2015-01-27 08:14:53 -06:00
2020-12-11 04:44:44 -06:00
// HTTP auth
2020-10-08 03:03:20 -05:00
SigV4AuthEnabled bool
2022-08-11 09:12:57 -05:00
AzureAuthEnabled bool
2015-01-27 08:45:27 -06:00
2015-02-23 13:07:49 -06:00
AnonymousEnabled bool
2015-01-07 09:37:24 -06:00
2015-05-01 04:55:59 -05:00
// Auth proxy settings
2020-12-11 04:44:44 -06:00
AuthProxyEnabled bool
AuthProxyHeaderProperty string
2015-05-01 04:55:59 -05:00
2015-06-30 02:37:52 -05:00
// Basic Auth
BasicAuthEnabled bool
2014-10-04 06:33:20 -05:00
// Global setting objects.
2020-11-17 04:51:31 -06:00
Raw * ini . File
2014-10-06 14:31:54 -05:00
2015-04-09 05:16:59 -05:00
// for logging purposes
configFiles [ ] string
appliedCommandLineProperties [ ] string
appliedEnvOverrides [ ] string
2015-03-22 14:14:00 -05:00
2021-02-10 03:07:32 -06:00
// analytics
2022-11-09 08:09:19 -06:00
GoogleAnalyticsId string
GoogleAnalytics4Id string
GoogleAnalytics4SendManualPageViews bool
GoogleTagManagerId string
RudderstackDataPlaneUrl string
RudderstackWriteKey string
RudderstackSdkUrl string
RudderstackConfigUrl string
2015-06-04 02:34:42 -05:00
// LDAP
2019-05-22 07:30:03 -05:00
LDAPEnabled bool
2022-10-12 06:33:33 -05:00
LDAPSkipOrgRoleSync bool
2019-05-22 07:30:03 -05:00
LDAPConfigFile string
LDAPSyncCron string
LDAPAllowSignup bool
LDAPActiveSyncEnabled bool
2015-07-10 04:10:48 -05:00
2016-04-29 07:35:58 -05:00
// Alerting
2021-11-24 13:56:07 -06:00
AlertingEnabled * bool
2018-09-06 04:20:38 -05:00
ExecuteAlerts bool
2018-09-25 05:17:04 -05:00
AlertingRenderLimit int
2018-09-06 04:20:38 -05:00
AlertingErrorOrTimeout string
AlertingNoDataOrNullValues string
2016-06-07 06:31:56 -05:00
2019-03-29 00:58:37 -05:00
AlertingEvaluationTimeout time . Duration
AlertingNotificationTimeout time . Duration
AlertingMaxAttempts int
2020-01-14 03:13:34 -06:00
AlertingMinInterval int64
2019-03-29 00:58:37 -05:00
2018-04-27 04:39:14 -05:00
// Explore UI
ExploreEnabled bool
2022-03-29 10:27:53 -05:00
// Help UI
HelpEnabled bool
// Profile UI
ProfileEnabled bool
2016-05-27 06:52:19 -05:00
// Grafana.NET URL
2017-05-22 07:56:50 -05:00
GrafanaComUrl string
2016-07-30 06:36:21 -05:00
2016-08-10 10:27:39 -05:00
ImageUploadProvider string
2014-10-04 06:33:20 -05:00
)
2020-11-20 10:01:10 -06:00
// AddChangePasswordLink returns if login form is disabled or not since
// the same intention can be used to hide both features.
func AddChangePasswordLink ( ) bool {
return ! DisableLoginForm
}
2018-10-12 00:55:36 -05:00
// TODO move all global vars to this struct
2018-04-30 09:21:04 -05:00
type Cfg struct {
2019-04-22 10:58:24 -05:00
Raw * ini . File
Logger log . Logger
2018-04-30 09:21:04 -05:00
2018-10-12 00:55:36 -05:00
// HTTP Server Settings
2021-03-10 05:41:29 -06:00
CertFile string
KeyFile string
HTTPAddr string
HTTPPort string
2020-11-13 02:52:38 -06:00
AppURL string
AppSubURL string
2019-05-27 10:47:29 -05:00
ServeFromSubPath bool
2020-06-22 11:00:39 -05:00
StaticRootPath string
2020-08-19 07:39:13 -05:00
Protocol Scheme
2022-11-01 09:04:01 -05:00
SocketGid int
SocketMode int
2020-12-11 04:44:44 -06:00
SocketPath string
RouterLogging bool
Domain string
2021-02-01 03:13:09 -06:00
CDNRootURL * url . URL
2021-03-19 05:21:52 -05:00
ReadTimeout time . Duration
2021-03-10 05:41:29 -06:00
EnableGzip bool
EnforceDomain bool
2018-10-12 00:55:36 -05:00
2021-08-25 08:11:22 -05:00
// Security settings
2021-11-10 04:52:16 -06:00
SecretKey string
2021-08-25 08:11:22 -05:00
EmailCodeValidMinutes int
2020-06-11 09:14:05 -05:00
// build
BuildVersion string
BuildCommit string
BuildBranch string
BuildStamp int64
IsEnterprise bool
// packaging
Packaging string
2018-05-01 08:51:15 -05:00
// Paths
2022-09-28 01:29:35 -05:00
HomePath string
ProvisioningPath string
DataPath string
LogsPath string
PluginsPath string
BundledPluginsPath string
EnterpriseLicensePath string
2018-05-01 08:51:15 -05:00
2018-04-30 09:21:04 -05:00
// SMTP email settings
Smtp SmtpSettings
2018-05-24 08:26:27 -05:00
// Rendering
2020-04-27 10:25:08 -05:00
ImagesDir string
2021-05-12 10:16:57 -05:00
CSVsDir string
2020-04-27 10:25:08 -05:00
RendererUrl string
RendererCallbackUrl string
2022-08-30 05:09:38 -05:00
RendererAuthToken string
2020-04-27 10:25:08 -05:00
RendererConcurrentRequestLimit int
2022-11-03 06:06:55 -05:00
RendererRenderKeyLifeTime time . Duration
2018-09-24 08:58:22 -05:00
2019-02-05 14:09:55 -06:00
// Security
2020-12-11 04:44:44 -06:00
DisableInitAdminCreation bool
DisableBruteForceLoginProtection bool
CookieSecure bool
CookieSameSiteDisabled bool
CookieSameSiteMode http . SameSite
AllowEmbedding bool
XSSProtectionHeader bool
ContentTypeProtectionHeader bool
StrictTransportSecurity bool
StrictTransportSecurityMaxAge int
StrictTransportSecurityPreload bool
StrictTransportSecuritySubDomains bool
2021-01-12 00:42:32 -06:00
// CSPEnabled toggles Content Security Policy support.
CSPEnabled bool
// CSPTemplate contains the Content Security Policy template.
2022-11-16 11:11:26 -06:00
CSPTemplate string
// CSPReportEnabled toggles Content Security Policy Report Only support.
CSPReportOnlyEnabled bool
// CSPReportOnlyTemplate contains the Content Security Policy Report Only template.
CSPReportOnlyTemplate string
2022-02-16 10:14:33 -06:00
AngularSupportEnabled bool
2019-02-05 14:09:55 -06:00
2022-09-28 01:29:35 -05:00
TempDataLifetime time . Duration
// Plugins
2021-05-27 05:45:06 -05:00
PluginsEnableAlpha bool
PluginsAppsSkipVerifyTLS bool
PluginSettings PluginSettings
PluginsAllowUnsigned [ ] string
PluginCatalogURL string
2021-11-15 03:53:35 -06:00
PluginCatalogHiddenPlugins [ ] string
2021-05-27 05:45:06 -05:00
PluginAdminEnabled bool
PluginAdminExternalManageEnabled bool
2022-09-28 01:29:35 -05:00
// Panels
DisableSanitizeHtml bool
2020-10-19 09:58:16 -05:00
// Metrics
2018-11-01 06:07:11 -05:00
MetricsEndpointEnabled bool
2018-11-14 14:42:47 -06:00
MetricsEndpointBasicAuthUsername string
MetricsEndpointBasicAuthPassword string
2019-09-17 02:32:24 -05:00
MetricsEndpointDisableTotalStats bool
2020-10-19 09:58:16 -05:00
MetricsGrafanaEnvironmentInfo map [ string ] string
2019-01-22 07:06:44 -06:00
2020-06-22 11:00:39 -05:00
// Dashboards
DefaultHomeDashboardPath string
2019-02-05 14:09:55 -06:00
// Auth
2019-02-07 03:51:35 -06:00
LoginCookieName string
2020-09-14 08:57:38 -05:00
LoginMaxInactiveLifetime time . Duration
LoginMaxLifetime time . Duration
2019-02-07 03:51:35 -06:00
TokenRotationIntervalMinutes int
2020-10-08 03:03:20 -05:00
SigV4AuthEnabled bool
2022-02-08 07:48:17 -06:00
SigV4VerboseLogging bool
2022-08-11 09:12:57 -05:00
AzureAuthEnabled bool
2023-01-16 06:16:01 -06:00
AzureSkipOrgRoleSync bool
2020-12-11 04:44:44 -06:00
BasicAuthEnabled bool
2020-12-15 12:09:04 -06:00
AdminUser string
AdminPassword string
2022-10-12 10:34:59 -05:00
DisableLogin bool
2022-09-07 07:38:40 -05:00
AdminEmail string
2022-09-20 10:48:40 -05:00
DisableSyncLock bool
2020-12-11 04:44:44 -06:00
2021-02-24 11:08:13 -06:00
// AWS Plugin Auth
AWSAllowedAuthProviders [ ] string
AWSAssumeRoleEnabled bool
2021-03-10 00:41:22 -06:00
AWSListMetricsPageLimit int
2021-02-24 11:08:13 -06:00
2021-05-12 09:23:37 -05:00
// Azure Cloud settings
2022-04-01 06:26:49 -05:00
Azure * azsettings . AzureSettings
2021-05-12 09:23:37 -05:00
2020-12-11 04:44:44 -06:00
// Auth proxy settings
AuthProxyEnabled bool
AuthProxyHeaderName string
AuthProxyHeaderProperty string
AuthProxyAutoSignUp bool
AuthProxyEnableLoginToken bool
AuthProxyWhitelist string
AuthProxyHeaders map [ string ] string
2022-03-04 03:58:27 -06:00
AuthProxyHeadersEncoded bool
2020-12-11 04:44:44 -06:00
AuthProxySyncTTL int
2019-02-22 05:11:26 -06:00
2020-03-30 09:44:58 -05:00
// OAuth
OAuthCookieMaxAge int
2021-03-31 10:40:44 -05:00
// JWT Auth
2022-09-07 07:00:33 -05:00
JWTAuthEnabled bool
JWTAuthHeaderName string
JWTAuthURLLogin bool
JWTAuthEmailClaim string
JWTAuthUsernameClaim string
JWTAuthExpectClaims string
JWTAuthJWKSetURL string
JWTAuthCacheTTL time . Duration
JWTAuthKeyFile string
JWTAuthJWKSetFile string
JWTAuthAutoSignUp bool
JWTAuthRoleAttributePath string
JWTAuthRoleAttributeStrict bool
JWTAuthAllowAssignGrafanaAdmin bool
2023-01-18 06:59:50 -06:00
JWTAuthSkipOrgRoleSync bool
2021-03-31 10:40:44 -05:00
2019-03-14 07:04:47 -05:00
// Dataproxy
2021-07-15 07:30:06 -05:00
SendUserHeader bool
DataProxyLogging bool
DataProxyTimeout int
DataProxyDialTimeout int
DataProxyTLSHandshakeTimeout int
DataProxyExpectContinueTimeout int
DataProxyMaxConnsPerHost int
DataProxyMaxIdleConns int
DataProxyKeepAlive int
DataProxyIdleConnTimeout int
2021-09-10 08:51:06 -05:00
ResponseLimit int64
2021-09-13 08:27:51 -05:00
DataProxyRowLimit int64
2019-03-14 07:04:47 -05:00
2019-03-03 14:48:00 -06:00
// DistributedCache
2019-03-08 13:49:16 -06:00
RemoteCacheOptions * RemoteCacheOptions
2019-03-12 01:32:47 -05:00
EditorsCanAdmin bool
2019-06-26 01:47:03 -05:00
ApiKeyMaxSecondsToLive int64
2019-09-09 01:58:57 -05:00
2022-01-26 11:44:20 -06:00
// Check if a feature toggle is enabled
// @deprecated
IsFeatureToggleEnabled func ( key string ) bool // filled in dynamically
2020-12-11 04:44:44 -06:00
AnonymousEnabled bool
AnonymousOrgName string
AnonymousOrgRole string
2020-06-17 00:39:50 -05:00
AnonymousHideVersion bool
2020-09-02 01:07:31 -05:00
2020-09-07 09:19:33 -05:00
DateFormats DateFormats
2020-10-13 05:30:09 -05:00
// User
UserInviteMaxLifetime time . Duration
2020-11-24 05:10:32 -06:00
HiddenUsers map [ string ] struct { }
2022-06-24 09:59:45 -05:00
CaseInsensitiveLogin bool // Login and Email will be considered case insensitive
2020-10-13 05:30:09 -05:00
2022-11-22 03:08:40 -06:00
// Service Accounts
SATokenExpirationDayLimit int
2020-09-02 01:07:31 -05:00
// Annotations
2021-03-08 07:16:07 -06:00
AnnotationCleanupJobBatchSize int64
2022-09-23 05:04:41 -05:00
AnnotationMaximumTagsLength int64
2020-09-02 01:07:31 -05:00
AlertingAnnotationCleanupSetting AnnotationCleanupSettings
DashboardAnnotationCleanupSettings AnnotationCleanupSettings
APIAnnotationCleanupSettings AnnotationCleanupSettings
2020-11-12 05:29:43 -06:00
// Sentry config
Sentry Sentry
2020-12-11 04:44:44 -06:00
2022-06-28 02:25:30 -05:00
// GrafanaJavascriptAgent config
GrafanaJavascriptAgent GrafanaJavascriptAgent
2020-12-28 05:24:42 -06:00
// Data sources
DataSourceLimit int
2020-12-11 04:44:44 -06:00
// Snapshots
SnapshotPublicMode bool
ErrTemplateName string
Env string
2022-05-02 03:38:42 -05:00
ForceMigration bool
2021-03-08 00:02:49 -06:00
// Analytics
2022-04-06 03:50:21 -05:00
CheckForGrafanaUpdates bool
CheckForPluginUpdates bool
2021-09-15 06:00:38 -05:00
ReportingDistributor string
ReportingEnabled bool
ApplicationInsightsConnectionString string
ApplicationInsightsEndpointUrl string
2022-04-14 08:18:03 -05:00
FeedbackLinksEnabled bool
2021-03-08 00:02:49 -06:00
2023-01-16 06:16:01 -06:00
// AzureAD
AzureADSkipOrgRoleSync bool
2023-01-19 02:54:22 -06:00
// Google
GoogleSkipOrgRoleSync bool
2020-12-11 04:44:44 -06:00
// LDAP
2022-10-12 06:33:33 -05:00
LDAPEnabled bool
LDAPSkipOrgRoleSync bool
LDAPAllowSignup bool
2020-12-11 04:44:44 -06:00
2022-11-22 06:18:34 -06:00
DefaultTheme string
DefaultLanguage string
HomePage string
2021-01-07 04:36:13 -06:00
2022-11-14 13:08:10 -06:00
Quota QuotaSettings
2022-02-21 10:34:47 -06:00
AutoAssignOrg bool
AutoAssignOrgId int
AutoAssignOrgRole string
OAuthSkipOrgRoleUpdateSync bool
2021-01-22 11:27:33 -06:00
// ExpressionsEnabled specifies whether expressions are enabled.
ExpressionsEnabled bool
2021-03-10 05:41:29 -06:00
ImageUploadProvider string
2021-05-27 14:03:18 -05:00
// LiveMaxConnections is a maximum number of WebSocket connections to
// Grafana Live ws endpoint (per Grafana server instance). 0 disables
// Live, -1 means unlimited connections.
LiveMaxConnections int
2021-06-24 03:07:09 -05:00
// LiveHAEngine is a type of engine to use to achieve HA with Grafana Live.
// Zero value means in-memory single node setup.
LiveHAEngine string
// LiveHAEngineAddress is a connection address for Live HA engine.
LiveHAEngineAddress string
2021-07-01 01:30:09 -05:00
// LiveAllowedOrigins is a set of origins accepted by Live. If not provided
// then Live uses AppURL as the only allowed origin.
LiveAllowedOrigins [ ] string
2021-06-08 09:08:25 -05:00
Add a separate grafana.com API URL setting (#59506)
The GrafanaComURL setting is currently used in two places:
- the /api/gnet endpoint, which proxies all requests to the URL
configured in GrafanaComURL
- OAuth logins using grafana.com, where the auth URL, token URL and
redirect URL are all configured to use the GrafanaComURL.
This has worked fine until now because almost all Grafana instances have
just used the default value, https://grafana.com. However, we now have a
few different grafana.com's, some of which are behind IAP. The IAP
causes the /api/gnet proxy to fail because the required cookies are not
present in the request (how could they be?). Setting the
[grafana_net.url] setting to an internal-only URL improves the situation
slightly - the proxy works again just fine - but breaks any OAuth logins
using grafana.com, because the user must be redirected to a publicly
accessible URL.
This commit adds an additional setting, `[grafana_com.api_url]`,
which can be used to tell Grafana to use the new API URL when proxying
requests to the grafana.com API, while still using the existing
`GrafanaComURL` setting for other things.
The setting will fall back to the GrafanaComURL setting + "/api" if unset.
2022-12-01 11:06:12 -06:00
// Grafana.com URL, used for OAuth redirect.
2021-06-08 09:08:25 -05:00
GrafanaComURL string
Add a separate grafana.com API URL setting (#59506)
The GrafanaComURL setting is currently used in two places:
- the /api/gnet endpoint, which proxies all requests to the URL
configured in GrafanaComURL
- OAuth logins using grafana.com, where the auth URL, token URL and
redirect URL are all configured to use the GrafanaComURL.
This has worked fine until now because almost all Grafana instances have
just used the default value, https://grafana.com. However, we now have a
few different grafana.com's, some of which are behind IAP. The IAP
causes the /api/gnet proxy to fail because the required cookies are not
present in the request (how could they be?). Setting the
[grafana_net.url] setting to an internal-only URL improves the situation
slightly - the proxy works again just fine - but breaks any OAuth logins
using grafana.com, because the user must be redirected to a publicly
accessible URL.
This commit adds an additional setting, `[grafana_com.api_url]`,
which can be used to tell Grafana to use the new API URL when proxying
requests to the grafana.com API, while still using the existing
`GrafanaComURL` setting for other things.
The setting will fall back to the GrafanaComURL setting + "/api" if unset.
2022-12-01 11:06:12 -06:00
// Grafana.com API URL. Can be set separately to GrafanaComURL
// in case API is not publicly accessible.
// Defaults to GrafanaComURL setting + "/api" if unset.
GrafanaComAPIURL string
2023-01-12 09:44:08 -06:00
// GrafanaComSkipOrgRoleSync can be set for
// letting users set org roles from within Grafana and
// skip the org roles coming from GrafanaCom
GrafanaComSkipOrgRoleSync bool
2021-07-21 10:54:05 -05:00
2021-07-21 15:48:20 -05:00
// Geomap base layer config
GeomapDefaultBaseLayerConfig map [ string ] interface { }
GeomapEnableCustomBaseLayers bool
2021-08-13 07:14:36 -05:00
// Unified Alerting
2021-09-20 02:12:21 -05:00
UnifiedAlerting UnifiedAlertingSettings
2022-01-28 10:55:09 -06:00
// Query history
QueryHistoryEnabled bool
2022-04-24 16:55:10 -05:00
DashboardPreviews DashboardPreviewsSettings
2022-05-16 05:45:41 -05:00
2022-07-25 12:11:17 -05:00
Storage StorageSettings
2022-09-20 18:09:55 -05:00
Search SearchSettings
2022-11-29 23:50:59 -06:00
SecureSocksDSProxy SecureSocksDSProxySettings
2022-05-16 05:45:41 -05:00
// Access Control
2022-05-16 10:52:10 -05:00
RBACEnabled bool
RBACPermissionCache bool
2022-08-31 09:58:45 -05:00
// Enable Permission validation during role creation and provisioning
RBACPermissionValidationEnabled bool
2022-12-01 02:41:40 -06:00
// Reset basic roles permissions on start-up
RBACResetBasicRoles bool
2022-09-26 15:25:34 -05:00
// GRPC Server.
GRPCServerNetwork string
GRPCServerAddress string
GRPCServerTLSConfig * tls . Config
2022-11-30 11:12:34 -06:00
CustomResponseHeaders map [ string ] string
2018-04-30 09:21:04 -05:00
}
2015-04-08 07:10:04 -05:00
type CommandLineArgs struct {
2015-04-12 02:15:49 -05:00
Config string
HomePath string
Args [ ] string
2015-04-08 07:10:04 -05:00
}
2021-11-08 10:56:56 -06:00
func ( cfg Cfg ) parseAppUrlAndSubUrl ( section * ini . Section ) ( string , string , error ) {
2020-09-08 04:33:04 -05:00
appUrl := valueAsString ( section , "root_url" , "http://localhost:3000/" )
2015-01-27 03:09:54 -06:00
if appUrl [ len ( appUrl ) - 1 ] != '/' {
appUrl += "/"
}
// Check if has app suburl.
2015-01-30 07:21:32 -06:00
url , err := url . Parse ( appUrl )
2015-01-27 03:09:54 -06:00
if err != nil {
2021-11-08 10:56:56 -06:00
cfg . Logger . Error ( "Invalid root_url." , "url" , appUrl , "error" , err )
2021-10-26 10:36:24 -05:00
os . Exit ( 1 )
2015-01-27 03:09:54 -06:00
}
2020-09-08 04:33:04 -05:00
appSubUrl := strings . TrimSuffix ( url . Path , "/" )
2019-04-25 01:29:07 -05:00
return appUrl , appSubUrl , nil
2015-01-27 03:09:54 -06:00
}
2015-02-06 07:17:40 -06:00
func ToAbsUrl ( relativeUrl string ) string {
2015-02-04 04:35:59 -06:00
return AppUrl + relativeUrl
}
2021-05-10 10:03:10 -05:00
func RedactedValue ( key , value string ) string {
uppercased := strings . ToUpper ( key )
// Sensitive information: password, secrets etc
for _ , pattern := range [ ] string {
"PASSWORD" ,
"SECRET" ,
"PROVIDER_CONFIG" ,
"PRIVATE_KEY" ,
"SECRET_KEY" ,
"CERTIFICATE" ,
2021-08-19 04:41:26 -05:00
"ACCOUNT_KEY" ,
2021-11-30 04:28:52 -06:00
"ENCRYPTION_KEY" ,
"VAULT_TOKEN" ,
2021-05-10 10:03:10 -05:00
} {
2021-11-30 04:28:52 -06:00
if match , err := regexp . MatchString ( pattern , uppercased ) ; match && err == nil {
2021-05-10 10:03:10 -05:00
return RedactedPassword
}
}
2021-11-30 04:28:52 -06:00
for _ , exception := range [ ] string {
"RUDDERSTACK" ,
"APPLICATION_INSIGHTS" ,
"SENTRY" ,
2021-05-10 10:03:10 -05:00
} {
2021-11-30 04:28:52 -06:00
if strings . Contains ( uppercased , exception ) {
return value
2021-05-10 10:03:10 -05:00
}
}
2021-11-30 04:28:52 -06:00
if u , err := RedactedURL ( value ) ; err == nil {
return u
}
2021-05-10 10:03:10 -05:00
return value
2016-06-28 11:37:59 -05:00
}
2021-11-30 04:28:52 -06:00
func RedactedURL ( value string ) ( string , error ) {
// Value could be a list of URLs
chunks := util . SplitString ( value )
for i , chunk := range chunks {
var hasTmpPrefix bool
const tmpPrefix = "http://"
if ! strings . Contains ( chunk , "://" ) {
chunk = tmpPrefix + chunk
hasTmpPrefix = true
}
u , err := url . Parse ( chunk )
if err != nil {
return "" , err
}
redacted := u . Redacted ( )
if hasTmpPrefix {
redacted = strings . Replace ( redacted , tmpPrefix , "" , 1 )
}
chunks [ i ] = redacted
}
if strings . Contains ( value , "," ) {
return strings . Join ( chunks , "," ) , nil
}
return strings . Join ( chunks , " " ) , nil
}
2018-04-30 09:21:04 -05:00
func applyEnvVariableOverrides ( file * ini . File ) error {
2015-04-09 05:16:59 -05:00
appliedEnvOverrides = make ( [ ] string , 0 )
2018-04-30 09:21:04 -05:00
for _ , section := range file . Sections ( ) {
2015-02-12 06:31:41 -06:00
for _ , key := range section . Keys ( ) {
2021-11-30 04:28:52 -06:00
envKey := EnvKey ( section . Name ( ) , key . Name ( ) )
2015-02-12 06:31:41 -06:00
envValue := os . Getenv ( envKey )
if len ( envValue ) > 0 {
key . SetValue ( envValue )
2021-05-10 10:03:10 -05:00
appliedEnvOverrides = append ( appliedEnvOverrides , fmt . Sprintf ( "%s=%s" , envKey , RedactedValue ( envKey , envValue ) ) )
2015-02-12 06:31:41 -06:00
}
}
}
2018-03-28 11:03:33 -05:00
return nil
2015-02-12 04:55:55 -06:00
}
2020-10-19 09:58:16 -05:00
func ( cfg * Cfg ) readGrafanaEnvironmentMetrics ( ) error {
environmentMetricsSection := cfg . Raw . Section ( "metrics.environment_info" )
keys := environmentMetricsSection . Keys ( )
cfg . MetricsGrafanaEnvironmentInfo = make ( map [ string ] string , len ( keys ) )
for _ , key := range keys {
labelName := model . LabelName ( key . Name ( ) )
labelValue := model . LabelValue ( key . Value ( ) )
if ! labelName . IsValid ( ) {
return fmt . Errorf ( "invalid label name in [metrics.environment_info] configuration. name %q" , labelName )
}
if ! labelValue . IsValid ( ) {
return fmt . Errorf ( "invalid label value in [metrics.environment_info] configuration. name %q value %q" , labelName , labelValue )
}
cfg . MetricsGrafanaEnvironmentInfo [ string ( labelName ) ] = string ( labelValue )
}
return nil
}
2022-09-23 05:04:41 -05:00
func ( cfg * Cfg ) readAnnotationSettings ( ) error {
2021-03-08 07:16:07 -06:00
section := cfg . Raw . Section ( "annotations" )
cfg . AnnotationCleanupJobBatchSize = section . Key ( "cleanupjob_batchsize" ) . MustInt64 ( 100 )
2022-09-23 05:04:41 -05:00
cfg . AnnotationMaximumTagsLength = section . Key ( "tags_length" ) . MustInt64 ( 500 )
switch {
case cfg . AnnotationMaximumTagsLength > 4096 :
// ensure that the configuration does not exceed the respective column size
return fmt . Errorf ( "[annotations.tags_length] configuration exceeds the maximum allowed (4096)" )
case cfg . AnnotationMaximumTagsLength > 500 :
cfg . Logger . Info ( "[annotations.tags_length] has been increased from its default value; this may affect the performance" , "tagLength" , cfg . AnnotationMaximumTagsLength )
case cfg . AnnotationMaximumTagsLength < 500 :
cfg . Logger . Warn ( "[annotations.tags_length] is too low; the minimum allowed (500) is enforced" )
cfg . AnnotationMaximumTagsLength = 500
}
2021-03-08 07:16:07 -06:00
2020-09-02 01:07:31 -05:00
dashboardAnnotation := cfg . Raw . Section ( "annotations.dashboard" )
apiIAnnotation := cfg . Raw . Section ( "annotations.api" )
alertingSection := cfg . Raw . Section ( "alerting" )
var newAnnotationCleanupSettings = func ( section * ini . Section , maxAgeField string ) AnnotationCleanupSettings {
2020-11-02 12:26:19 -06:00
maxAge , err := gtime . ParseDuration ( section . Key ( maxAgeField ) . MustString ( "" ) )
2020-09-02 01:07:31 -05:00
if err != nil {
maxAge = 0
}
return AnnotationCleanupSettings {
MaxAge : maxAge ,
MaxCount : section . Key ( "max_annotations_to_keep" ) . MustInt64 ( 0 ) ,
}
}
cfg . AlertingAnnotationCleanupSetting = newAnnotationCleanupSettings ( alertingSection , "max_annotation_age" )
cfg . DashboardAnnotationCleanupSettings = newAnnotationCleanupSettings ( dashboardAnnotation , "max_age" )
cfg . APIAnnotationCleanupSettings = newAnnotationCleanupSettings ( apiIAnnotation , "max_age" )
2022-09-23 05:04:41 -05:00
return nil
2020-09-02 01:07:31 -05:00
}
2021-01-22 11:27:33 -06:00
func ( cfg * Cfg ) readExpressionsSettings ( ) {
expressions := cfg . Raw . Section ( "expressions" )
cfg . ExpressionsEnabled = expressions . Key ( "enabled" ) . MustBool ( true )
}
2020-09-02 01:07:31 -05:00
type AnnotationCleanupSettings struct {
MaxAge time . Duration
MaxCount int64
}
2021-11-30 04:28:52 -06:00
func EnvKey ( sectionName string , keyName string ) string {
2020-09-22 09:22:19 -05:00
sN := strings . ToUpper ( strings . ReplaceAll ( sectionName , "." , "_" ) )
sN = strings . ReplaceAll ( sN , "-" , "_" )
kN := strings . ToUpper ( strings . ReplaceAll ( keyName , "." , "_" ) )
2020-01-10 08:33:54 -06:00
envKey := fmt . Sprintf ( "GF_%s_%s" , sN , kN )
return envKey
}
2018-04-30 09:21:04 -05:00
func applyCommandLineDefaultProperties ( props map [ string ] string , file * ini . File ) {
2015-04-09 05:16:59 -05:00
appliedCommandLineProperties = make ( [ ] string , 0 )
2018-04-30 09:21:04 -05:00
for _ , section := range file . Sections ( ) {
2015-04-09 05:16:59 -05:00
for _ , key := range section . Keys ( ) {
keyString := fmt . Sprintf ( "default.%s.%s" , section . Name ( ) , key . Name ( ) )
value , exists := props [ keyString ]
if exists {
key . SetValue ( value )
2021-05-10 10:03:10 -05:00
appliedCommandLineProperties = append ( appliedCommandLineProperties ,
fmt . Sprintf ( "%s=%s" , keyString , RedactedValue ( keyString , value ) ) )
2015-04-09 05:16:59 -05:00
}
2015-04-08 13:31:42 -05:00
}
}
}
2018-04-30 09:21:04 -05:00
func applyCommandLineProperties ( props map [ string ] string , file * ini . File ) {
for _ , section := range file . Sections ( ) {
2017-10-01 13:02:25 -05:00
sectionName := section . Name ( ) + "."
2019-09-30 08:16:04 -05:00
if section . Name ( ) == ini . DefaultSection {
2017-10-01 13:02:25 -05:00
sectionName = ""
}
2015-04-09 05:16:59 -05:00
for _ , key := range section . Keys ( ) {
2017-10-01 13:02:25 -05:00
keyString := sectionName + key . Name ( )
2015-04-09 05:16:59 -05:00
value , exists := props [ keyString ]
if exists {
appliedCommandLineProperties = append ( appliedCommandLineProperties , fmt . Sprintf ( "%s=%s" , keyString , value ) )
2017-10-01 13:02:25 -05:00
key . SetValue ( value )
2015-04-09 05:16:59 -05:00
}
}
}
}
2015-02-15 15:57:49 -06:00
2021-11-08 10:56:56 -06:00
func ( cfg Cfg ) getCommandLineProperties ( args [ ] string ) map [ string ] string {
2015-04-09 05:16:59 -05:00
props := make ( map [ string ] string )
2014-10-04 06:33:20 -05:00
2015-04-09 05:16:59 -05:00
for _ , arg := range args {
if ! strings . HasPrefix ( arg , "cfg:" ) {
continue
}
trimmed := strings . TrimPrefix ( arg , "cfg:" )
parts := strings . Split ( trimmed , "=" )
if len ( parts ) != 2 {
2021-11-08 10:56:56 -06:00
cfg . Logger . Error ( "Invalid command line argument." , "argument" , arg )
2021-10-26 10:36:24 -05:00
os . Exit ( 1 )
2015-01-27 03:09:54 -06:00
}
2015-01-05 00:59:18 -06:00
2015-04-09 05:16:59 -05:00
props [ parts [ 0 ] ] = parts [ 1 ]
}
return props
}
func makeAbsolute ( path string , root string ) string {
if filepath . IsAbs ( path ) {
return path
}
return filepath . Join ( root , path )
}
2021-08-25 08:11:22 -05:00
func ( cfg * Cfg ) loadSpecifiedConfigFile ( configFile string , masterFile * ini . File ) error {
2015-04-12 02:15:49 -05:00
if configFile == "" {
2021-08-25 08:11:22 -05:00
configFile = filepath . Join ( cfg . HomePath , CustomInitPath )
2015-04-12 02:15:49 -05:00
// return without error if custom file does not exist
if ! pathExists ( configFile ) {
2016-06-30 18:37:06 -05:00
return nil
2015-04-12 02:15:49 -05:00
}
}
2015-04-10 03:58:32 -05:00
userConfig , err := ini . Load ( configFile )
if err != nil {
2020-11-05 06:07:06 -06:00
return fmt . Errorf ( "failed to parse %q: %w" , configFile , err )
2015-04-10 03:58:32 -05:00
}
2016-11-28 10:55:18 -06:00
userConfig . BlockMode = false
2015-04-10 03:58:32 -05:00
for _ , section := range userConfig . Sections ( ) {
for _ , key := range section . Keys ( ) {
if key . Value ( ) == "" {
continue
}
2018-04-30 09:21:04 -05:00
defaultSec , err := masterFile . GetSection ( section . Name ( ) )
2015-04-10 03:58:32 -05:00
if err != nil {
2018-04-30 09:21:04 -05:00
defaultSec , _ = masterFile . NewSection ( section . Name ( ) )
2015-04-10 03:58:32 -05:00
}
defaultKey , err := defaultSec . GetKey ( key . Name ( ) )
if err != nil {
2015-11-19 09:50:17 -06:00
defaultKey , _ = defaultSec . NewKey ( key . Name ( ) , key . Value ( ) )
2015-04-10 03:58:32 -05:00
}
defaultKey . SetValue ( key . Value ( ) )
}
}
configFiles = append ( configFiles , configFile )
2016-06-30 18:37:06 -05:00
return nil
2015-04-10 03:58:32 -05:00
}
2021-08-25 08:11:22 -05:00
func ( cfg * Cfg ) loadConfiguration ( args CommandLineArgs ) ( * ini . File , error ) {
2015-04-09 05:16:59 -05:00
// load config defaults
defaultConfigFile := path . Join ( HomePath , "conf/defaults.ini" )
configFiles = append ( configFiles , defaultConfigFile )
2016-12-06 00:36:10 -06:00
// check if config file exists
if _ , err := os . Stat ( defaultConfigFile ) ; os . IsNotExist ( err ) {
fmt . Println ( "Grafana-server Init Failed: Could not find config defaults, make sure homepath command line parameter is set or working directory is homepath" )
os . Exit ( 1 )
}
// load defaults
2018-04-30 09:21:04 -05:00
parsedFile , err := ini . Load ( defaultConfigFile )
2015-04-09 05:16:59 -05:00
if err != nil {
2020-03-23 07:37:53 -05:00
fmt . Printf ( "Failed to parse defaults.ini, %v\n" , err )
2016-12-06 00:36:10 -06:00
os . Exit ( 1 )
2018-04-30 09:21:04 -05:00
return nil , err
2015-04-09 05:16:59 -05:00
}
2018-04-30 09:21:04 -05:00
parsedFile . BlockMode = false
2016-11-18 09:43:08 -06:00
2015-04-09 05:16:59 -05:00
// command line props
2021-11-08 10:56:56 -06:00
commandLineProps := cfg . getCommandLineProperties ( args . Args )
2015-04-09 05:16:59 -05:00
// load default overrides
2018-04-30 09:21:04 -05:00
applyCommandLineDefaultProperties ( commandLineProps , parsedFile )
2015-04-09 05:16:59 -05:00
// load specified config file
2021-08-25 08:11:22 -05:00
err = cfg . loadSpecifiedConfigFile ( args . Config , parsedFile )
2016-06-30 18:37:06 -05:00
if err != nil {
2019-06-04 15:00:05 -05:00
err2 := cfg . initLogging ( parsedFile )
if err2 != nil {
return nil , err2
2019-04-25 01:29:07 -05:00
}
2021-11-08 10:56:56 -06:00
cfg . Logger . Error ( err . Error ( ) )
2021-10-26 10:36:24 -05:00
os . Exit ( 1 )
2016-06-30 18:37:06 -05:00
}
2014-10-04 06:33:20 -05:00
2015-04-09 05:16:59 -05:00
// apply environment overrides
2018-04-30 09:21:04 -05:00
err = applyEnvVariableOverrides ( parsedFile )
2018-03-28 11:03:33 -05:00
if err != nil {
2018-04-30 09:21:04 -05:00
return nil , err
2018-03-28 11:03:33 -05:00
}
2015-04-09 05:16:59 -05:00
// apply command line overrides
2018-04-30 09:21:04 -05:00
applyCommandLineProperties ( commandLineProps , parsedFile )
2015-04-08 07:10:04 -05:00
2015-04-09 05:16:59 -05:00
// evaluate config values containing environment variables
2020-06-10 07:58:42 -05:00
err = expandConfig ( parsedFile )
if err != nil {
return nil , err
}
2015-05-14 03:15:46 -05:00
// update data path and logging config
2020-09-08 04:33:04 -05:00
dataPath := valueAsString ( parsedFile . Section ( "paths" ) , "data" , "" )
2019-04-25 01:29:07 -05:00
cfg . DataPath = makeAbsolute ( dataPath , HomePath )
err = cfg . initLogging ( parsedFile )
if err != nil {
return nil , err
}
2018-03-28 11:03:33 -05:00
2022-02-03 09:20:02 -06:00
cfg . Logger . Info ( fmt . Sprintf ( "Starting %s" , ApplicationName ) , "version" , BuildVersion , "commit" , BuildCommit , "branch" , BuildBranch , "compiled" , time . Unix ( BuildStamp , 0 ) )
2018-04-30 09:21:04 -05:00
return parsedFile , err
2015-04-09 05:16:59 -05:00
}
2015-04-12 02:15:49 -05:00
func pathExists ( path string ) bool {
_ , err := os . Stat ( path )
if err == nil {
return true
}
if os . IsNotExist ( err ) {
return false
}
return false
}
2021-08-25 08:11:22 -05:00
func ( cfg * Cfg ) setHomePath ( args CommandLineArgs ) {
2015-04-12 02:15:49 -05:00
if args . HomePath != "" {
2021-08-25 08:11:22 -05:00
cfg . HomePath = args . HomePath
HomePath = cfg . HomePath
2015-04-12 02:15:49 -05:00
return
}
2021-01-12 00:42:32 -06:00
var err error
2021-08-25 08:11:22 -05:00
cfg . HomePath , err = filepath . Abs ( "." )
2021-01-12 00:42:32 -06:00
if err != nil {
panic ( err )
}
2021-08-25 08:11:22 -05:00
HomePath = cfg . HomePath
2015-04-12 02:15:49 -05:00
// check if homepath is correct
2021-08-25 08:11:22 -05:00
if pathExists ( filepath . Join ( cfg . HomePath , "conf/defaults.ini" ) ) {
2015-04-12 02:15:49 -05:00
return
}
// try down one path
2021-08-25 08:11:22 -05:00
if pathExists ( filepath . Join ( cfg . HomePath , "../conf/defaults.ini" ) ) {
cfg . HomePath = filepath . Join ( cfg . HomePath , "../" )
HomePath = cfg . HomePath
2015-04-12 02:15:49 -05:00
}
}
2018-04-27 15:14:36 -05:00
var skipStaticRootValidation = false
2015-09-11 01:58:45 -05:00
2019-04-22 10:58:24 -05:00
func NewCfg ( ) * Cfg {
return & Cfg {
2022-08-11 08:37:31 -05:00
Logger : log . New ( "settings" ) ,
Raw : ini . Empty ( ) ,
Azure : & azsettings . AzureSettings { } ,
RBACEnabled : true ,
2019-04-22 10:58:24 -05:00
}
}
2021-08-25 08:11:22 -05:00
func NewCfgFromArgs ( args CommandLineArgs ) ( * Cfg , error ) {
cfg := NewCfg ( )
if err := cfg . Load ( args ) ; err != nil {
return nil , err
}
return cfg , nil
}
2019-04-22 10:58:24 -05:00
func ( cfg * Cfg ) validateStaticRootPath ( ) error {
2015-09-11 01:58:45 -05:00
if skipStaticRootValidation {
return nil
2015-09-10 06:34:32 -05:00
}
2017-10-01 13:02:25 -05:00
if _ , err := os . Stat ( path . Join ( StaticRootPath , "build" ) ) ; err != nil {
2019-04-22 10:58:24 -05:00
cfg . Logger . Error ( "Failed to detect generated javascript files in public/build" )
2015-09-10 06:34:32 -05:00
}
2017-10-01 13:02:25 -05:00
return nil
2015-09-10 06:34:32 -05:00
}
2021-08-25 08:11:22 -05:00
func ( cfg * Cfg ) Load ( args CommandLineArgs ) error {
cfg . setHomePath ( args )
2018-04-30 09:21:04 -05:00
2021-03-19 04:14:49 -05:00
// Fix for missing IANA db on Windows
_ , zoneInfoSet := os . LookupEnv ( zoneInfo )
if runtime . GOOS == "windows" && ! zoneInfoSet {
if err := os . Setenv ( zoneInfo , filepath . Join ( HomePath , "tools" , "zoneinfo.zip" ) ) ; err != nil {
cfg . Logger . Error ( "Can't set ZONEINFO environment variable" , "err" , err )
}
}
2018-10-12 00:55:36 -05:00
iniFile , err := cfg . loadConfiguration ( args )
2018-03-28 11:03:33 -05:00
if err != nil {
return err
}
2015-04-09 05:16:59 -05:00
2018-04-30 09:21:04 -05:00
cfg . Raw = iniFile
2020-11-13 02:52:38 -06:00
// Temporarily keep global, to make refactor in steps
2018-04-30 09:21:04 -05:00
Raw = cfg . Raw
2020-06-11 09:14:05 -05:00
cfg . BuildVersion = BuildVersion
cfg . BuildCommit = BuildCommit
cfg . BuildStamp = BuildStamp
cfg . BuildBranch = BuildBranch
cfg . IsEnterprise = IsEnterprise
cfg . Packaging = Packaging
2020-12-15 12:09:04 -06:00
cfg . ErrTemplateName = "error"
2020-12-11 04:44:44 -06:00
2020-09-08 04:33:04 -05:00
Env = valueAsString ( iniFile . Section ( "" ) , "app_mode" , "development" )
2020-12-11 04:44:44 -06:00
cfg . Env = Env
2022-05-02 03:38:42 -05:00
cfg . ForceMigration = iniFile . Section ( "" ) . Key ( "force_migration" ) . MustBool ( false )
2020-09-08 04:33:04 -05:00
InstanceName = valueAsString ( iniFile . Section ( "" ) , "instance_name" , "unknown_instance_name" )
plugins := valueAsString ( iniFile . Section ( "paths" ) , "plugins" , "" )
2021-02-10 06:31:47 -06:00
cfg . PluginsPath = makeAbsolute ( plugins , HomePath )
2020-05-04 03:57:55 -05:00
cfg . BundledPluginsPath = makeAbsolute ( "plugins-bundled" , HomePath )
2020-09-08 04:33:04 -05:00
provisioning := valueAsString ( iniFile . Section ( "paths" ) , "provisioning" , "" )
2020-03-20 03:40:14 -05:00
cfg . ProvisioningPath = makeAbsolute ( provisioning , HomePath )
2020-09-08 04:33:04 -05:00
2021-02-01 03:13:09 -06:00
if err := cfg . readServerSettings ( iniFile ) ; err != nil {
2020-08-26 06:11:57 -05:00
return err
}
2021-07-15 07:30:06 -05:00
if err := readDataProxySettings ( iniFile , cfg ) ; err != nil {
return err
2021-07-07 05:13:53 -05:00
}
2020-08-26 06:11:57 -05:00
if err := readSecuritySettings ( iniFile , cfg ) ; err != nil {
return err
}
2020-12-11 04:44:44 -06:00
if err := readSnapshotsSettings ( cfg , iniFile ) ; err != nil {
2020-08-26 06:11:57 -05:00
return err
}
2022-09-26 15:25:34 -05:00
if err := readGRPCServerSettings ( cfg , iniFile ) ; err != nil {
return err
}
2020-08-26 06:11:57 -05:00
// read dashboard settings
dashboards := iniFile . Section ( "dashboards" )
DashboardVersionsToKeep = dashboards . Key ( "versions_to_keep" ) . MustInt ( 20 )
2020-09-08 04:33:04 -05:00
MinRefreshInterval = valueAsString ( dashboards , "min_refresh_interval" , "5s" )
2019-05-27 10:47:29 -05:00
2020-08-26 06:11:57 -05:00
cfg . DefaultHomeDashboardPath = dashboards . Key ( "default_home_dashboard_path" ) . MustString ( "" )
2014-10-04 06:33:20 -05:00
2020-08-26 06:11:57 -05:00
if err := readUserSettings ( iniFile , cfg ) ; err != nil {
return err
}
2022-11-22 03:08:40 -06:00
if err := readServiceAccountSettings ( iniFile , cfg ) ; err != nil {
return err
}
2020-08-26 06:11:57 -05:00
if err := readAuthSettings ( iniFile , cfg ) ; err != nil {
return err
}
2022-05-16 05:45:41 -05:00
readAccessControlSettings ( iniFile , cfg )
2021-08-25 08:11:22 -05:00
if err := cfg . readRenderingSettings ( iniFile ) ; err != nil {
2020-08-26 06:11:57 -05:00
return err
}
cfg . TempDataLifetime = iniFile . Section ( "paths" ) . Key ( "temp_data_lifetime" ) . MustDuration ( time . Second * 3600 * 24 )
cfg . MetricsEndpointEnabled = iniFile . Section ( "metrics" ) . Key ( "enabled" ) . MustBool ( true )
2020-09-08 04:33:04 -05:00
cfg . MetricsEndpointBasicAuthUsername = valueAsString ( iniFile . Section ( "metrics" ) , "basic_auth_username" , "" )
cfg . MetricsEndpointBasicAuthPassword = valueAsString ( iniFile . Section ( "metrics" ) , "basic_auth_password" , "" )
2020-08-26 06:11:57 -05:00
cfg . MetricsEndpointDisableTotalStats = iniFile . Section ( "metrics" ) . Key ( "disable_total_stats" ) . MustBool ( false )
analytics := iniFile . Section ( "analytics" )
2022-04-06 03:50:21 -05:00
cfg . CheckForGrafanaUpdates = analytics . Key ( "check_for_updates" ) . MustBool ( true )
cfg . CheckForPluginUpdates = analytics . Key ( "check_for_plugin_updates" ) . MustBool ( true )
2020-08-26 06:11:57 -05:00
GoogleAnalyticsId = analytics . Key ( "google_analytics_ua_id" ) . String ( )
2022-09-20 05:13:14 -05:00
GoogleAnalytics4Id = analytics . Key ( "google_analytics_4_id" ) . String ( )
2022-11-09 08:09:19 -06:00
GoogleAnalytics4SendManualPageViews = analytics . Key ( "google_analytics_4_send_manual_page_views" ) . MustBool ( false )
2020-08-26 06:11:57 -05:00
GoogleTagManagerId = analytics . Key ( "google_tag_manager_id" ) . String ( )
2021-07-09 04:45:25 -05:00
RudderstackWriteKey = analytics . Key ( "rudderstack_write_key" ) . String ( )
RudderstackDataPlaneUrl = analytics . Key ( "rudderstack_data_plane_url" ) . String ( )
2021-12-06 08:42:29 -06:00
RudderstackSdkUrl = analytics . Key ( "rudderstack_sdk_url" ) . String ( )
RudderstackConfigUrl = analytics . Key ( "rudderstack_config_url" ) . String ( )
2022-04-14 08:18:03 -05:00
2021-03-10 03:14:00 -06:00
cfg . ReportingEnabled = analytics . Key ( "reporting_enabled" ) . MustBool ( true )
cfg . ReportingDistributor = analytics . Key ( "reporting_distributor" ) . MustString ( "grafana-labs" )
2022-04-14 08:18:03 -05:00
2021-03-10 03:14:00 -06:00
if len ( cfg . ReportingDistributor ) >= 100 {
cfg . ReportingDistributor = cfg . ReportingDistributor [ : 100 ]
2021-02-10 03:07:32 -06:00
}
2022-04-14 08:18:03 -05:00
2021-09-15 06:00:38 -05:00
cfg . ApplicationInsightsConnectionString = analytics . Key ( "application_insights_connection_string" ) . String ( )
cfg . ApplicationInsightsEndpointUrl = analytics . Key ( "application_insights_endpoint_url" ) . String ( )
2022-04-14 08:18:03 -05:00
cfg . FeedbackLinksEnabled = analytics . Key ( "feedback_links_enabled" ) . MustBool ( true )
2020-08-26 06:11:57 -05:00
if err := readAlertingSettings ( iniFile ) ; err != nil {
return err
2019-08-16 10:06:54 -05:00
}
2021-08-13 07:14:36 -05:00
2020-08-26 06:11:57 -05:00
explore := iniFile . Section ( "explore" )
ExploreEnabled = explore . Key ( "enabled" ) . MustBool ( true )
2022-03-29 10:27:53 -05:00
help := iniFile . Section ( "help" )
HelpEnabled = help . Key ( "enabled" ) . MustBool ( true )
profile := iniFile . Section ( "profile" )
ProfileEnabled = profile . Key ( "enabled" ) . MustBool ( true )
2022-01-28 10:55:09 -06:00
queryHistory := iniFile . Section ( "query_history" )
2022-06-21 07:57:44 -05:00
cfg . QueryHistoryEnabled = queryHistory . Key ( "enabled" ) . MustBool ( true )
2022-01-28 10:55:09 -06:00
2020-08-26 06:11:57 -05:00
panelsSection := iniFile . Section ( "panels" )
cfg . DisableSanitizeHtml = panelsSection . Key ( "disable_sanitize_html" ) . MustBool ( false )
2021-11-15 03:53:35 -06:00
if err := cfg . readPluginSettings ( iniFile ) ; err != nil {
return err
}
2015-01-27 03:09:54 -06:00
2021-09-29 09:16:40 -05:00
if err := cfg . readFeatureToggles ( iniFile ) ; err != nil {
return err
}
if err := cfg . ReadUnifiedAlertingSettings ( iniFile ) ; err != nil {
return err
2020-08-26 06:11:57 -05:00
}
// check old location for this option
if panelsSection . Key ( "enable_alpha" ) . MustBool ( false ) {
cfg . PluginsEnableAlpha = true
}
cfg . readLDAPConfig ( )
2021-03-12 07:30:21 -06:00
cfg . handleAWSConfig ( )
2021-05-12 09:23:37 -05:00
cfg . readAzureSettings ( )
2020-08-26 06:11:57 -05:00
cfg . readSessionConfig ( )
cfg . readSmtpSettings ( )
2022-09-23 05:04:41 -05:00
if err := cfg . readAnnotationSettings ( ) ; err != nil {
return err
}
2022-11-14 13:08:10 -06:00
cfg . readQuotaSettings ( )
2021-01-22 11:27:33 -06:00
cfg . readExpressionsSettings ( )
2020-10-19 09:58:16 -05:00
if err := cfg . readGrafanaEnvironmentMetrics ( ) ; err != nil {
return err
}
2020-08-26 06:11:57 -05:00
2020-12-28 05:24:42 -06:00
cfg . readDataSourcesSettings ( )
2022-04-24 16:55:10 -05:00
cfg . DashboardPreviews = readDashboardPreviewsSettings ( iniFile )
2022-07-25 12:11:17 -05:00
cfg . Storage = readStorageSettings ( iniFile )
2022-09-20 18:09:55 -05:00
cfg . Search = readSearchSettings ( iniFile )
2022-04-24 16:55:10 -05:00
2022-11-29 23:50:59 -06:00
cfg . SecureSocksDSProxy , err = readSecureSocksDSProxySettings ( iniFile )
if err != nil {
// if the proxy is misconfigured, disable it rather than crashing
cfg . SecureSocksDSProxy . Enabled = false
cfg . Logger . Error ( "secure_socks_datasource_proxy unable to start up" , "err" , err . Error ( ) )
}
2020-08-26 06:11:57 -05:00
if VerifyEmailEnabled && ! cfg . Smtp . Enabled {
2021-11-08 10:56:56 -06:00
cfg . Logger . Warn ( "require_email_validation is enabled but smtp is disabled" )
2020-08-26 06:11:57 -05:00
}
2023-01-18 06:59:50 -06:00
// check old key name
2020-09-08 04:33:04 -05:00
GrafanaComUrl = valueAsString ( iniFile . Section ( "grafana_net" ) , "url" , "" )
2020-08-26 06:11:57 -05:00
if GrafanaComUrl == "" {
2020-09-08 04:33:04 -05:00
GrafanaComUrl = valueAsString ( iniFile . Section ( "grafana_com" ) , "url" , "https://grafana.com" )
2020-08-26 06:11:57 -05:00
}
2021-06-08 09:08:25 -05:00
cfg . GrafanaComURL = GrafanaComUrl
2020-08-26 06:11:57 -05:00
Add a separate grafana.com API URL setting (#59506)
The GrafanaComURL setting is currently used in two places:
- the /api/gnet endpoint, which proxies all requests to the URL
configured in GrafanaComURL
- OAuth logins using grafana.com, where the auth URL, token URL and
redirect URL are all configured to use the GrafanaComURL.
This has worked fine until now because almost all Grafana instances have
just used the default value, https://grafana.com. However, we now have a
few different grafana.com's, some of which are behind IAP. The IAP
causes the /api/gnet proxy to fail because the required cookies are not
present in the request (how could they be?). Setting the
[grafana_net.url] setting to an internal-only URL improves the situation
slightly - the proxy works again just fine - but breaks any OAuth logins
using grafana.com, because the user must be redirected to a publicly
accessible URL.
This commit adds an additional setting, `[grafana_com.api_url]`,
which can be used to tell Grafana to use the new API URL when proxying
requests to the grafana.com API, while still using the existing
`GrafanaComURL` setting for other things.
The setting will fall back to the GrafanaComURL setting + "/api" if unset.
2022-12-01 11:06:12 -06:00
cfg . GrafanaComAPIURL = valueAsString ( iniFile . Section ( "grafana_com" ) , "api_url" , GrafanaComUrl + "/api" )
2020-08-26 06:11:57 -05:00
imageUploadingSection := iniFile . Section ( "external_image_storage" )
2021-03-10 05:41:29 -06:00
cfg . ImageUploadProvider = valueAsString ( imageUploadingSection , "provider" , "" )
ImageUploadProvider = cfg . ImageUploadProvider
2017-01-16 05:43:59 -06:00
2020-08-26 06:11:57 -05:00
enterprise := iniFile . Section ( "enterprise" )
2020-09-08 04:33:04 -05:00
cfg . EnterpriseLicensePath = valueAsString ( enterprise , "license_path" , filepath . Join ( cfg . DataPath , "license.jwt" ) )
2015-09-11 01:58:45 -05:00
2020-08-26 06:11:57 -05:00
cacheServer := iniFile . Section ( "remote_cache" )
2020-09-08 04:33:04 -05:00
dbName := valueAsString ( cacheServer , "type" , "database" )
connStr := valueAsString ( cacheServer , "connstr" , "" )
2022-12-06 06:20:49 -06:00
prefix := valueAsString ( cacheServer , "prefix" , "" )
2022-12-06 08:12:27 -06:00
encryption := cacheServer . Key ( "encryption" ) . MustBool ( false )
2020-09-08 04:33:04 -05:00
2020-08-26 06:11:57 -05:00
cfg . RemoteCacheOptions = & RemoteCacheOptions {
2022-12-06 08:12:27 -06:00
Name : dbName ,
ConnStr : connStr ,
Prefix : prefix ,
Encryption : encryption ,
2020-08-26 06:11:57 -05:00
}
2015-01-27 03:09:54 -06:00
2021-07-21 10:54:05 -05:00
geomapSection := iniFile . Section ( "geomap" )
2021-07-21 15:48:20 -05:00
basemapJSON := valueAsString ( geomapSection , "default_baselayer_config" , "" )
2021-07-21 10:54:05 -05:00
if basemapJSON != "" {
2021-07-21 15:48:20 -05:00
layer := make ( map [ string ] interface { } )
err = json . Unmarshal ( [ ] byte ( basemapJSON ) , & layer )
2021-07-21 10:54:05 -05:00
if err != nil {
2021-07-21 15:48:20 -05:00
cfg . Logger . Error ( "Error reading json from default_baselayer_config" , "error" , err )
} else {
cfg . GeomapDefaultBaseLayerConfig = layer
2021-07-21 10:54:05 -05:00
}
}
2021-07-21 15:48:20 -05:00
cfg . GeomapEnableCustomBaseLayers = geomapSection . Key ( "enable_custom_baselayers" ) . MustBool ( true )
2021-07-21 10:54:05 -05:00
2020-09-07 09:19:33 -05:00
cfg . readDateFormats ( )
2020-11-12 05:29:43 -06:00
cfg . readSentryConfig ( )
2022-06-28 02:25:30 -05:00
cfg . readGrafanaJavascriptAgentConfig ( )
2020-09-07 09:19:33 -05:00
2021-05-27 14:03:18 -05:00
if err := cfg . readLiveSettings ( iniFile ) ; err != nil {
return err
}
2021-08-25 08:11:22 -05:00
cfg . LogConfigSources ( )
2020-08-26 06:11:57 -05:00
return nil
}
2020-09-08 04:33:04 -05:00
func valueAsString ( section * ini . Section , keyName string , defaultValue string ) string {
return section . Key ( keyName ) . MustString ( defaultValue )
2020-08-26 06:11:57 -05:00
}
type RemoteCacheOptions struct {
2022-12-06 08:12:27 -06:00
Name string
ConnStr string
Prefix string
Encryption bool
2020-08-26 06:11:57 -05:00
}
func ( cfg * Cfg ) readLDAPConfig ( ) {
ldapSec := cfg . Raw . Section ( "auth.ldap" )
LDAPConfigFile = ldapSec . Key ( "config_file" ) . String ( )
LDAPSyncCron = ldapSec . Key ( "sync_cron" ) . String ( )
LDAPEnabled = ldapSec . Key ( "enabled" ) . MustBool ( false )
2020-12-11 04:44:44 -06:00
cfg . LDAPEnabled = LDAPEnabled
2022-10-12 06:33:33 -05:00
LDAPSkipOrgRoleSync = ldapSec . Key ( "skip_org_role_sync" ) . MustBool ( false )
cfg . LDAPSkipOrgRoleSync = LDAPSkipOrgRoleSync
2020-08-26 06:11:57 -05:00
LDAPActiveSyncEnabled = ldapSec . Key ( "active_sync_enabled" ) . MustBool ( false )
LDAPAllowSignup = ldapSec . Key ( "allow_sign_up" ) . MustBool ( true )
2020-12-11 04:44:44 -06:00
cfg . LDAPAllowSignup = LDAPAllowSignup
2020-08-26 06:11:57 -05:00
}
2021-03-12 07:30:21 -06:00
func ( cfg * Cfg ) handleAWSConfig ( ) {
2021-02-24 11:08:13 -06:00
awsPluginSec := cfg . Raw . Section ( "aws" )
cfg . AWSAssumeRoleEnabled = awsPluginSec . Key ( "assume_role_enabled" ) . MustBool ( true )
2021-03-12 07:30:21 -06:00
allowedAuthProviders := awsPluginSec . Key ( "allowed_auth_providers" ) . MustString ( "default,keys,credentials" )
2021-02-24 11:08:13 -06:00
for _ , authProvider := range strings . Split ( allowedAuthProviders , "," ) {
authProvider = strings . TrimSpace ( authProvider )
if authProvider != "" {
cfg . AWSAllowedAuthProviders = append ( cfg . AWSAllowedAuthProviders , authProvider )
}
}
2021-03-10 00:41:22 -06:00
cfg . AWSListMetricsPageLimit = awsPluginSec . Key ( "list_metrics_page_limit" ) . MustInt ( 500 )
2021-03-12 07:30:21 -06:00
// Also set environment variables that can be used by core plugins
err := os . Setenv ( awsds . AssumeRoleEnabledEnvVarKeyName , strconv . FormatBool ( cfg . AWSAssumeRoleEnabled ) )
if err != nil {
cfg . Logger . Error ( fmt . Sprintf ( "could not set environment variable '%s'" , awsds . AssumeRoleEnabledEnvVarKeyName ) , err )
}
err = os . Setenv ( awsds . AllowedAuthProvidersEnvVarKeyName , allowedAuthProviders )
if err != nil {
cfg . Logger . Error ( fmt . Sprintf ( "could not set environment variable '%s'" , awsds . AllowedAuthProvidersEnvVarKeyName ) , err )
}
2021-02-24 11:08:13 -06:00
}
2020-08-26 06:11:57 -05:00
func ( cfg * Cfg ) readSessionConfig ( ) {
sec , _ := cfg . Raw . GetSection ( "session" )
if sec != nil {
cfg . Logger . Warn (
"[Removed] Session setting was removed in v6.2, use remote_cache option instead" ,
)
}
}
func ( cfg * Cfg ) initLogging ( file * ini . File ) error {
2020-09-08 04:33:04 -05:00
logModeStr := valueAsString ( file . Section ( "log" ) , "mode" , "console" )
2020-08-26 06:11:57 -05:00
// split on comma
logModes := strings . Split ( logModeStr , "," )
// also try space
if len ( logModes ) == 1 {
logModes = strings . Split ( logModeStr , " " )
}
2020-09-08 04:33:04 -05:00
logsPath := valueAsString ( file . Section ( "paths" ) , "logs" , "" )
2020-08-26 06:11:57 -05:00
cfg . LogsPath = makeAbsolute ( logsPath , HomePath )
return log . ReadLoggingConfig ( logModes , cfg . LogsPath , file )
}
func ( cfg * Cfg ) LogConfigSources ( ) {
var text bytes . Buffer
for _ , file := range configFiles {
cfg . Logger . Info ( "Config loaded from" , "file" , file )
}
if len ( appliedCommandLineProperties ) > 0 {
for _ , prop := range appliedCommandLineProperties {
cfg . Logger . Info ( "Config overridden from command line" , "arg" , prop )
}
}
if len ( appliedEnvOverrides ) > 0 {
text . WriteString ( "\tEnvironment variables used:\n" )
for _ , prop := range appliedEnvOverrides {
cfg . Logger . Info ( "Config overridden from Environment variable" , "var" , prop )
}
}
cfg . Logger . Info ( "Path Home" , "path" , HomePath )
cfg . Logger . Info ( "Path Data" , "path" , cfg . DataPath )
cfg . Logger . Info ( "Path Logs" , "path" , cfg . LogsPath )
2021-02-10 06:31:47 -06:00
cfg . Logger . Info ( "Path Plugins" , "path" , cfg . PluginsPath )
2020-08-26 06:11:57 -05:00
cfg . Logger . Info ( "Path Provisioning" , "path" , cfg . ProvisioningPath )
2020-12-11 04:44:44 -06:00
cfg . Logger . Info ( "App mode " + cfg . Env )
2020-08-26 06:11:57 -05:00
}
type DynamicSection struct {
section * ini . Section
Logger log . Logger
}
// Key dynamically overrides keys with environment variables.
// As a side effect, the value of the setting key will be updated if an environment variable is present.
func ( s * DynamicSection ) Key ( k string ) * ini . Key {
2021-11-30 04:28:52 -06:00
envKey := EnvKey ( s . section . Name ( ) , k )
2020-08-26 06:11:57 -05:00
envValue := os . Getenv ( envKey )
key := s . section . Key ( k )
if len ( envValue ) == 0 {
return key
}
2017-01-16 05:43:59 -06:00
2020-08-26 06:11:57 -05:00
key . SetValue ( envValue )
2021-05-10 10:03:10 -05:00
s . Logger . Info ( "Config overridden from Environment variable" , "var" , fmt . Sprintf ( "%s=%s" , envKey , RedactedValue ( envKey , envValue ) ) )
2020-08-26 06:11:57 -05:00
return key
}
// SectionWithEnvOverrides dynamically overrides keys with environment variables.
// As a side effect, the value of the setting key will be updated if an environment variable is present.
func ( cfg * Cfg ) SectionWithEnvOverrides ( s string ) * DynamicSection {
return & DynamicSection { cfg . Raw . Section ( s ) , cfg . Logger }
}
func readSecuritySettings ( iniFile * ini . File , cfg * Cfg ) error {
2018-04-30 09:21:04 -05:00
security := iniFile . Section ( "security" )
2020-09-08 04:33:04 -05:00
SecretKey = valueAsString ( security , "secret_key" , "" )
2021-11-10 04:52:16 -06:00
cfg . SecretKey = SecretKey
2015-05-01 01:40:13 -05:00
DisableGravatar = security . Key ( "disable_gravatar" ) . MustBool ( true )
2018-04-30 09:21:04 -05:00
cfg . DisableBruteForceLoginProtection = security . Key ( "disable_brute_force_login_protection" ) . MustBool ( false )
2015-05-01 01:40:13 -05:00
2019-02-05 14:09:55 -06:00
CookieSecure = security . Key ( "cookie_secure" ) . MustBool ( false )
cfg . CookieSecure = CookieSecure
2020-09-08 04:33:04 -05:00
samesiteString := valueAsString ( security , "cookie_samesite" , "lax" )
2019-02-05 14:09:55 -06:00
2020-01-14 10:41:54 -06:00
if samesiteString == "disabled" {
CookieSameSiteDisabled = true
cfg . CookieSameSiteDisabled = CookieSameSiteDisabled
2019-02-05 14:09:55 -06:00
} else {
2020-01-14 10:41:54 -06:00
validSameSiteValues := map [ string ] http . SameSite {
"lax" : http . SameSiteLaxMode ,
"strict" : http . SameSiteStrictMode ,
"none" : http . SameSiteNoneMode ,
}
if samesite , ok := validSameSiteValues [ samesiteString ] ; ok {
CookieSameSiteMode = samesite
cfg . CookieSameSiteMode = CookieSameSiteMode
} else {
CookieSameSiteMode = http . SameSiteLaxMode
cfg . CookieSameSiteMode = CookieSameSiteMode
}
2019-02-05 14:09:55 -06:00
}
2020-12-11 04:44:44 -06:00
cfg . AllowEmbedding = security . Key ( "allow_embedding" ) . MustBool ( false )
2019-05-06 02:56:23 -05:00
2020-12-11 04:44:44 -06:00
cfg . ContentTypeProtectionHeader = security . Key ( "x_content_type_options" ) . MustBool ( true )
cfg . XSSProtectionHeader = security . Key ( "x_xss_protection" ) . MustBool ( true )
cfg . StrictTransportSecurity = security . Key ( "strict_transport_security" ) . MustBool ( false )
cfg . StrictTransportSecurityMaxAge = security . Key ( "strict_transport_security_max_age_seconds" ) . MustInt ( 86400 )
cfg . StrictTransportSecurityPreload = security . Key ( "strict_transport_security_preload" ) . MustBool ( false )
cfg . StrictTransportSecuritySubDomains = security . Key ( "strict_transport_security_subdomains" ) . MustBool ( false )
2022-11-16 11:11:26 -06:00
cfg . AngularSupportEnabled = security . Key ( "angular_support_enabled" ) . MustBool ( true )
2021-01-12 00:42:32 -06:00
cfg . CSPEnabled = security . Key ( "content_security_policy" ) . MustBool ( false )
cfg . CSPTemplate = security . Key ( "content_security_policy_template" ) . MustString ( "" )
2022-11-16 11:11:26 -06:00
cfg . CSPReportOnlyEnabled = security . Key ( "content_security_policy_report_only" ) . MustBool ( false )
cfg . CSPReportOnlyTemplate = security . Key ( "content_security_policy_report_only_template" ) . MustString ( "" )
if cfg . CSPEnabled && cfg . CSPTemplate == "" {
return fmt . Errorf ( "enabling content_security_policy requires a content_security_policy_template configuration" )
}
if cfg . CSPReportOnlyEnabled && cfg . CSPReportOnlyTemplate == "" {
return fmt . Errorf ( "enabling content_security_policy_report_only requires a content_security_policy_report_only_template configuration" )
}
2019-06-12 06:15:50 -05:00
2020-08-26 06:11:57 -05:00
// read data source proxy whitelist
2015-09-09 10:21:25 -05:00
DataProxyWhiteList = make ( map [ string ] bool )
2020-09-08 04:33:04 -05:00
securityStr := valueAsString ( security , "data_source_proxy_whitelist" , "" )
2020-08-26 06:11:57 -05:00
for _ , hostAndIP := range util . SplitString ( securityStr ) {
DataProxyWhiteList [ hostAndIP ] = true
2015-09-09 10:21:25 -05:00
}
2015-01-27 08:45:27 -06:00
// admin
2019-11-08 04:11:03 -06:00
cfg . DisableInitAdminCreation = security . Key ( "disable_initial_admin_creation" ) . MustBool ( false )
2020-12-15 12:09:04 -06:00
cfg . AdminUser = valueAsString ( security , "admin_user" , "" )
cfg . AdminPassword = valueAsString ( security , "admin_password" , "" )
2022-09-07 07:38:40 -05:00
cfg . AdminEmail = valueAsString ( security , "admin_email" , fmt . Sprintf ( "%s@localhost" , cfg . AdminUser ) )
2015-01-27 08:45:27 -06:00
2020-08-26 06:11:57 -05:00
return nil
}
2023-01-16 06:16:01 -06:00
func readAuthAzureADSettings ( iniFile * ini . File , cfg * Cfg ) {
sec := iniFile . Section ( "auth.azuread" )
cfg . AzureADSkipOrgRoleSync = sec . Key ( "skip_org_role_sync" ) . MustBool ( false )
}
2016-09-28 08:27:08 -05:00
2023-01-12 09:44:08 -06:00
func readAuthGrafanaComSettings ( iniFile * ini . File , cfg * Cfg ) {
sec := iniFile . Section ( "auth.grafana_com" )
cfg . GrafanaComSkipOrgRoleSync = sec . Key ( "skip_org_role_sync" ) . MustBool ( false )
}
2023-01-19 02:54:22 -06:00
func readAuthGoogleSettings ( iniFile * ini . File , cfg * Cfg ) {
sec := iniFile . Section ( "auth.google" )
cfg . GoogleSkipOrgRoleSync = sec . Key ( "skip_org_role_sync" ) . MustBool ( false )
}
2020-09-14 08:57:38 -05:00
func readAuthSettings ( iniFile * ini . File , cfg * Cfg ) ( err error ) {
2018-04-30 09:21:04 -05:00
auth := iniFile . Section ( "auth" )
2019-02-05 14:09:55 -06:00
2020-12-15 12:09:04 -06:00
cfg . LoginCookieName = valueAsString ( auth , "login_cookie_name" , "grafana_session" )
2022-06-01 05:29:15 -05:00
const defaultMaxInactiveLifetime = "7d"
maxInactiveDurationVal := valueAsString ( auth , "login_maximum_inactive_lifetime_duration" , defaultMaxInactiveLifetime )
2020-11-02 12:26:19 -06:00
cfg . LoginMaxInactiveLifetime , err = gtime . ParseDuration ( maxInactiveDurationVal )
2020-09-14 08:57:38 -05:00
if err != nil {
return err
}
2022-06-01 05:29:15 -05:00
const defaultMaxLifetime = "30d"
maxLifetimeDurationVal := valueAsString ( auth , "login_maximum_lifetime_duration" , defaultMaxLifetime )
2020-11-02 12:26:19 -06:00
cfg . LoginMaxLifetime , err = gtime . ParseDuration ( maxLifetimeDurationVal )
2020-09-14 08:57:38 -05:00
if err != nil {
return err
}
2019-02-05 14:09:55 -06:00
2019-06-26 01:47:03 -05:00
cfg . ApiKeyMaxSecondsToLive = auth . Key ( "api_key_max_seconds_to_live" ) . MustInt64 ( - 1 )
2019-02-05 14:09:55 -06:00
cfg . TokenRotationIntervalMinutes = auth . Key ( "token_rotation_interval_minutes" ) . MustInt ( 10 )
if cfg . TokenRotationIntervalMinutes < 2 {
cfg . TokenRotationIntervalMinutes = 2
}
2022-09-20 10:48:40 -05:00
// Debug setting unlocking frontend auth sync lock. Users will still be reset on their next login.
cfg . DisableSyncLock = auth . Key ( "disable_sync_lock" ) . MustBool ( false )
2016-09-28 08:27:08 -05:00
DisableLoginForm = auth . Key ( "disable_login_form" ) . MustBool ( false )
2017-03-29 04:33:28 -05:00
DisableSignoutMenu = auth . Key ( "disable_signout_menu" ) . MustBool ( false )
2023-01-19 08:53:02 -06:00
// Deprecated
2018-05-28 09:16:48 -05:00
OAuthAutoLogin = auth . Key ( "oauth_auto_login" ) . MustBool ( false )
2023-01-19 08:53:02 -06:00
if OAuthAutoLogin {
cfg . Logger . Warn ( "[Deprecated] The oauth_auto_login configuration setting is deprecated. Please use auto_login inside auth provider section instead." )
}
2020-09-01 03:57:43 -05:00
cfg . OAuthCookieMaxAge = auth . Key ( "oauth_state_cookie_max_age" ) . MustInt ( 600 )
2020-09-08 04:33:04 -05:00
SignoutRedirectUrl = valueAsString ( auth , "signout_redirect_url" , "" )
2022-02-21 10:34:47 -06:00
cfg . OAuthSkipOrgRoleUpdateSync = auth . Key ( "oauth_skip_org_role_update_sync" ) . MustBool ( false )
2015-01-27 08:14:53 -06:00
2022-10-12 10:34:59 -05:00
cfg . DisableLogin = auth . Key ( "disable_login" ) . MustBool ( false )
2020-10-08 03:03:20 -05:00
// SigV4
SigV4AuthEnabled = auth . Key ( "sigv4_auth_enabled" ) . MustBool ( false )
cfg . SigV4AuthEnabled = SigV4AuthEnabled
2022-02-08 07:48:17 -06:00
cfg . SigV4VerboseLogging = auth . Key ( "sigv4_verbose_logging" ) . MustBool ( false )
2020-10-08 03:03:20 -05:00
2022-08-11 09:12:57 -05:00
// Azure Auth
AzureAuthEnabled = auth . Key ( "azure_auth_enabled" ) . MustBool ( false )
cfg . AzureAuthEnabled = AzureAuthEnabled
2023-01-16 06:16:01 -06:00
readAuthAzureADSettings ( iniFile , cfg )
2022-08-11 09:12:57 -05:00
2023-01-19 02:54:22 -06:00
// Google Auth
readAuthGoogleSettings ( iniFile , cfg )
2015-01-27 08:45:27 -06:00
// anonymous access
2018-04-30 09:21:04 -05:00
AnonymousEnabled = iniFile . Section ( "auth.anonymous" ) . Key ( "enabled" ) . MustBool ( false )
2020-12-11 04:44:44 -06:00
cfg . AnonymousEnabled = AnonymousEnabled
cfg . AnonymousOrgName = valueAsString ( iniFile . Section ( "auth.anonymous" ) , "org_name" , "" )
cfg . AnonymousOrgRole = valueAsString ( iniFile . Section ( "auth.anonymous" ) , "org_role" , "" )
2020-06-17 00:39:50 -05:00
cfg . AnonymousHideVersion = iniFile . Section ( "auth.anonymous" ) . Key ( "hide_version" ) . MustBool ( false )
2015-01-07 09:37:24 -06:00
2020-08-26 06:11:57 -05:00
// basic auth
authBasic := iniFile . Section ( "auth.basic" )
BasicAuthEnabled = authBasic . Key ( "enabled" ) . MustBool ( true )
2020-12-11 04:44:44 -06:00
cfg . BasicAuthEnabled = BasicAuthEnabled
2020-08-26 06:11:57 -05:00
2021-03-31 10:40:44 -05:00
// JWT auth
authJWT := iniFile . Section ( "auth.jwt" )
cfg . JWTAuthEnabled = authJWT . Key ( "enabled" ) . MustBool ( false )
cfg . JWTAuthHeaderName = valueAsString ( authJWT , "header_name" , "" )
2022-07-27 09:10:47 -05:00
cfg . JWTAuthURLLogin = authJWT . Key ( "url_login" ) . MustBool ( false )
2021-03-31 10:40:44 -05:00
cfg . JWTAuthEmailClaim = valueAsString ( authJWT , "email_claim" , "" )
cfg . JWTAuthUsernameClaim = valueAsString ( authJWT , "username_claim" , "" )
cfg . JWTAuthExpectClaims = valueAsString ( authJWT , "expect_claims" , "{}" )
cfg . JWTAuthJWKSetURL = valueAsString ( authJWT , "jwk_set_url" , "" )
cfg . JWTAuthCacheTTL = authJWT . Key ( "cache_ttl" ) . MustDuration ( time . Minute * 60 )
cfg . JWTAuthKeyFile = valueAsString ( authJWT , "key_file" , "" )
cfg . JWTAuthJWKSetFile = valueAsString ( authJWT , "jwk_set_file" , "" )
2022-01-13 10:15:22 -06:00
cfg . JWTAuthAutoSignUp = authJWT . Key ( "auto_sign_up" ) . MustBool ( false )
2022-09-07 07:00:33 -05:00
cfg . JWTAuthRoleAttributePath = valueAsString ( authJWT , "role_attribute_path" , "" )
cfg . JWTAuthRoleAttributeStrict = authJWT . Key ( "role_attribute_strict" ) . MustBool ( false )
cfg . JWTAuthAllowAssignGrafanaAdmin = authJWT . Key ( "allow_assign_grafana_admin" ) . MustBool ( false )
2023-01-18 06:59:50 -06:00
cfg . JWTAuthSkipOrgRoleSync = authJWT . Key ( "skip_org_role_sync" ) . MustBool ( false )
2021-03-31 10:40:44 -05:00
2018-04-30 09:21:04 -05:00
authProxy := iniFile . Section ( "auth.proxy" )
2015-05-01 04:55:59 -05:00
AuthProxyEnabled = authProxy . Key ( "enabled" ) . MustBool ( false )
2020-12-11 04:44:44 -06:00
cfg . AuthProxyEnabled = AuthProxyEnabled
2019-05-17 06:57:26 -05:00
2020-12-11 04:44:44 -06:00
cfg . AuthProxyHeaderName = valueAsString ( authProxy , "header_name" , "" )
2020-09-08 04:33:04 -05:00
AuthProxyHeaderProperty = valueAsString ( authProxy , "header_property" , "" )
2020-12-11 04:44:44 -06:00
cfg . AuthProxyHeaderProperty = AuthProxyHeaderProperty
cfg . AuthProxyAutoSignUp = authProxy . Key ( "auto_sign_up" ) . MustBool ( true )
cfg . AuthProxyEnableLoginToken = authProxy . Key ( "enable_login_token" ) . MustBool ( false )
2020-08-26 06:11:57 -05:00
2022-05-31 07:08:24 -05:00
cfg . AuthProxySyncTTL = authProxy . Key ( "sync_ttl" ) . MustInt ( )
2020-08-26 06:11:57 -05:00
2020-12-11 04:44:44 -06:00
cfg . AuthProxyWhitelist = valueAsString ( authProxy , "whitelist" , "" )
2020-08-26 06:11:57 -05:00
2020-12-11 04:44:44 -06:00
cfg . AuthProxyHeaders = make ( map [ string ] string )
2020-09-08 04:33:04 -05:00
headers := valueAsString ( authProxy , "headers" , "" )
2020-08-26 06:11:57 -05:00
for _ , propertyAndHeader := range util . SplitString ( headers ) {
split := strings . SplitN ( propertyAndHeader , ":" , 2 )
if len ( split ) == 2 {
2020-12-11 04:44:44 -06:00
cfg . AuthProxyHeaders [ split [ 0 ] ] = split [ 1 ]
2020-08-26 06:11:57 -05:00
}
}
2022-03-04 03:58:27 -06:00
cfg . AuthProxyHeadersEncoded = authProxy . Key ( "headers_encoded" ) . MustBool ( false )
2023-01-12 09:44:08 -06:00
readAuthGrafanaComSettings ( iniFile , cfg )
2020-08-26 06:11:57 -05:00
return nil
}
2022-05-16 05:45:41 -05:00
func readAccessControlSettings ( iniFile * ini . File , cfg * Cfg ) {
rbac := iniFile . Section ( "rbac" )
cfg . RBACEnabled = rbac . Key ( "enabled" ) . MustBool ( true )
2022-05-16 10:52:10 -05:00
cfg . RBACPermissionCache = rbac . Key ( "permission_cache" ) . MustBool ( true )
2022-09-02 10:18:01 -05:00
cfg . RBACPermissionValidationEnabled = rbac . Key ( "permission_validation_enabled" ) . MustBool ( false )
2022-12-01 02:41:40 -06:00
cfg . RBACResetBasicRoles = rbac . Key ( "reset_basic_roles" ) . MustBool ( false )
2022-05-16 05:45:41 -05:00
}
2020-08-26 06:11:57 -05:00
func readUserSettings ( iniFile * ini . File , cfg * Cfg ) error {
users := iniFile . Section ( "users" )
AllowUserSignUp = users . Key ( "allow_sign_up" ) . MustBool ( true )
AllowUserOrgCreate = users . Key ( "allow_org_create" ) . MustBool ( true )
2021-01-07 04:36:13 -06:00
cfg . AutoAssignOrg = users . Key ( "auto_assign_org" ) . MustBool ( true )
AutoAssignOrg = cfg . AutoAssignOrg
cfg . AutoAssignOrgId = users . Key ( "auto_assign_org_id" ) . MustInt ( 1 )
AutoAssignOrgId = cfg . AutoAssignOrgId
cfg . AutoAssignOrgRole = users . Key ( "auto_assign_org_role" ) . In ( "Editor" , [ ] string { "Editor" , "Admin" , "Viewer" } )
AutoAssignOrgRole = cfg . AutoAssignOrgRole
2020-08-26 06:11:57 -05:00
VerifyEmailEnabled = users . Key ( "verify_email_enabled" ) . MustBool ( false )
2020-09-08 04:33:04 -05:00
2022-06-24 09:59:45 -05:00
cfg . CaseInsensitiveLogin = users . Key ( "case_insensitive_login" ) . MustBool ( false )
2020-09-08 04:33:04 -05:00
LoginHint = valueAsString ( users , "login_hint" , "" )
PasswordHint = valueAsString ( users , "password_hint" , "" )
2020-12-11 04:44:44 -06:00
cfg . DefaultTheme = valueAsString ( users , "default_theme" , "" )
2022-11-22 06:18:34 -06:00
cfg . DefaultLanguage = valueAsString ( users , "default_language" , "" )
2021-04-13 08:27:51 -05:00
cfg . HomePage = valueAsString ( users , "home_page" , "" )
2020-09-08 04:33:04 -05:00
ExternalUserMngLinkUrl = valueAsString ( users , "external_manage_link_url" , "" )
ExternalUserMngLinkName = valueAsString ( users , "external_manage_link_name" , "" )
ExternalUserMngInfo = valueAsString ( users , "external_manage_info" , "" )
2020-08-26 06:11:57 -05:00
ViewersCanEdit = users . Key ( "viewers_can_edit" ) . MustBool ( false )
cfg . EditorsCanAdmin = users . Key ( "editors_can_admin" ) . MustBool ( false )
2018-05-07 03:39:16 -05:00
2020-10-13 05:30:09 -05:00
userInviteMaxLifetimeVal := valueAsString ( users , "user_invite_max_lifetime_duration" , "24h" )
2020-11-02 12:26:19 -06:00
userInviteMaxLifetimeDuration , err := gtime . ParseDuration ( userInviteMaxLifetimeVal )
2020-10-13 05:30:09 -05:00
if err != nil {
return err
}
cfg . UserInviteMaxLifetime = userInviteMaxLifetimeDuration
if cfg . UserInviteMaxLifetime < time . Minute * 15 {
return errors . New ( "the minimum supported value for the `user_invite_max_lifetime_duration` configuration is 15m (15 minutes)" )
}
2020-11-24 05:10:32 -06:00
cfg . HiddenUsers = make ( map [ string ] struct { } )
hiddenUsers := users . Key ( "hidden_users" ) . MustString ( "" )
for _ , user := range strings . Split ( hiddenUsers , "," ) {
user = strings . TrimSpace ( user )
2021-02-12 09:08:18 -06:00
if user != "" {
cfg . HiddenUsers [ user ] = struct { } { }
}
2020-11-24 05:10:32 -06:00
}
2020-08-26 06:11:57 -05:00
return nil
}
2015-06-30 02:37:52 -05:00
2022-11-22 03:08:40 -06:00
func readServiceAccountSettings ( iniFile * ini . File , cfg * Cfg ) error {
serviceAccount := iniFile . Section ( "service_accounts" )
cfg . SATokenExpirationDayLimit = serviceAccount . Key ( "token_expiration_day_limit" ) . MustInt ( - 1 )
return nil
}
2021-08-25 08:11:22 -05:00
func ( cfg * Cfg ) readRenderingSettings ( iniFile * ini . File ) error {
2018-05-24 08:26:27 -05:00
renderSec := iniFile . Section ( "rendering" )
2020-09-08 04:33:04 -05:00
cfg . RendererUrl = valueAsString ( renderSec , "server_url" , "" )
cfg . RendererCallbackUrl = valueAsString ( renderSec , "callback_url" , "" )
2022-08-30 05:09:38 -05:00
cfg . RendererAuthToken = valueAsString ( renderSec , "renderer_token" , "-" )
2020-09-08 04:33:04 -05:00
2018-09-04 06:42:55 -05:00
if cfg . RendererCallbackUrl == "" {
cfg . RendererCallbackUrl = AppUrl
} else {
if cfg . RendererCallbackUrl [ len ( cfg . RendererCallbackUrl ) - 1 ] != '/' {
cfg . RendererCallbackUrl += "/"
}
_ , err := url . Parse ( cfg . RendererCallbackUrl )
if err != nil {
2020-08-26 06:11:57 -05:00
// XXX: Should return an error?
2021-11-08 10:56:56 -06:00
cfg . Logger . Error ( "Invalid callback_url." , "url" , cfg . RendererCallbackUrl , "error" , err )
2021-10-26 10:36:24 -05:00
os . Exit ( 1 )
2018-09-04 06:42:55 -05:00
}
}
2020-04-27 10:25:08 -05:00
2020-09-08 04:33:04 -05:00
cfg . RendererConcurrentRequestLimit = renderSec . Key ( "concurrent_render_request_limit" ) . MustInt ( 30 )
2022-11-03 06:06:55 -05:00
cfg . RendererRenderKeyLifeTime = renderSec . Key ( "render_key_lifetime" ) . MustDuration ( 5 * time . Minute )
2018-10-12 00:55:36 -05:00
cfg . ImagesDir = filepath . Join ( cfg . DataPath , "png" )
2021-05-12 10:16:57 -05:00
cfg . CSVsDir = filepath . Join ( cfg . DataPath , "csv" )
2014-11-14 10:13:33 -06:00
2020-08-26 06:11:57 -05:00
return nil
}
2021-09-29 09:16:40 -05:00
2020-08-26 06:11:57 -05:00
func readAlertingSettings ( iniFile * ini . File ) error {
2018-04-30 09:21:04 -05:00
alerting := iniFile . Section ( "alerting" )
2021-11-24 13:56:07 -06:00
enabled , err := alerting . Key ( "enabled" ) . Bool ( )
AlertingEnabled = nil
if err == nil {
AlertingEnabled = & enabled
}
2016-10-10 06:09:16 -05:00
ExecuteAlerts = alerting . Key ( "execute_alerts" ) . MustBool ( true )
2018-09-25 05:17:04 -05:00
AlertingRenderLimit = alerting . Key ( "concurrent_render_limit" ) . MustInt ( 5 )
2020-09-08 04:33:04 -05:00
AlertingErrorOrTimeout = valueAsString ( alerting , "error_or_timeout" , "alerting" )
AlertingNoDataOrNullValues = valueAsString ( alerting , "nodata_or_nullvalues" , "no_data" )
2016-04-29 07:35:58 -05:00
2019-04-30 05:05:38 -05:00
evaluationTimeoutSeconds := alerting . Key ( "evaluation_timeout_seconds" ) . MustInt64 ( 30 )
AlertingEvaluationTimeout = time . Second * time . Duration ( evaluationTimeoutSeconds )
notificationTimeoutSeconds := alerting . Key ( "notification_timeout_seconds" ) . MustInt64 ( 30 )
AlertingNotificationTimeout = time . Second * time . Duration ( notificationTimeoutSeconds )
2019-03-29 00:58:37 -05:00
AlertingMaxAttempts = alerting . Key ( "max_attempts" ) . MustInt ( 3 )
2020-01-14 03:13:34 -06:00
AlertingMinInterval = alerting . Key ( "min_interval_seconds" ) . MustInt64 ( 1 )
2019-03-29 00:58:37 -05:00
2020-08-26 06:11:57 -05:00
return nil
}
2019-04-12 06:46:42 -05:00
2022-09-26 15:25:34 -05:00
func readGRPCServerSettings ( cfg * Cfg , iniFile * ini . File ) error {
server := iniFile . Section ( "grpc_server" )
errPrefix := "grpc_server:"
useTLS := server . Key ( "use_tls" ) . MustBool ( false )
certFile := server . Key ( "cert_file" ) . String ( )
keyFile := server . Key ( "cert_key" ) . String ( )
if useTLS {
serverCert , err := tls . LoadX509KeyPair ( certFile , keyFile )
if err != nil {
return fmt . Errorf ( "%s error loading X509 key pair: %w" , errPrefix , err )
}
cfg . GRPCServerTLSConfig = & tls . Config {
Certificates : [ ] tls . Certificate { serverCert } ,
ClientAuth : tls . NoClientCert ,
}
}
cfg . GRPCServerNetwork = valueAsString ( server , "network" , "tcp" )
cfg . GRPCServerAddress = valueAsString ( server , "address" , "" )
switch cfg . GRPCServerNetwork {
case "unix" :
if cfg . GRPCServerAddress != "" {
// Explicitly provided path for unix domain socket.
if stat , err := os . Stat ( cfg . GRPCServerAddress ) ; os . IsNotExist ( err ) {
// File does not exist - nice, nothing to do.
} else if err != nil {
return fmt . Errorf ( "%s error getting stat for a file: %s" , errPrefix , cfg . GRPCServerAddress )
} else {
if stat . Mode ( ) & fs . ModeSocket == 0 {
return fmt . Errorf ( "%s file %s already exists and is not a unix domain socket" , errPrefix , cfg . GRPCServerAddress )
}
// Unix domain socket file, should be safe to remove.
err := os . Remove ( cfg . GRPCServerAddress )
if err != nil {
return fmt . Errorf ( "%s can't remove unix socket file: %s" , errPrefix , cfg . GRPCServerAddress )
}
}
} else {
// Use temporary file path for a unix domain socket.
tf , err := os . CreateTemp ( "" , "gf_grpc_server_api" )
if err != nil {
return fmt . Errorf ( "%s error creating tmp file: %v" , errPrefix , err )
}
unixPath := tf . Name ( )
if err := tf . Close ( ) ; err != nil {
return fmt . Errorf ( "%s error closing tmp file: %v" , errPrefix , err )
}
if err := os . Remove ( unixPath ) ; err != nil {
return fmt . Errorf ( "%s error removing tmp file: %v" , errPrefix , err )
}
cfg . GRPCServerAddress = unixPath
}
case "tcp" :
if cfg . GRPCServerAddress == "" {
cfg . GRPCServerAddress = "127.0.0.1:10000"
}
default :
return fmt . Errorf ( "%s unsupported network %s" , errPrefix , cfg . GRPCServerNetwork )
}
return nil
}
2022-07-13 04:33:28 -05:00
// IsLegacyAlertingEnabled returns whether the legacy alerting is enabled or not.
// It's safe to be used only after readAlertingSettings() and ReadUnifiedAlertingSettings() are executed.
func IsLegacyAlertingEnabled ( ) bool {
return AlertingEnabled != nil && * AlertingEnabled
}
2020-12-11 04:44:44 -06:00
func readSnapshotsSettings ( cfg * Cfg , iniFile * ini . File ) error {
2020-08-26 06:11:57 -05:00
snapshots := iniFile . Section ( "snapshots" )
2020-09-08 04:33:04 -05:00
ExternalSnapshotUrl = valueAsString ( snapshots , "external_snapshot_url" , "" )
ExternalSnapshotName = valueAsString ( snapshots , "external_snapshot_name" , "" )
2020-08-26 06:11:57 -05:00
ExternalEnabled = snapshots . Key ( "external_enabled" ) . MustBool ( true )
SnapShotRemoveExpired = snapshots . Key ( "snapshot_remove_expired" ) . MustBool ( true )
2020-12-11 04:44:44 -06:00
cfg . SnapshotPublicMode = snapshots . Key ( "public_mode" ) . MustBool ( false )
2016-05-27 06:52:19 -05:00
2020-08-26 06:11:57 -05:00
return nil
}
2018-11-01 06:07:11 -05:00
2021-02-01 03:13:09 -06:00
func ( cfg * Cfg ) readServerSettings ( iniFile * ini . File ) error {
2020-08-26 06:11:57 -05:00
server := iniFile . Section ( "server" )
var err error
2021-11-08 10:56:56 -06:00
AppUrl , AppSubUrl , err = cfg . parseAppUrlAndSubUrl ( server )
2019-04-25 01:29:07 -05:00
if err != nil {
return err
}
2020-08-26 06:11:57 -05:00
ServeFromSubPath = server . Key ( "serve_from_sub_path" ) . MustBool ( false )
2018-11-01 06:07:11 -05:00
2020-11-13 02:52:38 -06:00
cfg . AppURL = AppUrl
cfg . AppSubURL = AppSubUrl
2020-08-26 06:11:57 -05:00
cfg . ServeFromSubPath = ServeFromSubPath
2020-12-11 04:44:44 -06:00
cfg . Protocol = HTTPScheme
2021-02-01 03:13:09 -06:00
2020-09-08 04:33:04 -05:00
protocolStr := valueAsString ( server , "protocol" , "http" )
2020-08-26 06:11:57 -05:00
if protocolStr == "https" {
2020-12-11 04:44:44 -06:00
cfg . Protocol = HTTPSScheme
2021-03-10 05:41:29 -06:00
cfg . CertFile = server . Key ( "cert_file" ) . String ( )
cfg . KeyFile = server . Key ( "cert_key" ) . String ( )
2019-04-25 01:29:07 -05:00
}
2020-08-26 06:11:57 -05:00
if protocolStr == "h2" {
2020-12-11 04:44:44 -06:00
cfg . Protocol = HTTP2Scheme
2021-03-10 05:41:29 -06:00
cfg . CertFile = server . Key ( "cert_file" ) . String ( )
cfg . KeyFile = server . Key ( "cert_key" ) . String ( )
2019-03-03 14:48:00 -06:00
}
2020-08-26 06:11:57 -05:00
if protocolStr == "socket" {
2020-12-11 04:44:44 -06:00
cfg . Protocol = SocketScheme
2022-11-01 09:04:01 -05:00
cfg . SocketGid = server . Key ( "socket_gid" ) . MustInt ( - 1 )
cfg . SocketMode = server . Key ( "socket_mode" ) . MustInt ( 0660 )
2020-12-11 04:44:44 -06:00
cfg . SocketPath = server . Key ( "socket" ) . String ( )
2015-04-08 01:59:12 -05:00
}
2015-03-03 03:18:24 -06:00
2020-12-11 04:44:44 -06:00
cfg . Domain = valueAsString ( server , "domain" , "localhost" )
2021-03-10 05:41:29 -06:00
cfg . HTTPAddr = valueAsString ( server , "http_addr" , DefaultHTTPAddr )
cfg . HTTPPort = valueAsString ( server , "http_port" , "3000" )
2020-12-11 04:44:44 -06:00
cfg . RouterLogging = server . Key ( "router_logging" ) . MustBool ( false )
2015-04-09 05:16:59 -05:00
2021-03-10 05:41:29 -06:00
cfg . EnableGzip = server . Key ( "enable_gzip" ) . MustBool ( false )
cfg . EnforceDomain = server . Key ( "enforce_domain" ) . MustBool ( false )
2020-09-08 04:33:04 -05:00
staticRoot := valueAsString ( server , "static_root_path" , "" )
2020-08-26 06:11:57 -05:00
StaticRootPath = makeAbsolute ( staticRoot , HomePath )
cfg . StaticRootPath = StaticRootPath
2020-01-10 08:33:54 -06:00
2020-08-26 06:11:57 -05:00
if err := cfg . validateStaticRootPath ( ) ; err != nil {
return err
2020-01-10 08:33:54 -06:00
}
2021-02-01 03:13:09 -06:00
cdnURL := valueAsString ( server , "cdn_url" , "" )
if cdnURL != "" {
cfg . CDNRootURL , err = url . Parse ( cdnURL )
if err != nil {
return err
}
}
2021-03-19 05:21:52 -05:00
cfg . ReadTimeout = server . Key ( "read_timeout" ) . MustDuration ( 0 )
2022-11-30 11:12:34 -06:00
headersSection := cfg . Raw . Section ( "server.custom_response_headers" )
keys := headersSection . Keys ( )
cfg . CustomResponseHeaders = make ( map [ string ] string , len ( keys ) )
for _ , key := range keys {
cfg . CustomResponseHeaders [ key . Name ( ) ] = key . Value ( )
}
2020-08-26 06:11:57 -05:00
return nil
2020-01-10 08:33:54 -06:00
}
2020-12-28 05:24:42 -06:00
2021-02-01 03:13:09 -06:00
// GetContentDeliveryURL returns full content delivery URL with /<edition>/<version> added to URL
func ( cfg * Cfg ) GetContentDeliveryURL ( prefix string ) string {
if cfg . CDNRootURL != nil {
url := * cfg . CDNRootURL
preReleaseFolder := ""
url . Path = path . Join ( url . Path , prefix , preReleaseFolder , cfg . BuildVersion )
2021-02-02 05:34:59 -06:00
return url . String ( ) + "/"
2021-02-01 03:13:09 -06:00
}
return ""
}
2020-12-28 05:24:42 -06:00
func ( cfg * Cfg ) readDataSourcesSettings ( ) {
datasources := cfg . Raw . Section ( "datasources" )
cfg . DataSourceLimit = datasources . Key ( "datasource_limit" ) . MustInt ( 5000 )
}
2021-05-27 14:03:18 -05:00
2021-07-01 01:30:09 -05:00
func GetAllowedOriginGlobs ( originPatterns [ ] string ) ( [ ] glob . Glob , error ) {
allowedOrigins := originPatterns
2023-01-23 10:44:27 -06:00
originGlobs := make ( [ ] glob . Glob , 0 , len ( allowedOrigins ) )
2021-07-01 01:30:09 -05:00
for _ , originPattern := range allowedOrigins {
g , err := glob . Compile ( originPattern )
if err != nil {
return nil , fmt . Errorf ( "error parsing origin pattern: %v" , err )
}
originGlobs = append ( originGlobs , g )
}
return originGlobs , nil
}
2021-05-27 14:03:18 -05:00
func ( cfg * Cfg ) readLiveSettings ( iniFile * ini . File ) error {
section := iniFile . Section ( "live" )
cfg . LiveMaxConnections = section . Key ( "max_connections" ) . MustInt ( 100 )
if cfg . LiveMaxConnections < - 1 {
return fmt . Errorf ( "unexpected value %d for [live] max_connections" , cfg . LiveMaxConnections )
}
2021-06-24 03:07:09 -05:00
cfg . LiveHAEngine = section . Key ( "ha_engine" ) . MustString ( "" )
switch cfg . LiveHAEngine {
case "" , "redis" :
default :
return fmt . Errorf ( "unsupported live HA engine type: %s" , cfg . LiveHAEngine )
}
cfg . LiveHAEngineAddress = section . Key ( "ha_engine_address" ) . MustString ( "127.0.0.1:6379" )
2021-07-01 01:30:09 -05:00
var originPatterns [ ] string
allowedOrigins := section . Key ( "allowed_origins" ) . MustString ( "" )
for _ , originPattern := range strings . Split ( allowedOrigins , "," ) {
originPattern = strings . TrimSpace ( originPattern )
if originPattern == "" {
continue
}
originPatterns = append ( originPatterns , originPattern )
}
_ , err := GetAllowedOriginGlobs ( originPatterns )
if err != nil {
return err
}
cfg . LiveAllowedOrigins = originPatterns
2021-05-27 14:03:18 -05:00
return nil
}