setting.go 24 KB

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