setting.go 23 KB

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