setting.go 27 KB

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