setting.go 22 KB

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