setting.go 28 KB

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