setting.go 22 KB

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