setting.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777
  1. // Copyright 2014 Unknwon
  2. // Copyright 2014 Torkel Ödegaard
  3. package setting
  4. import (
  5. "bytes"
  6. "fmt"
  7. "net/url"
  8. "os"
  9. "path"
  10. "path/filepath"
  11. "regexp"
  12. "runtime"
  13. "strings"
  14. "gopkg.in/ini.v1"
  15. "github.com/go-macaron/session"
  16. "time"
  17. "github.com/grafana/grafana/pkg/log"
  18. "github.com/grafana/grafana/pkg/util"
  19. )
  20. type Scheme string
  21. const (
  22. HTTP Scheme = "http"
  23. HTTPS Scheme = "https"
  24. SOCKET Scheme = "socket"
  25. DEFAULT_HTTP_ADDR string = "0.0.0.0"
  26. )
  27. const (
  28. DEV string = "development"
  29. PROD string = "production"
  30. TEST string = "test"
  31. )
  32. var (
  33. // App settings.
  34. Env = DEV
  35. AppUrl string
  36. AppSubUrl string
  37. InstanceName string
  38. // build
  39. BuildVersion string
  40. BuildCommit string
  41. BuildStamp int64
  42. IsEnterprise bool
  43. ApplicationName string
  44. // Paths
  45. HomePath string
  46. PluginsPath string
  47. CustomInitPath = "conf/custom.ini"
  48. // Log settings.
  49. LogConfigs []util.DynMap
  50. // Http server options
  51. Protocol Scheme
  52. Domain string
  53. HttpAddr, HttpPort string
  54. SshPort int
  55. CertFile, KeyFile string
  56. SocketPath string
  57. RouterLogging bool
  58. DataProxyLogging bool
  59. StaticRootPath string
  60. EnableGzip bool
  61. EnforceDomain bool
  62. // Security settings.
  63. SecretKey string
  64. LogInRememberDays int
  65. CookieUserName string
  66. CookieRememberName string
  67. DisableGravatar bool
  68. EmailCodeValidMinutes int
  69. DataProxyWhiteList map[string]bool
  70. DisableBruteForceLoginProtection bool
  71. // Snapshots
  72. ExternalSnapshotUrl string
  73. ExternalSnapshotName string
  74. ExternalEnabled bool
  75. SnapShotRemoveExpired bool
  76. // Dashboard history
  77. DashboardVersionsToKeep int
  78. // User settings
  79. AllowUserSignUp bool
  80. AllowUserOrgCreate bool
  81. AutoAssignOrg bool
  82. AutoAssignOrgId int
  83. AutoAssignOrgRole string
  84. VerifyEmailEnabled bool
  85. LoginHint string
  86. DefaultTheme string
  87. DisableLoginForm bool
  88. DisableSignoutMenu bool
  89. SignoutRedirectUrl string
  90. ExternalUserMngLinkUrl string
  91. ExternalUserMngLinkName string
  92. ExternalUserMngInfo string
  93. ViewersCanEdit bool
  94. // Http auth
  95. AdminUser string
  96. AdminPassword string
  97. AnonymousEnabled bool
  98. AnonymousOrgName string
  99. AnonymousOrgRole string
  100. // Auth proxy settings
  101. AuthProxyEnabled bool
  102. AuthProxyHeaderName string
  103. AuthProxyHeaderProperty string
  104. AuthProxyAutoSignUp bool
  105. AuthProxyLdapSyncTtl int
  106. AuthProxyWhitelist string
  107. AuthProxyHeaders map[string]string
  108. // Basic Auth
  109. BasicAuthEnabled bool
  110. // Plugin settings
  111. PluginAppsSkipVerifyTLS bool
  112. // Session settings.
  113. SessionOptions session.Options
  114. SessionConnMaxLifetime int64
  115. // Global setting objects.
  116. Raw *ini.File
  117. ConfRootPath string
  118. IsWindows bool
  119. // for logging purposes
  120. configFiles []string
  121. appliedCommandLineProperties []string
  122. appliedEnvOverrides []string
  123. ReportingEnabled bool
  124. CheckForUpdates bool
  125. GoogleAnalyticsId string
  126. GoogleTagManagerId string
  127. // LDAP
  128. LdapEnabled bool
  129. LdapConfigFile string
  130. LdapAllowSignup = true
  131. // QUOTA
  132. Quota QuotaSettings
  133. // Alerting
  134. AlertingEnabled bool
  135. ExecuteAlerts bool
  136. AlertingRenderLimit int
  137. AlertingErrorOrTimeout string
  138. AlertingNoDataOrNullValues string
  139. // Explore UI
  140. ExploreEnabled bool
  141. // logger
  142. logger log.Logger
  143. // Grafana.NET URL
  144. GrafanaComUrl string
  145. // S3 temp image store
  146. S3TempImageStoreBucketUrl string
  147. S3TempImageStoreAccessKey string
  148. S3TempImageStoreSecretKey string
  149. ImageUploadProvider string
  150. )
  151. // TODO move all global vars to this struct
  152. type Cfg struct {
  153. Raw *ini.File
  154. // HTTP Server Settings
  155. AppUrl string
  156. AppSubUrl string
  157. // Paths
  158. ProvisioningPath string
  159. DataPath string
  160. LogsPath string
  161. // SMTP email settings
  162. Smtp SmtpSettings
  163. // Rendering
  164. ImagesDir string
  165. PhantomDir string
  166. RendererUrl string
  167. RendererCallbackUrl string
  168. RendererLimit int
  169. RendererLimitAlerting int
  170. DisableBruteForceLoginProtection bool
  171. TempDataLifetime time.Duration
  172. MetricsEndpointEnabled bool
  173. }
  174. type CommandLineArgs struct {
  175. Config string
  176. HomePath string
  177. Args []string
  178. }
  179. func init() {
  180. IsWindows = runtime.GOOS == "windows"
  181. logger = log.New("settings")
  182. }
  183. func parseAppUrlAndSubUrl(section *ini.Section) (string, string) {
  184. appUrl := section.Key("root_url").MustString("http://localhost:3000/")
  185. if appUrl[len(appUrl)-1] != '/' {
  186. appUrl += "/"
  187. }
  188. // Check if has app suburl.
  189. url, err := url.Parse(appUrl)
  190. if err != nil {
  191. log.Fatal(4, "Invalid root_url(%s): %s", appUrl, err)
  192. }
  193. appSubUrl := strings.TrimSuffix(url.Path, "/")
  194. return appUrl, appSubUrl
  195. }
  196. func ToAbsUrl(relativeUrl string) string {
  197. return AppUrl + relativeUrl
  198. }
  199. func shouldRedactKey(s string) bool {
  200. uppercased := strings.ToUpper(s)
  201. return strings.Contains(uppercased, "PASSWORD") || strings.Contains(uppercased, "SECRET") || strings.Contains(uppercased, "PROVIDER_CONFIG")
  202. }
  203. func shouldRedactURLKey(s string) bool {
  204. uppercased := strings.ToUpper(s)
  205. return strings.Contains(uppercased, "DATABASE_URL")
  206. }
  207. func applyEnvVariableOverrides(file *ini.File) error {
  208. appliedEnvOverrides = make([]string, 0)
  209. for _, section := range file.Sections() {
  210. for _, key := range section.Keys() {
  211. sectionName := strings.ToUpper(strings.Replace(section.Name(), ".", "_", -1))
  212. keyName := strings.ToUpper(strings.Replace(key.Name(), ".", "_", -1))
  213. envKey := fmt.Sprintf("GF_%s_%s", sectionName, keyName)
  214. envValue := os.Getenv(envKey)
  215. if len(envValue) > 0 {
  216. key.SetValue(envValue)
  217. if shouldRedactKey(envKey) {
  218. envValue = "*********"
  219. }
  220. if shouldRedactURLKey(envKey) {
  221. u, err := url.Parse(envValue)
  222. if err != nil {
  223. return fmt.Errorf("could not parse environment variable. key: %s, value: %s. error: %v", envKey, envValue, err)
  224. }
  225. ui := u.User
  226. if ui != nil {
  227. _, exists := ui.Password()
  228. if exists {
  229. u.User = url.UserPassword(ui.Username(), "-redacted-")
  230. envValue = u.String()
  231. }
  232. }
  233. }
  234. appliedEnvOverrides = append(appliedEnvOverrides, fmt.Sprintf("%s=%s", envKey, envValue))
  235. }
  236. }
  237. }
  238. return nil
  239. }
  240. func applyCommandLineDefaultProperties(props map[string]string, file *ini.File) {
  241. appliedCommandLineProperties = make([]string, 0)
  242. for _, section := range file.Sections() {
  243. for _, key := range section.Keys() {
  244. keyString := fmt.Sprintf("default.%s.%s", section.Name(), key.Name())
  245. value, exists := props[keyString]
  246. if exists {
  247. key.SetValue(value)
  248. if shouldRedactKey(keyString) {
  249. value = "*********"
  250. }
  251. appliedCommandLineProperties = append(appliedCommandLineProperties, fmt.Sprintf("%s=%s", keyString, value))
  252. }
  253. }
  254. }
  255. }
  256. func applyCommandLineProperties(props map[string]string, file *ini.File) {
  257. for _, section := range file.Sections() {
  258. sectionName := section.Name() + "."
  259. if section.Name() == ini.DEFAULT_SECTION {
  260. sectionName = ""
  261. }
  262. for _, key := range section.Keys() {
  263. keyString := sectionName + key.Name()
  264. value, exists := props[keyString]
  265. if exists {
  266. appliedCommandLineProperties = append(appliedCommandLineProperties, fmt.Sprintf("%s=%s", keyString, value))
  267. key.SetValue(value)
  268. }
  269. }
  270. }
  271. }
  272. func getCommandLineProperties(args []string) map[string]string {
  273. props := make(map[string]string)
  274. for _, arg := range args {
  275. if !strings.HasPrefix(arg, "cfg:") {
  276. continue
  277. }
  278. trimmed := strings.TrimPrefix(arg, "cfg:")
  279. parts := strings.Split(trimmed, "=")
  280. if len(parts) != 2 {
  281. log.Fatal(3, "Invalid command line argument. argument: %v", arg)
  282. return nil
  283. }
  284. props[parts[0]] = parts[1]
  285. }
  286. return props
  287. }
  288. func makeAbsolute(path string, root string) string {
  289. if filepath.IsAbs(path) {
  290. return path
  291. }
  292. return filepath.Join(root, path)
  293. }
  294. func evalEnvVarExpression(value string) string {
  295. regex := regexp.MustCompile(`\${(\w+)}`)
  296. return regex.ReplaceAllStringFunc(value, func(envVar string) string {
  297. envVar = strings.TrimPrefix(envVar, "${")
  298. envVar = strings.TrimSuffix(envVar, "}")
  299. envValue := os.Getenv(envVar)
  300. // if env variable is hostname and it is empty use os.Hostname as default
  301. if envVar == "HOSTNAME" && envValue == "" {
  302. envValue, _ = os.Hostname()
  303. }
  304. return envValue
  305. })
  306. }
  307. func evalConfigValues(file *ini.File) {
  308. for _, section := range file.Sections() {
  309. for _, key := range section.Keys() {
  310. key.SetValue(evalEnvVarExpression(key.Value()))
  311. }
  312. }
  313. }
  314. func loadSpecifedConfigFile(configFile string, masterFile *ini.File) error {
  315. if configFile == "" {
  316. configFile = filepath.Join(HomePath, CustomInitPath)
  317. // return without error if custom file does not exist
  318. if !pathExists(configFile) {
  319. return nil
  320. }
  321. }
  322. userConfig, err := ini.Load(configFile)
  323. if err != nil {
  324. return fmt.Errorf("Failed to parse %v, %v", configFile, err)
  325. }
  326. userConfig.BlockMode = false
  327. for _, section := range userConfig.Sections() {
  328. for _, key := range section.Keys() {
  329. if key.Value() == "" {
  330. continue
  331. }
  332. defaultSec, err := masterFile.GetSection(section.Name())
  333. if err != nil {
  334. defaultSec, _ = masterFile.NewSection(section.Name())
  335. }
  336. defaultKey, err := defaultSec.GetKey(key.Name())
  337. if err != nil {
  338. defaultKey, _ = defaultSec.NewKey(key.Name(), key.Value())
  339. }
  340. defaultKey.SetValue(key.Value())
  341. }
  342. }
  343. configFiles = append(configFiles, configFile)
  344. return nil
  345. }
  346. func (cfg *Cfg) loadConfiguration(args *CommandLineArgs) (*ini.File, error) {
  347. var err error
  348. // load config defaults
  349. defaultConfigFile := path.Join(HomePath, "conf/defaults.ini")
  350. configFiles = append(configFiles, defaultConfigFile)
  351. // check if config file exists
  352. if _, err := os.Stat(defaultConfigFile); os.IsNotExist(err) {
  353. fmt.Println("Grafana-server Init Failed: Could not find config defaults, make sure homepath command line parameter is set or working directory is homepath")
  354. os.Exit(1)
  355. }
  356. // load defaults
  357. parsedFile, err := ini.Load(defaultConfigFile)
  358. if err != nil {
  359. fmt.Println(fmt.Sprintf("Failed to parse defaults.ini, %v", err))
  360. os.Exit(1)
  361. return nil, err
  362. }
  363. parsedFile.BlockMode = false
  364. // command line props
  365. commandLineProps := getCommandLineProperties(args.Args)
  366. // load default overrides
  367. applyCommandLineDefaultProperties(commandLineProps, parsedFile)
  368. // load specified config file
  369. err = loadSpecifedConfigFile(args.Config, parsedFile)
  370. if err != nil {
  371. cfg.initLogging(parsedFile)
  372. log.Fatal(3, err.Error())
  373. }
  374. // apply environment overrides
  375. err = applyEnvVariableOverrides(parsedFile)
  376. if err != nil {
  377. return nil, err
  378. }
  379. // apply command line overrides
  380. applyCommandLineProperties(commandLineProps, parsedFile)
  381. // evaluate config values containing environment variables
  382. evalConfigValues(parsedFile)
  383. // update data path and logging config
  384. cfg.DataPath = makeAbsolute(parsedFile.Section("paths").Key("data").String(), HomePath)
  385. cfg.initLogging(parsedFile)
  386. return parsedFile, err
  387. }
  388. func pathExists(path string) bool {
  389. _, err := os.Stat(path)
  390. if err == nil {
  391. return true
  392. }
  393. if os.IsNotExist(err) {
  394. return false
  395. }
  396. return false
  397. }
  398. func setHomePath(args *CommandLineArgs) {
  399. if args.HomePath != "" {
  400. HomePath = args.HomePath
  401. return
  402. }
  403. HomePath, _ = filepath.Abs(".")
  404. // check if homepath is correct
  405. if pathExists(filepath.Join(HomePath, "conf/defaults.ini")) {
  406. return
  407. }
  408. // try down one path
  409. if pathExists(filepath.Join(HomePath, "../conf/defaults.ini")) {
  410. HomePath = filepath.Join(HomePath, "../")
  411. }
  412. }
  413. var skipStaticRootValidation = false
  414. func validateStaticRootPath() error {
  415. if skipStaticRootValidation {
  416. return nil
  417. }
  418. if _, err := os.Stat(path.Join(StaticRootPath, "build")); err != nil {
  419. logger.Error("Failed to detect generated javascript files in public/build")
  420. }
  421. return nil
  422. }
  423. func NewCfg() *Cfg {
  424. return &Cfg{
  425. Raw: ini.Empty(),
  426. }
  427. }
  428. func (cfg *Cfg) Load(args *CommandLineArgs) error {
  429. setHomePath(args)
  430. iniFile, err := cfg.loadConfiguration(args)
  431. if err != nil {
  432. return err
  433. }
  434. cfg.Raw = iniFile
  435. // Temporary keep global, to make refactor in steps
  436. Raw = cfg.Raw
  437. ApplicationName = "Grafana"
  438. if IsEnterprise {
  439. ApplicationName += " Enterprise"
  440. }
  441. Env = iniFile.Section("").Key("app_mode").MustString("development")
  442. InstanceName = iniFile.Section("").Key("instance_name").MustString("unknown_instance_name")
  443. PluginsPath = makeAbsolute(iniFile.Section("paths").Key("plugins").String(), HomePath)
  444. cfg.ProvisioningPath = makeAbsolute(iniFile.Section("paths").Key("provisioning").String(), HomePath)
  445. server := iniFile.Section("server")
  446. AppUrl, AppSubUrl = parseAppUrlAndSubUrl(server)
  447. cfg.AppUrl = AppUrl
  448. cfg.AppSubUrl = AppSubUrl
  449. Protocol = HTTP
  450. if server.Key("protocol").MustString("http") == "https" {
  451. Protocol = HTTPS
  452. CertFile = server.Key("cert_file").String()
  453. KeyFile = server.Key("cert_key").String()
  454. }
  455. if server.Key("protocol").MustString("http") == "socket" {
  456. Protocol = SOCKET
  457. SocketPath = server.Key("socket").String()
  458. }
  459. Domain = server.Key("domain").MustString("localhost")
  460. HttpAddr = server.Key("http_addr").MustString(DEFAULT_HTTP_ADDR)
  461. HttpPort = server.Key("http_port").MustString("3000")
  462. RouterLogging = server.Key("router_logging").MustBool(false)
  463. EnableGzip = server.Key("enable_gzip").MustBool(false)
  464. EnforceDomain = server.Key("enforce_domain").MustBool(false)
  465. StaticRootPath = makeAbsolute(server.Key("static_root_path").String(), HomePath)
  466. if err := validateStaticRootPath(); err != nil {
  467. return err
  468. }
  469. // read data proxy settings
  470. dataproxy := iniFile.Section("dataproxy")
  471. DataProxyLogging = dataproxy.Key("logging").MustBool(false)
  472. // read security settings
  473. security := iniFile.Section("security")
  474. SecretKey = security.Key("secret_key").String()
  475. LogInRememberDays = security.Key("login_remember_days").MustInt()
  476. CookieUserName = security.Key("cookie_username").String()
  477. CookieRememberName = security.Key("cookie_remember_name").String()
  478. DisableGravatar = security.Key("disable_gravatar").MustBool(true)
  479. cfg.DisableBruteForceLoginProtection = security.Key("disable_brute_force_login_protection").MustBool(false)
  480. DisableBruteForceLoginProtection = cfg.DisableBruteForceLoginProtection
  481. // read snapshots settings
  482. snapshots := iniFile.Section("snapshots")
  483. ExternalSnapshotUrl = snapshots.Key("external_snapshot_url").String()
  484. ExternalSnapshotName = snapshots.Key("external_snapshot_name").String()
  485. ExternalEnabled = snapshots.Key("external_enabled").MustBool(true)
  486. SnapShotRemoveExpired = snapshots.Key("snapshot_remove_expired").MustBool(true)
  487. // read dashboard settings
  488. dashboards := iniFile.Section("dashboards")
  489. DashboardVersionsToKeep = dashboards.Key("versions_to_keep").MustInt(20)
  490. // read data source proxy white list
  491. DataProxyWhiteList = make(map[string]bool)
  492. for _, hostAndIp := range util.SplitString(security.Key("data_source_proxy_whitelist").String()) {
  493. DataProxyWhiteList[hostAndIp] = true
  494. }
  495. // admin
  496. AdminUser = security.Key("admin_user").String()
  497. AdminPassword = security.Key("admin_password").String()
  498. users := iniFile.Section("users")
  499. AllowUserSignUp = users.Key("allow_sign_up").MustBool(true)
  500. AllowUserOrgCreate = users.Key("allow_org_create").MustBool(true)
  501. AutoAssignOrg = users.Key("auto_assign_org").MustBool(true)
  502. AutoAssignOrgId = users.Key("auto_assign_org_id").MustInt(1)
  503. AutoAssignOrgRole = users.Key("auto_assign_org_role").In("Editor", []string{"Editor", "Admin", "Viewer"})
  504. VerifyEmailEnabled = users.Key("verify_email_enabled").MustBool(false)
  505. LoginHint = users.Key("login_hint").String()
  506. DefaultTheme = users.Key("default_theme").String()
  507. ExternalUserMngLinkUrl = users.Key("external_manage_link_url").String()
  508. ExternalUserMngLinkName = users.Key("external_manage_link_name").String()
  509. ExternalUserMngInfo = users.Key("external_manage_info").String()
  510. ViewersCanEdit = users.Key("viewers_can_edit").MustBool(false)
  511. // auth
  512. auth := iniFile.Section("auth")
  513. DisableLoginForm = auth.Key("disable_login_form").MustBool(false)
  514. DisableSignoutMenu = auth.Key("disable_signout_menu").MustBool(false)
  515. SignoutRedirectUrl = auth.Key("signout_redirect_url").String()
  516. // anonymous access
  517. AnonymousEnabled = iniFile.Section("auth.anonymous").Key("enabled").MustBool(false)
  518. AnonymousOrgName = iniFile.Section("auth.anonymous").Key("org_name").String()
  519. AnonymousOrgRole = iniFile.Section("auth.anonymous").Key("org_role").String()
  520. // auth proxy
  521. authProxy := iniFile.Section("auth.proxy")
  522. AuthProxyEnabled = authProxy.Key("enabled").MustBool(false)
  523. AuthProxyHeaderName = authProxy.Key("header_name").String()
  524. AuthProxyHeaderProperty = authProxy.Key("header_property").String()
  525. AuthProxyAutoSignUp = authProxy.Key("auto_sign_up").MustBool(true)
  526. AuthProxyLdapSyncTtl = authProxy.Key("ldap_sync_ttl").MustInt()
  527. AuthProxyWhitelist = authProxy.Key("whitelist").String()
  528. AuthProxyHeaders = make(map[string]string)
  529. for _, propertyAndHeader := range util.SplitString(authProxy.Key("headers").String()) {
  530. split := strings.SplitN(propertyAndHeader, ":", 2)
  531. if len(split) == 2 {
  532. AuthProxyHeaders[split[0]] = split[1]
  533. }
  534. }
  535. // basic auth
  536. authBasic := iniFile.Section("auth.basic")
  537. BasicAuthEnabled = authBasic.Key("enabled").MustBool(true)
  538. // global plugin settings
  539. PluginAppsSkipVerifyTLS = iniFile.Section("plugins").Key("app_tls_skip_verify_insecure").MustBool(false)
  540. // Rendering
  541. renderSec := iniFile.Section("rendering")
  542. cfg.RendererUrl = renderSec.Key("server_url").String()
  543. cfg.RendererCallbackUrl = renderSec.Key("callback_url").String()
  544. if cfg.RendererCallbackUrl == "" {
  545. cfg.RendererCallbackUrl = AppUrl
  546. } else {
  547. if cfg.RendererCallbackUrl[len(cfg.RendererCallbackUrl)-1] != '/' {
  548. cfg.RendererCallbackUrl += "/"
  549. }
  550. _, err := url.Parse(cfg.RendererCallbackUrl)
  551. if err != nil {
  552. log.Fatal(4, "Invalid callback_url(%s): %s", cfg.RendererCallbackUrl, err)
  553. }
  554. }
  555. cfg.ImagesDir = filepath.Join(cfg.DataPath, "png")
  556. cfg.PhantomDir = filepath.Join(HomePath, "tools/phantomjs")
  557. cfg.TempDataLifetime = iniFile.Section("paths").Key("temp_data_lifetime").MustDuration(time.Second * 3600 * 24)
  558. cfg.MetricsEndpointEnabled = iniFile.Section("metrics").Key("enabled").MustBool(true)
  559. analytics := iniFile.Section("analytics")
  560. ReportingEnabled = analytics.Key("reporting_enabled").MustBool(true)
  561. CheckForUpdates = analytics.Key("check_for_updates").MustBool(true)
  562. GoogleAnalyticsId = analytics.Key("google_analytics_ua_id").String()
  563. GoogleTagManagerId = analytics.Key("google_tag_manager_id").String()
  564. ldapSec := iniFile.Section("auth.ldap")
  565. LdapEnabled = ldapSec.Key("enabled").MustBool(false)
  566. LdapConfigFile = ldapSec.Key("config_file").String()
  567. LdapAllowSignup = ldapSec.Key("allow_sign_up").MustBool(true)
  568. alerting := iniFile.Section("alerting")
  569. AlertingEnabled = alerting.Key("enabled").MustBool(true)
  570. ExecuteAlerts = alerting.Key("execute_alerts").MustBool(true)
  571. AlertingRenderLimit = alerting.Key("concurrent_render_limit").MustInt(5)
  572. AlertingErrorOrTimeout = alerting.Key("error_or_timeout").MustString("alerting")
  573. AlertingNoDataOrNullValues = alerting.Key("nodata_or_nullvalues").MustString("no_data")
  574. explore := iniFile.Section("explore")
  575. ExploreEnabled = explore.Key("enabled").MustBool(false)
  576. cfg.readSessionConfig()
  577. cfg.readSmtpSettings()
  578. cfg.readQuotaSettings()
  579. if VerifyEmailEnabled && !cfg.Smtp.Enabled {
  580. log.Warn("require_email_validation is enabled but smtp is disabled")
  581. }
  582. // check old key name
  583. GrafanaComUrl = iniFile.Section("grafana_net").Key("url").MustString("")
  584. if GrafanaComUrl == "" {
  585. GrafanaComUrl = iniFile.Section("grafana_com").Key("url").MustString("https://grafana.com")
  586. }
  587. imageUploadingSection := iniFile.Section("external_image_storage")
  588. ImageUploadProvider = imageUploadingSection.Key("provider").MustString("")
  589. return nil
  590. }
  591. func (cfg *Cfg) readSessionConfig() {
  592. sec := cfg.Raw.Section("session")
  593. SessionOptions = session.Options{}
  594. SessionOptions.Provider = sec.Key("provider").In("memory", []string{"memory", "file", "redis", "mysql", "postgres", "memcache"})
  595. SessionOptions.ProviderConfig = strings.Trim(sec.Key("provider_config").String(), "\" ")
  596. SessionOptions.CookieName = sec.Key("cookie_name").MustString("grafana_sess")
  597. SessionOptions.CookiePath = AppSubUrl
  598. SessionOptions.Secure = sec.Key("cookie_secure").MustBool()
  599. SessionOptions.Gclifetime = cfg.Raw.Section("session").Key("gc_interval_time").MustInt64(86400)
  600. SessionOptions.Maxlifetime = cfg.Raw.Section("session").Key("session_life_time").MustInt64(86400)
  601. SessionOptions.IDLength = 16
  602. if SessionOptions.Provider == "file" {
  603. SessionOptions.ProviderConfig = makeAbsolute(SessionOptions.ProviderConfig, cfg.DataPath)
  604. os.MkdirAll(path.Dir(SessionOptions.ProviderConfig), os.ModePerm)
  605. }
  606. if SessionOptions.CookiePath == "" {
  607. SessionOptions.CookiePath = "/"
  608. }
  609. SessionConnMaxLifetime = cfg.Raw.Section("session").Key("conn_max_lifetime").MustInt64(14400)
  610. }
  611. func (cfg *Cfg) initLogging(file *ini.File) {
  612. // split on comma
  613. logModes := strings.Split(file.Section("log").Key("mode").MustString("console"), ",")
  614. // also try space
  615. if len(logModes) == 1 {
  616. logModes = strings.Split(file.Section("log").Key("mode").MustString("console"), " ")
  617. }
  618. cfg.LogsPath = makeAbsolute(file.Section("paths").Key("logs").String(), HomePath)
  619. log.ReadLoggingConfig(logModes, cfg.LogsPath, file)
  620. }
  621. func (cfg *Cfg) LogConfigSources() {
  622. var text bytes.Buffer
  623. for _, file := range configFiles {
  624. logger.Info("Config loaded from", "file", file)
  625. }
  626. if len(appliedCommandLineProperties) > 0 {
  627. for _, prop := range appliedCommandLineProperties {
  628. logger.Info("Config overridden from command line", "arg", prop)
  629. }
  630. }
  631. if len(appliedEnvOverrides) > 0 {
  632. text.WriteString("\tEnvironment variables used:\n")
  633. for _, prop := range appliedEnvOverrides {
  634. logger.Info("Config overridden from Environment variable", "var", prop)
  635. }
  636. }
  637. logger.Info("Path Home", "path", HomePath)
  638. logger.Info("Path Data", "path", cfg.DataPath)
  639. logger.Info("Path Logs", "path", cfg.LogsPath)
  640. logger.Info("Path Plugins", "path", PluginsPath)
  641. logger.Info("Path Provisioning", "path", cfg.ProvisioningPath)
  642. logger.Info("App mode " + Env)
  643. }