setting.go 27 KB

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