setting.go 23 KB

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