setting.go 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092
  1. // Copyright 2014 Unknwon
  2. // Copyright 2014 Torkel Ödegaard
  3. package setting
  4. import (
  5. "bytes"
  6. "errors"
  7. "fmt"
  8. "net/http"
  9. "net/url"
  10. "os"
  11. "path"
  12. "path/filepath"
  13. "regexp"
  14. "runtime"
  15. "strings"
  16. "time"
  17. "github.com/go-macaron/session"
  18. ini "gopkg.in/ini.v1"
  19. "github.com/grafana/grafana/pkg/infra/log"
  20. "github.com/grafana/grafana/pkg/util"
  21. )
  22. type Scheme string
  23. const (
  24. HTTP Scheme = "http"
  25. HTTPS Scheme = "https"
  26. HTTP2 Scheme = "h2"
  27. SOCKET Scheme = "socket"
  28. DEFAULT_HTTP_ADDR string = "0.0.0.0"
  29. )
  30. const (
  31. DEV = "development"
  32. PROD = "production"
  33. TEST = "test"
  34. APP_NAME = "Grafana"
  35. APP_NAME_ENTERPRISE = "Grafana Enterprise"
  36. )
  37. var (
  38. ERR_TEMPLATE_NAME = "error"
  39. )
  40. var (
  41. // App settings.
  42. Env = DEV
  43. AppUrl string
  44. AppSubUrl string
  45. ServeFromSubPath bool
  46. InstanceName string
  47. // build
  48. BuildVersion string
  49. BuildCommit string
  50. BuildBranch string
  51. BuildStamp int64
  52. IsEnterprise bool
  53. ApplicationName string
  54. // packaging
  55. Packaging = "unknown"
  56. // Paths
  57. HomePath string
  58. PluginsPath string
  59. CustomInitPath = "conf/custom.ini"
  60. // Log settings.
  61. LogConfigs []util.DynMap
  62. // Http server options
  63. Protocol Scheme
  64. Domain string
  65. HttpAddr, HttpPort string
  66. SshPort int
  67. CertFile, KeyFile string
  68. SocketPath string
  69. RouterLogging bool
  70. DataProxyLogging bool
  71. DataProxyTimeout int
  72. StaticRootPath string
  73. EnableGzip bool
  74. EnforceDomain bool
  75. // Security settings.
  76. SecretKey string
  77. DisableGravatar bool
  78. EmailCodeValidMinutes int
  79. DataProxyWhiteList map[string]bool
  80. DisableBruteForceLoginProtection bool
  81. CookieSecure bool
  82. CookieSameSite http.SameSite
  83. AllowEmbedding bool
  84. XSSProtectionHeader bool
  85. ContentTypeProtectionHeader bool
  86. StrictTransportSecurity bool
  87. StrictTransportSecurityMaxAge int
  88. StrictTransportSecurityPreload bool
  89. StrictTransportSecuritySubDomains bool
  90. // Snapshots
  91. ExternalSnapshotUrl string
  92. ExternalSnapshotName string
  93. ExternalEnabled bool
  94. SnapShotRemoveExpired bool
  95. SnapshotPublicMode bool
  96. // Dashboard history
  97. DashboardVersionsToKeep int
  98. // User settings
  99. AllowUserSignUp bool
  100. AllowUserOrgCreate bool
  101. AutoAssignOrg bool
  102. AutoAssignOrgId int
  103. AutoAssignOrgRole string
  104. VerifyEmailEnabled bool
  105. LoginHint string
  106. PasswordHint string
  107. DefaultTheme string
  108. DisableLoginForm bool
  109. DisableSignoutMenu bool
  110. SignoutRedirectUrl string
  111. ExternalUserMngLinkUrl string
  112. ExternalUserMngLinkName string
  113. ExternalUserMngInfo string
  114. OAuthAutoLogin bool
  115. ViewersCanEdit bool
  116. // Http auth
  117. AdminUser string
  118. AdminPassword string
  119. LoginCookieName string
  120. LoginMaxLifetimeDays int
  121. AnonymousEnabled bool
  122. AnonymousOrgName string
  123. AnonymousOrgRole string
  124. // Auth proxy settings
  125. AuthProxyEnabled bool
  126. AuthProxyHeaderName string
  127. AuthProxyHeaderProperty string
  128. AuthProxyAutoSignUp bool
  129. AuthProxyLDAPSyncTtl int
  130. AuthProxyWhitelist string
  131. AuthProxyHeaders map[string]string
  132. // Basic Auth
  133. BasicAuthEnabled bool
  134. // Session settings.
  135. SessionOptions session.Options
  136. SessionConnMaxLifetime int64
  137. // Global setting objects.
  138. Raw *ini.File
  139. ConfRootPath string
  140. IsWindows bool
  141. // for logging purposes
  142. configFiles []string
  143. appliedCommandLineProperties []string
  144. appliedEnvOverrides []string
  145. ReportingEnabled bool
  146. CheckForUpdates bool
  147. GoogleAnalyticsId string
  148. GoogleTagManagerId string
  149. // LDAP
  150. LDAPEnabled bool
  151. LDAPConfigFile string
  152. LDAPSyncCron string
  153. LDAPAllowSignup bool
  154. LDAPActiveSyncEnabled bool
  155. // QUOTA
  156. Quota QuotaSettings
  157. // Alerting
  158. AlertingEnabled bool
  159. ExecuteAlerts bool
  160. AlertingRenderLimit int
  161. AlertingErrorOrTimeout string
  162. AlertingNoDataOrNullValues string
  163. AlertingEvaluationTimeout time.Duration
  164. AlertingNotificationTimeout time.Duration
  165. AlertingMaxAttempts int
  166. // Explore UI
  167. ExploreEnabled bool
  168. // Grafana.NET URL
  169. GrafanaComUrl string
  170. // S3 temp image store
  171. S3TempImageStoreBucketUrl string
  172. S3TempImageStoreAccessKey string
  173. S3TempImageStoreSecretKey string
  174. ImageUploadProvider string
  175. )
  176. // TODO move all global vars to this struct
  177. type Cfg struct {
  178. Raw *ini.File
  179. Logger log.Logger
  180. // HTTP Server Settings
  181. AppUrl string
  182. AppSubUrl string
  183. ServeFromSubPath bool
  184. // Paths
  185. ProvisioningPath string
  186. DataPath string
  187. LogsPath string
  188. // SMTP email settings
  189. Smtp SmtpSettings
  190. // Rendering
  191. ImagesDir string
  192. PhantomDir string
  193. RendererUrl string
  194. RendererCallbackUrl string
  195. RendererLimit int
  196. RendererLimitAlerting int
  197. // Security
  198. DisableBruteForceLoginProtection bool
  199. CookieSecure bool
  200. CookieSameSite http.SameSite
  201. TempDataLifetime time.Duration
  202. MetricsEndpointEnabled bool
  203. MetricsEndpointBasicAuthUsername string
  204. MetricsEndpointBasicAuthPassword string
  205. PluginsEnableAlpha bool
  206. PluginsAppsSkipVerifyTLS bool
  207. DisableSanitizeHtml bool
  208. EnterpriseLicensePath string
  209. // Auth
  210. LoginCookieName string
  211. LoginMaxInactiveLifetimeDays int
  212. LoginMaxLifetimeDays int
  213. TokenRotationIntervalMinutes int
  214. // SAML Auth
  215. SAMLEnabled bool
  216. // Dataproxy
  217. SendUserHeader bool
  218. // DistributedCache
  219. RemoteCacheOptions *RemoteCacheOptions
  220. EditorsCanAdmin bool
  221. ApiKeyMaxSecondsToLive int64
  222. FeatureToggles map[string]bool
  223. }
  224. type CommandLineArgs struct {
  225. Config string
  226. HomePath string
  227. Args []string
  228. }
  229. func init() {
  230. IsWindows = runtime.GOOS == "windows"
  231. }
  232. func parseAppUrlAndSubUrl(section *ini.Section) (string, string, error) {
  233. appUrl, err := valueAsString(section, "root_url", "http://localhost:3000/")
  234. if err != nil {
  235. return "", "", err
  236. }
  237. if appUrl[len(appUrl)-1] != '/' {
  238. appUrl += "/"
  239. }
  240. // Check if has app suburl.
  241. url, err := url.Parse(appUrl)
  242. if err != nil {
  243. log.Fatal(4, "Invalid root_url(%s): %s", appUrl, err)
  244. }
  245. appSubUrl := strings.TrimSuffix(url.Path, "/")
  246. return appUrl, appSubUrl, nil
  247. }
  248. func ToAbsUrl(relativeUrl string) string {
  249. return AppUrl + relativeUrl
  250. }
  251. func shouldRedactKey(s string) bool {
  252. uppercased := strings.ToUpper(s)
  253. return strings.Contains(uppercased, "PASSWORD") || strings.Contains(uppercased, "SECRET") || strings.Contains(uppercased, "PROVIDER_CONFIG")
  254. }
  255. func shouldRedactURLKey(s string) bool {
  256. uppercased := strings.ToUpper(s)
  257. return strings.Contains(uppercased, "DATABASE_URL")
  258. }
  259. func applyEnvVariableOverrides(file *ini.File) error {
  260. appliedEnvOverrides = make([]string, 0)
  261. for _, section := range file.Sections() {
  262. for _, key := range section.Keys() {
  263. sectionName := strings.ToUpper(strings.Replace(section.Name(), ".", "_", -1))
  264. keyName := strings.ToUpper(strings.Replace(key.Name(), ".", "_", -1))
  265. envKey := fmt.Sprintf("GF_%s_%s", sectionName, keyName)
  266. envValue := os.Getenv(envKey)
  267. if len(envValue) > 0 {
  268. key.SetValue(envValue)
  269. if shouldRedactKey(envKey) {
  270. envValue = "*********"
  271. }
  272. if shouldRedactURLKey(envKey) {
  273. u, err := url.Parse(envValue)
  274. if err != nil {
  275. return fmt.Errorf("could not parse environment variable. key: %s, value: %s. error: %v", envKey, envValue, err)
  276. }
  277. ui := u.User
  278. if ui != nil {
  279. _, exists := ui.Password()
  280. if exists {
  281. u.User = url.UserPassword(ui.Username(), "-redacted-")
  282. envValue = u.String()
  283. }
  284. }
  285. }
  286. appliedEnvOverrides = append(appliedEnvOverrides, fmt.Sprintf("%s=%s", envKey, envValue))
  287. }
  288. }
  289. }
  290. return nil
  291. }
  292. func applyCommandLineDefaultProperties(props map[string]string, file *ini.File) {
  293. appliedCommandLineProperties = make([]string, 0)
  294. for _, section := range file.Sections() {
  295. for _, key := range section.Keys() {
  296. keyString := fmt.Sprintf("default.%s.%s", section.Name(), key.Name())
  297. value, exists := props[keyString]
  298. if exists {
  299. key.SetValue(value)
  300. if shouldRedactKey(keyString) {
  301. value = "*********"
  302. }
  303. appliedCommandLineProperties = append(appliedCommandLineProperties, fmt.Sprintf("%s=%s", keyString, value))
  304. }
  305. }
  306. }
  307. }
  308. func applyCommandLineProperties(props map[string]string, file *ini.File) {
  309. for _, section := range file.Sections() {
  310. sectionName := section.Name() + "."
  311. if section.Name() == ini.DEFAULT_SECTION {
  312. sectionName = ""
  313. }
  314. for _, key := range section.Keys() {
  315. keyString := sectionName + key.Name()
  316. value, exists := props[keyString]
  317. if exists {
  318. appliedCommandLineProperties = append(appliedCommandLineProperties, fmt.Sprintf("%s=%s", keyString, value))
  319. key.SetValue(value)
  320. }
  321. }
  322. }
  323. }
  324. func getCommandLineProperties(args []string) map[string]string {
  325. props := make(map[string]string)
  326. for _, arg := range args {
  327. if !strings.HasPrefix(arg, "cfg:") {
  328. continue
  329. }
  330. trimmed := strings.TrimPrefix(arg, "cfg:")
  331. parts := strings.Split(trimmed, "=")
  332. if len(parts) != 2 {
  333. log.Fatal(3, "Invalid command line argument. argument: %v", arg)
  334. return nil
  335. }
  336. props[parts[0]] = parts[1]
  337. }
  338. return props
  339. }
  340. func makeAbsolute(path string, root string) string {
  341. if filepath.IsAbs(path) {
  342. return path
  343. }
  344. return filepath.Join(root, path)
  345. }
  346. func evalEnvVarExpression(value string) string {
  347. regex := regexp.MustCompile(`\${(\w+)}`)
  348. return regex.ReplaceAllStringFunc(value, func(envVar string) string {
  349. envVar = strings.TrimPrefix(envVar, "${")
  350. envVar = strings.TrimSuffix(envVar, "}")
  351. envValue := os.Getenv(envVar)
  352. // if env variable is hostname and it is empty use os.Hostname as default
  353. if envVar == "HOSTNAME" && envValue == "" {
  354. envValue, _ = os.Hostname()
  355. }
  356. return envValue
  357. })
  358. }
  359. func evalConfigValues(file *ini.File) {
  360. for _, section := range file.Sections() {
  361. for _, key := range section.Keys() {
  362. key.SetValue(evalEnvVarExpression(key.Value()))
  363. }
  364. }
  365. }
  366. func loadSpecifedConfigFile(configFile string, masterFile *ini.File) error {
  367. if configFile == "" {
  368. configFile = filepath.Join(HomePath, CustomInitPath)
  369. // return without error if custom file does not exist
  370. if !pathExists(configFile) {
  371. return nil
  372. }
  373. }
  374. userConfig, err := ini.Load(configFile)
  375. if err != nil {
  376. return fmt.Errorf("Failed to parse %v, %v", configFile, err)
  377. }
  378. userConfig.BlockMode = false
  379. for _, section := range userConfig.Sections() {
  380. for _, key := range section.Keys() {
  381. if key.Value() == "" {
  382. continue
  383. }
  384. defaultSec, err := masterFile.GetSection(section.Name())
  385. if err != nil {
  386. defaultSec, _ = masterFile.NewSection(section.Name())
  387. }
  388. defaultKey, err := defaultSec.GetKey(key.Name())
  389. if err != nil {
  390. defaultKey, _ = defaultSec.NewKey(key.Name(), key.Value())
  391. }
  392. defaultKey.SetValue(key.Value())
  393. }
  394. }
  395. configFiles = append(configFiles, configFile)
  396. return nil
  397. }
  398. func (cfg *Cfg) loadConfiguration(args *CommandLineArgs) (*ini.File, error) {
  399. var err error
  400. // load config defaults
  401. defaultConfigFile := path.Join(HomePath, "conf/defaults.ini")
  402. configFiles = append(configFiles, defaultConfigFile)
  403. // check if config file exists
  404. if _, err := os.Stat(defaultConfigFile); os.IsNotExist(err) {
  405. fmt.Println("Grafana-server Init Failed: Could not find config defaults, make sure homepath command line parameter is set or working directory is homepath")
  406. os.Exit(1)
  407. }
  408. // load defaults
  409. parsedFile, err := ini.Load(defaultConfigFile)
  410. if err != nil {
  411. fmt.Println(fmt.Sprintf("Failed to parse defaults.ini, %v", err))
  412. os.Exit(1)
  413. return nil, err
  414. }
  415. parsedFile.BlockMode = false
  416. // command line props
  417. commandLineProps := getCommandLineProperties(args.Args)
  418. // load default overrides
  419. applyCommandLineDefaultProperties(commandLineProps, parsedFile)
  420. // load specified config file
  421. err = loadSpecifedConfigFile(args.Config, parsedFile)
  422. if err != nil {
  423. err2 := cfg.initLogging(parsedFile)
  424. if err2 != nil {
  425. return nil, err2
  426. }
  427. log.Fatal(3, err.Error())
  428. }
  429. // apply environment overrides
  430. err = applyEnvVariableOverrides(parsedFile)
  431. if err != nil {
  432. return nil, err
  433. }
  434. // apply command line overrides
  435. applyCommandLineProperties(commandLineProps, parsedFile)
  436. // evaluate config values containing environment variables
  437. evalConfigValues(parsedFile)
  438. // update data path and logging config
  439. dataPath, err := valueAsString(parsedFile.Section("paths"), "data", "")
  440. if err != nil {
  441. return nil, err
  442. }
  443. cfg.DataPath = makeAbsolute(dataPath, HomePath)
  444. err = cfg.initLogging(parsedFile)
  445. if err != nil {
  446. return nil, err
  447. }
  448. return parsedFile, err
  449. }
  450. func pathExists(path string) bool {
  451. _, err := os.Stat(path)
  452. if err == nil {
  453. return true
  454. }
  455. if os.IsNotExist(err) {
  456. return false
  457. }
  458. return false
  459. }
  460. func setHomePath(args *CommandLineArgs) {
  461. if args.HomePath != "" {
  462. HomePath = args.HomePath
  463. return
  464. }
  465. HomePath, _ = filepath.Abs(".")
  466. // check if homepath is correct
  467. if pathExists(filepath.Join(HomePath, "conf/defaults.ini")) {
  468. return
  469. }
  470. // try down one path
  471. if pathExists(filepath.Join(HomePath, "../conf/defaults.ini")) {
  472. HomePath = filepath.Join(HomePath, "../")
  473. }
  474. }
  475. var skipStaticRootValidation = false
  476. func NewCfg() *Cfg {
  477. return &Cfg{
  478. Logger: log.New("settings"),
  479. Raw: ini.Empty(),
  480. }
  481. }
  482. func (cfg *Cfg) validateStaticRootPath() error {
  483. if skipStaticRootValidation {
  484. return nil
  485. }
  486. if _, err := os.Stat(path.Join(StaticRootPath, "build")); err != nil {
  487. cfg.Logger.Error("Failed to detect generated javascript files in public/build")
  488. }
  489. return nil
  490. }
  491. func (cfg *Cfg) Load(args *CommandLineArgs) error {
  492. setHomePath(args)
  493. iniFile, err := cfg.loadConfiguration(args)
  494. if err != nil {
  495. return err
  496. }
  497. cfg.Raw = iniFile
  498. // Temporary keep global, to make refactor in steps
  499. Raw = cfg.Raw
  500. ApplicationName = APP_NAME
  501. if IsEnterprise {
  502. ApplicationName = APP_NAME_ENTERPRISE
  503. }
  504. Env, err = valueAsString(iniFile.Section(""), "app_mode", "development")
  505. if err != nil {
  506. return err
  507. }
  508. InstanceName, err = valueAsString(iniFile.Section(""), "instance_name", "unknown_instance_name")
  509. if err != nil {
  510. return err
  511. }
  512. plugins, err := valueAsString(iniFile.Section("paths"), "plugins", "")
  513. if err != nil {
  514. return err
  515. }
  516. PluginsPath = makeAbsolute(plugins, HomePath)
  517. Provisioning, err := valueAsString(iniFile.Section("paths"), "provisioning", "")
  518. if err != nil {
  519. return err
  520. }
  521. cfg.ProvisioningPath = makeAbsolute(Provisioning, HomePath)
  522. server := iniFile.Section("server")
  523. AppUrl, AppSubUrl, err = parseAppUrlAndSubUrl(server)
  524. if err != nil {
  525. return err
  526. }
  527. ServeFromSubPath = server.Key("serve_from_sub_path").MustBool(false)
  528. cfg.AppUrl = AppUrl
  529. cfg.AppSubUrl = AppSubUrl
  530. cfg.ServeFromSubPath = ServeFromSubPath
  531. Protocol = HTTP
  532. protocolStr, err := valueAsString(server, "protocol", "http")
  533. if err != nil {
  534. return err
  535. }
  536. if protocolStr == "https" {
  537. Protocol = HTTPS
  538. CertFile = server.Key("cert_file").String()
  539. KeyFile = server.Key("cert_key").String()
  540. }
  541. if protocolStr == "h2" {
  542. Protocol = HTTP2
  543. CertFile = server.Key("cert_file").String()
  544. KeyFile = server.Key("cert_key").String()
  545. }
  546. if protocolStr == "socket" {
  547. Protocol = SOCKET
  548. SocketPath = server.Key("socket").String()
  549. }
  550. Domain, err = valueAsString(server, "domain", "localhost")
  551. if err != nil {
  552. return err
  553. }
  554. HttpAddr, err = valueAsString(server, "http_addr", DEFAULT_HTTP_ADDR)
  555. if err != nil {
  556. return err
  557. }
  558. HttpPort, err = valueAsString(server, "http_port", "3000")
  559. if err != nil {
  560. return err
  561. }
  562. RouterLogging = server.Key("router_logging").MustBool(false)
  563. EnableGzip = server.Key("enable_gzip").MustBool(false)
  564. EnforceDomain = server.Key("enforce_domain").MustBool(false)
  565. staticRoot, err := valueAsString(server, "static_root_path", "")
  566. if err != nil {
  567. return err
  568. }
  569. StaticRootPath = makeAbsolute(staticRoot, HomePath)
  570. if err := cfg.validateStaticRootPath(); err != nil {
  571. return err
  572. }
  573. // read data proxy settings
  574. dataproxy := iniFile.Section("dataproxy")
  575. DataProxyLogging = dataproxy.Key("logging").MustBool(false)
  576. DataProxyTimeout = dataproxy.Key("timeout").MustInt(30)
  577. cfg.SendUserHeader = dataproxy.Key("send_user_header").MustBool(false)
  578. // read security settings
  579. security := iniFile.Section("security")
  580. SecretKey, err = valueAsString(security, "secret_key", "")
  581. if err != nil {
  582. return err
  583. }
  584. DisableGravatar = security.Key("disable_gravatar").MustBool(true)
  585. cfg.DisableBruteForceLoginProtection = security.Key("disable_brute_force_login_protection").MustBool(false)
  586. DisableBruteForceLoginProtection = cfg.DisableBruteForceLoginProtection
  587. CookieSecure = security.Key("cookie_secure").MustBool(false)
  588. cfg.CookieSecure = CookieSecure
  589. samesiteString, err := valueAsString(security, "cookie_samesite", "lax")
  590. if err != nil {
  591. return err
  592. }
  593. validSameSiteValues := map[string]http.SameSite{
  594. "lax": http.SameSiteLaxMode,
  595. "strict": http.SameSiteStrictMode,
  596. "none": http.SameSiteDefaultMode,
  597. }
  598. if samesite, ok := validSameSiteValues[samesiteString]; ok {
  599. CookieSameSite = samesite
  600. cfg.CookieSameSite = CookieSameSite
  601. } else {
  602. CookieSameSite = http.SameSiteLaxMode
  603. cfg.CookieSameSite = CookieSameSite
  604. }
  605. AllowEmbedding = security.Key("allow_embedding").MustBool(false)
  606. ContentTypeProtectionHeader = security.Key("x_content_type_options").MustBool(false)
  607. XSSProtectionHeader = security.Key("x_xss_protection").MustBool(false)
  608. StrictTransportSecurity = security.Key("strict_transport_security").MustBool(false)
  609. StrictTransportSecurityMaxAge = security.Key("strict_transport_security_max_age_seconds").MustInt(86400)
  610. StrictTransportSecurityPreload = security.Key("strict_transport_security_preload").MustBool(false)
  611. StrictTransportSecuritySubDomains = security.Key("strict_transport_security_subdomains").MustBool(false)
  612. // read snapshots settings
  613. snapshots := iniFile.Section("snapshots")
  614. ExternalSnapshotUrl, err = valueAsString(snapshots, "external_snapshot_url", "")
  615. if err != nil {
  616. return err
  617. }
  618. ExternalSnapshotName, err = valueAsString(snapshots, "external_snapshot_name", "")
  619. if err != nil {
  620. return err
  621. }
  622. ExternalEnabled = snapshots.Key("external_enabled").MustBool(true)
  623. SnapShotRemoveExpired = snapshots.Key("snapshot_remove_expired").MustBool(true)
  624. SnapshotPublicMode = snapshots.Key("public_mode").MustBool(false)
  625. // read dashboard settings
  626. dashboards := iniFile.Section("dashboards")
  627. DashboardVersionsToKeep = dashboards.Key("versions_to_keep").MustInt(20)
  628. // read data source proxy white list
  629. DataProxyWhiteList = make(map[string]bool)
  630. securityStr, err := valueAsString(security, "data_source_proxy_whitelist", "")
  631. if err != nil {
  632. return err
  633. }
  634. for _, hostAndIp := range util.SplitString(securityStr) {
  635. DataProxyWhiteList[hostAndIp] = true
  636. }
  637. // admin
  638. AdminUser, err = valueAsString(security, "admin_user", "")
  639. if err != nil {
  640. return err
  641. }
  642. AdminPassword, err = valueAsString(security, "admin_password", "")
  643. if err != nil {
  644. return err
  645. }
  646. // users
  647. users := iniFile.Section("users")
  648. AllowUserSignUp = users.Key("allow_sign_up").MustBool(true)
  649. AllowUserOrgCreate = users.Key("allow_org_create").MustBool(true)
  650. AutoAssignOrg = users.Key("auto_assign_org").MustBool(true)
  651. AutoAssignOrgId = users.Key("auto_assign_org_id").MustInt(1)
  652. AutoAssignOrgRole = users.Key("auto_assign_org_role").In("Editor", []string{"Editor", "Admin", "Viewer"})
  653. VerifyEmailEnabled = users.Key("verify_email_enabled").MustBool(false)
  654. LoginHint, err = valueAsString(users, "login_hint", "")
  655. if err != nil {
  656. return err
  657. }
  658. PasswordHint, err = valueAsString(users, "password_hint", "")
  659. if err != nil {
  660. return err
  661. }
  662. DefaultTheme, err = valueAsString(users, "default_theme", "")
  663. if err != nil {
  664. return err
  665. }
  666. ExternalUserMngLinkUrl, err = valueAsString(users, "external_manage_link_url", "")
  667. if err != nil {
  668. return err
  669. }
  670. ExternalUserMngLinkName, err = valueAsString(users, "external_manage_link_name", "")
  671. if err != nil {
  672. return err
  673. }
  674. ExternalUserMngInfo, err = valueAsString(users, "external_manage_info", "")
  675. if err != nil {
  676. return err
  677. }
  678. ViewersCanEdit = users.Key("viewers_can_edit").MustBool(false)
  679. cfg.EditorsCanAdmin = users.Key("editors_can_admin").MustBool(false)
  680. // auth
  681. auth := iniFile.Section("auth")
  682. LoginCookieName, err = valueAsString(auth, "login_cookie_name", "grafana_session")
  683. cfg.LoginCookieName = LoginCookieName
  684. if err != nil {
  685. return err
  686. }
  687. cfg.LoginMaxInactiveLifetimeDays = auth.Key("login_maximum_inactive_lifetime_days").MustInt(7)
  688. LoginMaxLifetimeDays = auth.Key("login_maximum_lifetime_days").MustInt(30)
  689. cfg.LoginMaxLifetimeDays = LoginMaxLifetimeDays
  690. cfg.ApiKeyMaxSecondsToLive = auth.Key("api_key_max_seconds_to_live").MustInt64(-1)
  691. cfg.TokenRotationIntervalMinutes = auth.Key("token_rotation_interval_minutes").MustInt(10)
  692. if cfg.TokenRotationIntervalMinutes < 2 {
  693. cfg.TokenRotationIntervalMinutes = 2
  694. }
  695. DisableLoginForm = auth.Key("disable_login_form").MustBool(false)
  696. DisableSignoutMenu = auth.Key("disable_signout_menu").MustBool(false)
  697. OAuthAutoLogin = auth.Key("oauth_auto_login").MustBool(false)
  698. SignoutRedirectUrl, err = valueAsString(auth, "signout_redirect_url", "")
  699. if err != nil {
  700. return err
  701. }
  702. // SAML auth
  703. cfg.SAMLEnabled = iniFile.Section("auth.saml").Key("enabled").MustBool(false)
  704. // anonymous access
  705. AnonymousEnabled = iniFile.Section("auth.anonymous").Key("enabled").MustBool(false)
  706. AnonymousOrgName, err = valueAsString(iniFile.Section("auth.anonymous"), "org_name", "")
  707. if err != nil {
  708. return err
  709. }
  710. AnonymousOrgRole, err = valueAsString(iniFile.Section("auth.anonymous"), "org_role", "")
  711. if err != nil {
  712. return err
  713. }
  714. // auth proxy
  715. authProxy := iniFile.Section("auth.proxy")
  716. AuthProxyEnabled = authProxy.Key("enabled").MustBool(false)
  717. AuthProxyHeaderName, err = valueAsString(authProxy, "header_name", "")
  718. if err != nil {
  719. return err
  720. }
  721. AuthProxyHeaderProperty, err = valueAsString(authProxy, "header_property", "")
  722. if err != nil {
  723. return err
  724. }
  725. AuthProxyAutoSignUp = authProxy.Key("auto_sign_up").MustBool(true)
  726. AuthProxyLDAPSyncTtl = authProxy.Key("ldap_sync_ttl").MustInt()
  727. AuthProxyWhitelist, err = valueAsString(authProxy, "whitelist", "")
  728. if err != nil {
  729. return err
  730. }
  731. AuthProxyHeaders = make(map[string]string)
  732. headers, err := valueAsString(authProxy, "headers", "")
  733. if err != nil {
  734. return err
  735. }
  736. for _, propertyAndHeader := range util.SplitString(headers) {
  737. split := strings.SplitN(propertyAndHeader, ":", 2)
  738. if len(split) == 2 {
  739. AuthProxyHeaders[split[0]] = split[1]
  740. }
  741. }
  742. // basic auth
  743. authBasic := iniFile.Section("auth.basic")
  744. BasicAuthEnabled = authBasic.Key("enabled").MustBool(true)
  745. // Rendering
  746. renderSec := iniFile.Section("rendering")
  747. cfg.RendererUrl, err = valueAsString(renderSec, "server_url", "")
  748. if err != nil {
  749. return err
  750. }
  751. cfg.RendererCallbackUrl, err = valueAsString(renderSec, "callback_url", "")
  752. if err != nil {
  753. return err
  754. }
  755. if cfg.RendererCallbackUrl == "" {
  756. cfg.RendererCallbackUrl = AppUrl
  757. } else {
  758. if cfg.RendererCallbackUrl[len(cfg.RendererCallbackUrl)-1] != '/' {
  759. cfg.RendererCallbackUrl += "/"
  760. }
  761. _, err := url.Parse(cfg.RendererCallbackUrl)
  762. if err != nil {
  763. log.Fatal(4, "Invalid callback_url(%s): %s", cfg.RendererCallbackUrl, err)
  764. }
  765. }
  766. cfg.ImagesDir = filepath.Join(cfg.DataPath, "png")
  767. cfg.PhantomDir = filepath.Join(HomePath, "tools/phantomjs")
  768. cfg.TempDataLifetime = iniFile.Section("paths").Key("temp_data_lifetime").MustDuration(time.Second * 3600 * 24)
  769. cfg.MetricsEndpointEnabled = iniFile.Section("metrics").Key("enabled").MustBool(true)
  770. cfg.MetricsEndpointBasicAuthUsername, err = valueAsString(iniFile.Section("metrics"), "basic_auth_username", "")
  771. if err != nil {
  772. return err
  773. }
  774. cfg.MetricsEndpointBasicAuthPassword, err = valueAsString(iniFile.Section("metrics"), "basic_auth_password", "")
  775. if err != nil {
  776. return err
  777. }
  778. analytics := iniFile.Section("analytics")
  779. ReportingEnabled = analytics.Key("reporting_enabled").MustBool(true)
  780. CheckForUpdates = analytics.Key("check_for_updates").MustBool(true)
  781. GoogleAnalyticsId = analytics.Key("google_analytics_ua_id").String()
  782. GoogleTagManagerId = analytics.Key("google_tag_manager_id").String()
  783. alerting := iniFile.Section("alerting")
  784. AlertingEnabled = alerting.Key("enabled").MustBool(true)
  785. ExecuteAlerts = alerting.Key("execute_alerts").MustBool(true)
  786. AlertingRenderLimit = alerting.Key("concurrent_render_limit").MustInt(5)
  787. AlertingErrorOrTimeout, err = valueAsString(alerting, "error_or_timeout", "alerting")
  788. if err != nil {
  789. return err
  790. }
  791. AlertingNoDataOrNullValues, err = valueAsString(alerting, "nodata_or_nullvalues", "no_data")
  792. if err != nil {
  793. return err
  794. }
  795. evaluationTimeoutSeconds := alerting.Key("evaluation_timeout_seconds").MustInt64(30)
  796. AlertingEvaluationTimeout = time.Second * time.Duration(evaluationTimeoutSeconds)
  797. notificationTimeoutSeconds := alerting.Key("notification_timeout_seconds").MustInt64(30)
  798. AlertingNotificationTimeout = time.Second * time.Duration(notificationTimeoutSeconds)
  799. AlertingMaxAttempts = alerting.Key("max_attempts").MustInt(3)
  800. explore := iniFile.Section("explore")
  801. ExploreEnabled = explore.Key("enabled").MustBool(true)
  802. panelsSection := iniFile.Section("panels")
  803. cfg.DisableSanitizeHtml = panelsSection.Key("disable_sanitize_html").MustBool(false)
  804. pluginsSection := iniFile.Section("plugins")
  805. cfg.PluginsEnableAlpha = pluginsSection.Key("enable_alpha").MustBool(false)
  806. cfg.PluginsAppsSkipVerifyTLS = pluginsSection.Key("app_tls_skip_verify_insecure").MustBool(false)
  807. // Read and populate feature toggles list
  808. featureTogglesSection := iniFile.Section("feature_toggles")
  809. cfg.FeatureToggles = make(map[string]bool)
  810. featuresTogglesStr, err := valueAsString(featureTogglesSection, "enable", "")
  811. if err != nil {
  812. return err
  813. }
  814. for _, feature := range util.SplitString(featuresTogglesStr) {
  815. cfg.FeatureToggles[feature] = true
  816. }
  817. // check old location for this option
  818. if panelsSection.Key("enable_alpha").MustBool(false) {
  819. cfg.PluginsEnableAlpha = true
  820. }
  821. cfg.readLDAPConfig()
  822. cfg.readSessionConfig()
  823. cfg.readSmtpSettings()
  824. cfg.readQuotaSettings()
  825. if VerifyEmailEnabled && !cfg.Smtp.Enabled {
  826. log.Warn("require_email_validation is enabled but smtp is disabled")
  827. }
  828. // check old key name
  829. GrafanaComUrl, err = valueAsString(iniFile.Section("grafana_net"), "url", "")
  830. if err != nil {
  831. return err
  832. }
  833. if GrafanaComUrl == "" {
  834. GrafanaComUrl, err = valueAsString(iniFile.Section("grafana_com"), "url", "https://grafana.com")
  835. if err != nil {
  836. return err
  837. }
  838. }
  839. imageUploadingSection := iniFile.Section("external_image_storage")
  840. ImageUploadProvider, err = valueAsString(imageUploadingSection, "provider", "")
  841. if err != nil {
  842. return err
  843. }
  844. enterprise := iniFile.Section("enterprise")
  845. cfg.EnterpriseLicensePath, err = valueAsString(enterprise, "license_path", filepath.Join(cfg.DataPath, "license.jwt"))
  846. if err != nil {
  847. return err
  848. }
  849. cacheServer := iniFile.Section("remote_cache")
  850. dbName, err := valueAsString(cacheServer, "type", "database")
  851. if err != nil {
  852. return err
  853. }
  854. connStr, err := valueAsString(cacheServer, "connstr", "")
  855. if err != nil {
  856. return err
  857. }
  858. cfg.RemoteCacheOptions = &RemoteCacheOptions{
  859. Name: dbName,
  860. ConnStr: connStr,
  861. }
  862. return nil
  863. }
  864. func valueAsString(section *ini.Section, keyName string, defaultValue string) (value string, err error) {
  865. defer func() {
  866. if err_ := recover(); err_ != nil {
  867. err = errors.New("Invalid value for key '" + keyName + "' in configuration file")
  868. }
  869. }()
  870. return section.Key(keyName).MustString(defaultValue), nil
  871. }
  872. type RemoteCacheOptions struct {
  873. Name string
  874. ConnStr string
  875. }
  876. func (cfg *Cfg) readLDAPConfig() {
  877. ldapSec := cfg.Raw.Section("auth.ldap")
  878. LDAPConfigFile = ldapSec.Key("config_file").String()
  879. LDAPSyncCron = ldapSec.Key("sync_cron").String()
  880. LDAPEnabled = ldapSec.Key("enabled").MustBool(false)
  881. LDAPActiveSyncEnabled = ldapSec.Key("active_sync_enabled").MustBool(false)
  882. LDAPAllowSignup = ldapSec.Key("allow_sign_up").MustBool(true)
  883. }
  884. func (cfg *Cfg) readSessionConfig() {
  885. sec, _ := cfg.Raw.GetSection("session")
  886. if sec != nil {
  887. cfg.Logger.Warn(
  888. "[Removed] Session setting was removed in v6.2, use remote_cache option instead",
  889. )
  890. }
  891. }
  892. func (cfg *Cfg) initLogging(file *ini.File) error {
  893. logModeStr, err := valueAsString(file.Section("log"), "mode", "console")
  894. if err != nil {
  895. return err
  896. }
  897. // split on comma
  898. logModes := strings.Split(logModeStr, ",")
  899. // also try space
  900. if len(logModes) == 1 {
  901. logModes = strings.Split(logModeStr, " ")
  902. }
  903. logsPath, err := valueAsString(file.Section("paths"), "logs", "")
  904. if err != nil {
  905. return err
  906. }
  907. cfg.LogsPath = makeAbsolute(logsPath, HomePath)
  908. log.ReadLoggingConfig(logModes, cfg.LogsPath, file)
  909. return nil
  910. }
  911. func (cfg *Cfg) LogConfigSources() {
  912. var text bytes.Buffer
  913. for _, file := range configFiles {
  914. cfg.Logger.Info("Config loaded from", "file", file)
  915. }
  916. if len(appliedCommandLineProperties) > 0 {
  917. for _, prop := range appliedCommandLineProperties {
  918. cfg.Logger.Info("Config overridden from command line", "arg", prop)
  919. }
  920. }
  921. if len(appliedEnvOverrides) > 0 {
  922. text.WriteString("\tEnvironment variables used:\n")
  923. for _, prop := range appliedEnvOverrides {
  924. cfg.Logger.Info("Config overridden from Environment variable", "var", prop)
  925. }
  926. }
  927. cfg.Logger.Info("Path Home", "path", HomePath)
  928. cfg.Logger.Info("Path Data", "path", cfg.DataPath)
  929. cfg.Logger.Info("Path Logs", "path", cfg.LogsPath)
  930. cfg.Logger.Info("Path Plugins", "path", PluginsPath)
  931. cfg.Logger.Info("Path Provisioning", "path", cfg.ProvisioningPath)
  932. cfg.Logger.Info("App mode " + Env)
  933. }