setting.go 22 KB

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