setting.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791
  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. ViewersCanEdit bool
  102. // Http auth
  103. AdminUser string
  104. AdminPassword string
  105. AnonymousEnabled bool
  106. AnonymousOrgName string
  107. AnonymousOrgRole string
  108. // Auth proxy settings
  109. AuthProxyEnabled bool
  110. AuthProxyHeaderName string
  111. AuthProxyHeaderProperty string
  112. AuthProxyAutoSignUp bool
  113. AuthProxyLdapSyncTtl int
  114. AuthProxyWhitelist string
  115. AuthProxyHeaders map[string]string
  116. // Basic Auth
  117. BasicAuthEnabled bool
  118. // Plugin settings
  119. PluginAppsSkipVerifyTLS bool
  120. // Session settings.
  121. SessionOptions session.Options
  122. SessionConnMaxLifetime int64
  123. // Global setting objects.
  124. Raw *ini.File
  125. ConfRootPath string
  126. IsWindows bool
  127. // for logging purposes
  128. configFiles []string
  129. appliedCommandLineProperties []string
  130. appliedEnvOverrides []string
  131. ReportingEnabled bool
  132. CheckForUpdates bool
  133. GoogleAnalyticsId string
  134. GoogleTagManagerId string
  135. // LDAP
  136. LdapEnabled bool
  137. LdapConfigFile string
  138. LdapAllowSignup = true
  139. // QUOTA
  140. Quota QuotaSettings
  141. // Alerting
  142. AlertingEnabled bool
  143. ExecuteAlerts bool
  144. AlertingRenderLimit int
  145. AlertingErrorOrTimeout string
  146. AlertingNoDataOrNullValues string
  147. // Explore UI
  148. ExploreEnabled bool
  149. // logger
  150. logger log.Logger
  151. // Grafana.NET URL
  152. GrafanaComUrl string
  153. // S3 temp image store
  154. S3TempImageStoreBucketUrl string
  155. S3TempImageStoreAccessKey string
  156. S3TempImageStoreSecretKey string
  157. ImageUploadProvider string
  158. )
  159. // TODO move all global vars to this struct
  160. type Cfg struct {
  161. Raw *ini.File
  162. // HTTP Server Settings
  163. AppUrl string
  164. AppSubUrl string
  165. // Paths
  166. ProvisioningPath string
  167. DataPath string
  168. LogsPath string
  169. // SMTP email settings
  170. Smtp SmtpSettings
  171. // Rendering
  172. ImagesDir string
  173. PhantomDir string
  174. RendererUrl string
  175. RendererCallbackUrl string
  176. RendererLimit int
  177. RendererLimitAlerting int
  178. DisableBruteForceLoginProtection bool
  179. TempDataLifetime time.Duration
  180. MetricsEndpointEnabled bool
  181. EnableAlphaPanels bool
  182. EnterpriseLicensePath string
  183. }
  184. type CommandLineArgs struct {
  185. Config string
  186. HomePath string
  187. Args []string
  188. }
  189. func init() {
  190. IsWindows = runtime.GOOS == "windows"
  191. logger = log.New("settings")
  192. }
  193. func parseAppUrlAndSubUrl(section *ini.Section) (string, string) {
  194. appUrl := section.Key("root_url").MustString("http://localhost:3000/")
  195. if appUrl[len(appUrl)-1] != '/' {
  196. appUrl += "/"
  197. }
  198. // Check if has app suburl.
  199. url, err := url.Parse(appUrl)
  200. if err != nil {
  201. log.Fatal(4, "Invalid root_url(%s): %s", appUrl, err)
  202. }
  203. appSubUrl := strings.TrimSuffix(url.Path, "/")
  204. return appUrl, appSubUrl
  205. }
  206. func ToAbsUrl(relativeUrl string) string {
  207. return AppUrl + relativeUrl
  208. }
  209. func shouldRedactKey(s string) bool {
  210. uppercased := strings.ToUpper(s)
  211. return strings.Contains(uppercased, "PASSWORD") || strings.Contains(uppercased, "SECRET") || strings.Contains(uppercased, "PROVIDER_CONFIG")
  212. }
  213. func shouldRedactURLKey(s string) bool {
  214. uppercased := strings.ToUpper(s)
  215. return strings.Contains(uppercased, "DATABASE_URL")
  216. }
  217. func applyEnvVariableOverrides(file *ini.File) error {
  218. appliedEnvOverrides = make([]string, 0)
  219. for _, section := range file.Sections() {
  220. for _, key := range section.Keys() {
  221. sectionName := strings.ToUpper(strings.Replace(section.Name(), ".", "_", -1))
  222. keyName := strings.ToUpper(strings.Replace(key.Name(), ".", "_", -1))
  223. envKey := fmt.Sprintf("GF_%s_%s", sectionName, keyName)
  224. envValue := os.Getenv(envKey)
  225. if len(envValue) > 0 {
  226. key.SetValue(envValue)
  227. if shouldRedactKey(envKey) {
  228. envValue = "*********"
  229. }
  230. if shouldRedactURLKey(envKey) {
  231. u, err := url.Parse(envValue)
  232. if err != nil {
  233. return fmt.Errorf("could not parse environment variable. key: %s, value: %s. error: %v", envKey, envValue, err)
  234. }
  235. ui := u.User
  236. if ui != nil {
  237. _, exists := ui.Password()
  238. if exists {
  239. u.User = url.UserPassword(ui.Username(), "-redacted-")
  240. envValue = u.String()
  241. }
  242. }
  243. }
  244. appliedEnvOverrides = append(appliedEnvOverrides, fmt.Sprintf("%s=%s", envKey, envValue))
  245. }
  246. }
  247. }
  248. return nil
  249. }
  250. func applyCommandLineDefaultProperties(props map[string]string, file *ini.File) {
  251. appliedCommandLineProperties = make([]string, 0)
  252. for _, section := range file.Sections() {
  253. for _, key := range section.Keys() {
  254. keyString := fmt.Sprintf("default.%s.%s", section.Name(), key.Name())
  255. value, exists := props[keyString]
  256. if exists {
  257. key.SetValue(value)
  258. if shouldRedactKey(keyString) {
  259. value = "*********"
  260. }
  261. appliedCommandLineProperties = append(appliedCommandLineProperties, fmt.Sprintf("%s=%s", keyString, value))
  262. }
  263. }
  264. }
  265. }
  266. func applyCommandLineProperties(props map[string]string, file *ini.File) {
  267. for _, section := range file.Sections() {
  268. sectionName := section.Name() + "."
  269. if section.Name() == ini.DEFAULT_SECTION {
  270. sectionName = ""
  271. }
  272. for _, key := range section.Keys() {
  273. keyString := sectionName + key.Name()
  274. value, exists := props[keyString]
  275. if exists {
  276. appliedCommandLineProperties = append(appliedCommandLineProperties, fmt.Sprintf("%s=%s", keyString, value))
  277. key.SetValue(value)
  278. }
  279. }
  280. }
  281. }
  282. func getCommandLineProperties(args []string) map[string]string {
  283. props := make(map[string]string)
  284. for _, arg := range args {
  285. if !strings.HasPrefix(arg, "cfg:") {
  286. continue
  287. }
  288. trimmed := strings.TrimPrefix(arg, "cfg:")
  289. parts := strings.Split(trimmed, "=")
  290. if len(parts) != 2 {
  291. log.Fatal(3, "Invalid command line argument. argument: %v", arg)
  292. return nil
  293. }
  294. props[parts[0]] = parts[1]
  295. }
  296. return props
  297. }
  298. func makeAbsolute(path string, root string) string {
  299. if filepath.IsAbs(path) {
  300. return path
  301. }
  302. return filepath.Join(root, path)
  303. }
  304. func evalEnvVarExpression(value string) string {
  305. regex := regexp.MustCompile(`\${(\w+)}`)
  306. return regex.ReplaceAllStringFunc(value, func(envVar string) string {
  307. envVar = strings.TrimPrefix(envVar, "${")
  308. envVar = strings.TrimSuffix(envVar, "}")
  309. envValue := os.Getenv(envVar)
  310. // if env variable is hostname and it is empty use os.Hostname as default
  311. if envVar == "HOSTNAME" && envValue == "" {
  312. envValue, _ = os.Hostname()
  313. }
  314. return envValue
  315. })
  316. }
  317. func evalConfigValues(file *ini.File) {
  318. for _, section := range file.Sections() {
  319. for _, key := range section.Keys() {
  320. key.SetValue(evalEnvVarExpression(key.Value()))
  321. }
  322. }
  323. }
  324. func loadSpecifedConfigFile(configFile string, masterFile *ini.File) error {
  325. if configFile == "" {
  326. configFile = filepath.Join(HomePath, CustomInitPath)
  327. // return without error if custom file does not exist
  328. if !pathExists(configFile) {
  329. return nil
  330. }
  331. }
  332. userConfig, err := ini.Load(configFile)
  333. if err != nil {
  334. return fmt.Errorf("Failed to parse %v, %v", configFile, err)
  335. }
  336. userConfig.BlockMode = false
  337. for _, section := range userConfig.Sections() {
  338. for _, key := range section.Keys() {
  339. if key.Value() == "" {
  340. continue
  341. }
  342. defaultSec, err := masterFile.GetSection(section.Name())
  343. if err != nil {
  344. defaultSec, _ = masterFile.NewSection(section.Name())
  345. }
  346. defaultKey, err := defaultSec.GetKey(key.Name())
  347. if err != nil {
  348. defaultKey, _ = defaultSec.NewKey(key.Name(), key.Value())
  349. }
  350. defaultKey.SetValue(key.Value())
  351. }
  352. }
  353. configFiles = append(configFiles, configFile)
  354. return nil
  355. }
  356. func (cfg *Cfg) loadConfiguration(args *CommandLineArgs) (*ini.File, error) {
  357. var err error
  358. // load config defaults
  359. defaultConfigFile := path.Join(HomePath, "conf/defaults.ini")
  360. configFiles = append(configFiles, defaultConfigFile)
  361. // check if config file exists
  362. if _, err := os.Stat(defaultConfigFile); os.IsNotExist(err) {
  363. fmt.Println("Grafana-server Init Failed: Could not find config defaults, make sure homepath command line parameter is set or working directory is homepath")
  364. os.Exit(1)
  365. }
  366. // load defaults
  367. parsedFile, err := ini.Load(defaultConfigFile)
  368. if err != nil {
  369. fmt.Println(fmt.Sprintf("Failed to parse defaults.ini, %v", err))
  370. os.Exit(1)
  371. return nil, err
  372. }
  373. parsedFile.BlockMode = false
  374. // command line props
  375. commandLineProps := getCommandLineProperties(args.Args)
  376. // load default overrides
  377. applyCommandLineDefaultProperties(commandLineProps, parsedFile)
  378. // load specified config file
  379. err = loadSpecifedConfigFile(args.Config, parsedFile)
  380. if err != nil {
  381. cfg.initLogging(parsedFile)
  382. log.Fatal(3, err.Error())
  383. }
  384. // apply environment overrides
  385. err = applyEnvVariableOverrides(parsedFile)
  386. if err != nil {
  387. return nil, err
  388. }
  389. // apply command line overrides
  390. applyCommandLineProperties(commandLineProps, parsedFile)
  391. // evaluate config values containing environment variables
  392. evalConfigValues(parsedFile)
  393. // update data path and logging config
  394. cfg.DataPath = makeAbsolute(parsedFile.Section("paths").Key("data").String(), HomePath)
  395. cfg.initLogging(parsedFile)
  396. return parsedFile, err
  397. }
  398. func pathExists(path string) bool {
  399. _, err := os.Stat(path)
  400. if err == nil {
  401. return true
  402. }
  403. if os.IsNotExist(err) {
  404. return false
  405. }
  406. return false
  407. }
  408. func setHomePath(args *CommandLineArgs) {
  409. if args.HomePath != "" {
  410. HomePath = args.HomePath
  411. return
  412. }
  413. HomePath, _ = filepath.Abs(".")
  414. // check if homepath is correct
  415. if pathExists(filepath.Join(HomePath, "conf/defaults.ini")) {
  416. return
  417. }
  418. // try down one path
  419. if pathExists(filepath.Join(HomePath, "../conf/defaults.ini")) {
  420. HomePath = filepath.Join(HomePath, "../")
  421. }
  422. }
  423. var skipStaticRootValidation = false
  424. func validateStaticRootPath() error {
  425. if skipStaticRootValidation {
  426. return nil
  427. }
  428. if _, err := os.Stat(path.Join(StaticRootPath, "build")); err != nil {
  429. logger.Error("Failed to detect generated javascript files in public/build")
  430. }
  431. return nil
  432. }
  433. func NewCfg() *Cfg {
  434. return &Cfg{
  435. Raw: ini.Empty(),
  436. }
  437. }
  438. func (cfg *Cfg) Load(args *CommandLineArgs) error {
  439. setHomePath(args)
  440. iniFile, err := cfg.loadConfiguration(args)
  441. if err != nil {
  442. return err
  443. }
  444. cfg.Raw = iniFile
  445. // Temporary keep global, to make refactor in steps
  446. Raw = cfg.Raw
  447. ApplicationName = APP_NAME
  448. if IsEnterprise {
  449. ApplicationName = APP_NAME_ENTERPRISE
  450. }
  451. Env = iniFile.Section("").Key("app_mode").MustString("development")
  452. InstanceName = iniFile.Section("").Key("instance_name").MustString("unknown_instance_name")
  453. PluginsPath = makeAbsolute(iniFile.Section("paths").Key("plugins").String(), HomePath)
  454. cfg.ProvisioningPath = makeAbsolute(iniFile.Section("paths").Key("provisioning").String(), HomePath)
  455. server := iniFile.Section("server")
  456. AppUrl, AppSubUrl = parseAppUrlAndSubUrl(server)
  457. cfg.AppUrl = AppUrl
  458. cfg.AppSubUrl = AppSubUrl
  459. Protocol = HTTP
  460. if server.Key("protocol").MustString("http") == "https" {
  461. Protocol = HTTPS
  462. CertFile = server.Key("cert_file").String()
  463. KeyFile = server.Key("cert_key").String()
  464. }
  465. if server.Key("protocol").MustString("http") == "socket" {
  466. Protocol = SOCKET
  467. SocketPath = server.Key("socket").String()
  468. }
  469. Domain = server.Key("domain").MustString("localhost")
  470. HttpAddr = server.Key("http_addr").MustString(DEFAULT_HTTP_ADDR)
  471. HttpPort = server.Key("http_port").MustString("3000")
  472. RouterLogging = server.Key("router_logging").MustBool(false)
  473. EnableGzip = server.Key("enable_gzip").MustBool(false)
  474. EnforceDomain = server.Key("enforce_domain").MustBool(false)
  475. StaticRootPath = makeAbsolute(server.Key("static_root_path").String(), HomePath)
  476. if err := validateStaticRootPath(); err != nil {
  477. return err
  478. }
  479. // read data proxy settings
  480. dataproxy := iniFile.Section("dataproxy")
  481. DataProxyLogging = dataproxy.Key("logging").MustBool(false)
  482. // read security settings
  483. security := iniFile.Section("security")
  484. SecretKey = security.Key("secret_key").String()
  485. LogInRememberDays = security.Key("login_remember_days").MustInt()
  486. CookieUserName = security.Key("cookie_username").String()
  487. CookieRememberName = security.Key("cookie_remember_name").String()
  488. DisableGravatar = security.Key("disable_gravatar").MustBool(true)
  489. cfg.DisableBruteForceLoginProtection = security.Key("disable_brute_force_login_protection").MustBool(false)
  490. DisableBruteForceLoginProtection = cfg.DisableBruteForceLoginProtection
  491. // read snapshots settings
  492. snapshots := iniFile.Section("snapshots")
  493. ExternalSnapshotUrl = snapshots.Key("external_snapshot_url").String()
  494. ExternalSnapshotName = snapshots.Key("external_snapshot_name").String()
  495. ExternalEnabled = snapshots.Key("external_enabled").MustBool(true)
  496. SnapShotRemoveExpired = snapshots.Key("snapshot_remove_expired").MustBool(true)
  497. // read dashboard settings
  498. dashboards := iniFile.Section("dashboards")
  499. DashboardVersionsToKeep = dashboards.Key("versions_to_keep").MustInt(20)
  500. // read data source proxy white list
  501. DataProxyWhiteList = make(map[string]bool)
  502. for _, hostAndIp := range util.SplitString(security.Key("data_source_proxy_whitelist").String()) {
  503. DataProxyWhiteList[hostAndIp] = true
  504. }
  505. // admin
  506. AdminUser = security.Key("admin_user").String()
  507. AdminPassword = security.Key("admin_password").String()
  508. users := iniFile.Section("users")
  509. AllowUserSignUp = users.Key("allow_sign_up").MustBool(true)
  510. AllowUserOrgCreate = users.Key("allow_org_create").MustBool(true)
  511. AutoAssignOrg = users.Key("auto_assign_org").MustBool(true)
  512. AutoAssignOrgId = users.Key("auto_assign_org_id").MustInt(1)
  513. AutoAssignOrgRole = users.Key("auto_assign_org_role").In("Editor", []string{"Editor", "Admin", "Viewer"})
  514. VerifyEmailEnabled = users.Key("verify_email_enabled").MustBool(false)
  515. LoginHint = users.Key("login_hint").String()
  516. DefaultTheme = users.Key("default_theme").String()
  517. ExternalUserMngLinkUrl = users.Key("external_manage_link_url").String()
  518. ExternalUserMngLinkName = users.Key("external_manage_link_name").String()
  519. ExternalUserMngInfo = users.Key("external_manage_info").String()
  520. ViewersCanEdit = users.Key("viewers_can_edit").MustBool(false)
  521. // auth
  522. auth := iniFile.Section("auth")
  523. DisableLoginForm = auth.Key("disable_login_form").MustBool(false)
  524. DisableSignoutMenu = auth.Key("disable_signout_menu").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. }