setting.go 23 KB

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