setting.go 22 KB

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