setting.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813
  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. DataProxyTimeout int
  68. StaticRootPath string
  69. EnableGzip bool
  70. EnforceDomain bool
  71. // Security settings.
  72. SecretKey string
  73. DisableGravatar bool
  74. EmailCodeValidMinutes int
  75. DataProxyWhiteList map[string]bool
  76. DisableBruteForceLoginProtection bool
  77. // Snapshots
  78. ExternalSnapshotUrl string
  79. ExternalSnapshotName string
  80. ExternalEnabled bool
  81. SnapShotRemoveExpired bool
  82. // Dashboard history
  83. DashboardVersionsToKeep int
  84. // User settings
  85. AllowUserSignUp bool
  86. AllowUserOrgCreate bool
  87. AutoAssignOrg bool
  88. AutoAssignOrgId int
  89. AutoAssignOrgRole string
  90. VerifyEmailEnabled bool
  91. LoginHint string
  92. DefaultTheme string
  93. DisableLoginForm bool
  94. DisableSignoutMenu bool
  95. SignoutRedirectUrl string
  96. ExternalUserMngLinkUrl string
  97. ExternalUserMngLinkName string
  98. ExternalUserMngInfo string
  99. OAuthAutoLogin bool
  100. ViewersCanEdit bool
  101. // Http auth
  102. AdminUser string
  103. AdminPassword string
  104. AnonymousEnabled bool
  105. AnonymousOrgName string
  106. AnonymousOrgRole string
  107. // Auth proxy settings
  108. AuthProxyEnabled bool
  109. AuthProxyHeaderName string
  110. AuthProxyHeaderProperty string
  111. AuthProxyAutoSignUp bool
  112. AuthProxyLdapSyncTtl int
  113. AuthProxyWhitelist string
  114. AuthProxyHeaders map[string]string
  115. // Basic Auth
  116. BasicAuthEnabled bool
  117. // Plugin settings
  118. PluginAppsSkipVerifyTLS bool
  119. // Session settings.
  120. SessionOptions session.Options
  121. SessionConnMaxLifetime int64
  122. // Global setting objects.
  123. Raw *ini.File
  124. ConfRootPath string
  125. IsWindows bool
  126. // for logging purposes
  127. configFiles []string
  128. appliedCommandLineProperties []string
  129. appliedEnvOverrides []string
  130. ReportingEnabled bool
  131. CheckForUpdates bool
  132. GoogleAnalyticsId string
  133. GoogleTagManagerId string
  134. // LDAP
  135. LdapEnabled bool
  136. LdapConfigFile string
  137. LdapAllowSignup = true
  138. // QUOTA
  139. Quota QuotaSettings
  140. // Alerting
  141. AlertingEnabled bool
  142. ExecuteAlerts bool
  143. AlertingRenderLimit int
  144. AlertingErrorOrTimeout string
  145. AlertingNoDataOrNullValues string
  146. // Explore UI
  147. ExploreEnabled bool
  148. // logger
  149. logger log.Logger
  150. // Grafana.NET URL
  151. GrafanaComUrl string
  152. // S3 temp image store
  153. S3TempImageStoreBucketUrl string
  154. S3TempImageStoreAccessKey string
  155. S3TempImageStoreSecretKey string
  156. ImageUploadProvider string
  157. )
  158. // TODO move all global vars to this struct
  159. type Cfg struct {
  160. Raw *ini.File
  161. // HTTP Server Settings
  162. AppUrl string
  163. AppSubUrl string
  164. // Paths
  165. ProvisioningPath string
  166. DataPath string
  167. LogsPath string
  168. // SMTP email settings
  169. Smtp SmtpSettings
  170. // Rendering
  171. ImagesDir string
  172. PhantomDir string
  173. RendererUrl string
  174. RendererCallbackUrl string
  175. RendererLimit int
  176. RendererLimitAlerting int
  177. DisableBruteForceLoginProtection bool
  178. TempDataLifetime time.Duration
  179. MetricsEndpointEnabled bool
  180. MetricsEndpointBasicAuthUsername string
  181. MetricsEndpointBasicAuthPassword string
  182. EnableAlphaPanels bool
  183. DisableSanitizeHtml bool
  184. EnterpriseLicensePath string
  185. LoginCookieName string
  186. LoginCookieMaxDays int
  187. LoginCookieRotation int
  188. LoginDeleteExpiredTokensAfterDays int
  189. SecurityHTTPSCookies bool
  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.LoginDeleteExpiredTokensAfterDays = login.Key("delete_expired_token_after_days").MustInt(30)
  463. cfg.LoginCookieRotation = login.Key("rotate_token_minutes").MustInt(10)
  464. if cfg.LoginCookieRotation < 2 {
  465. cfg.LoginCookieRotation = 2
  466. }
  467. Env = iniFile.Section("").Key("app_mode").MustString("development")
  468. InstanceName = iniFile.Section("").Key("instance_name").MustString("unknown_instance_name")
  469. PluginsPath = makeAbsolute(iniFile.Section("paths").Key("plugins").String(), HomePath)
  470. cfg.ProvisioningPath = makeAbsolute(iniFile.Section("paths").Key("provisioning").String(), HomePath)
  471. server := iniFile.Section("server")
  472. AppUrl, AppSubUrl = parseAppUrlAndSubUrl(server)
  473. cfg.AppUrl = AppUrl
  474. cfg.AppSubUrl = AppSubUrl
  475. Protocol = HTTP
  476. if server.Key("protocol").MustString("http") == "https" {
  477. Protocol = HTTPS
  478. CertFile = server.Key("cert_file").String()
  479. KeyFile = server.Key("cert_key").String()
  480. }
  481. if server.Key("protocol").MustString("http") == "socket" {
  482. Protocol = SOCKET
  483. SocketPath = server.Key("socket").String()
  484. }
  485. Domain = server.Key("domain").MustString("localhost")
  486. HttpAddr = server.Key("http_addr").MustString(DEFAULT_HTTP_ADDR)
  487. HttpPort = server.Key("http_port").MustString("3000")
  488. RouterLogging = server.Key("router_logging").MustBool(false)
  489. EnableGzip = server.Key("enable_gzip").MustBool(false)
  490. EnforceDomain = server.Key("enforce_domain").MustBool(false)
  491. StaticRootPath = makeAbsolute(server.Key("static_root_path").String(), HomePath)
  492. if err := validateStaticRootPath(); err != nil {
  493. return err
  494. }
  495. // read data proxy settings
  496. dataproxy := iniFile.Section("dataproxy")
  497. DataProxyLogging = dataproxy.Key("logging").MustBool(false)
  498. DataProxyTimeout = dataproxy.Key("timeout").MustInt(30)
  499. // read security settings
  500. security := iniFile.Section("security")
  501. SecretKey = security.Key("secret_key").String()
  502. DisableGravatar = security.Key("disable_gravatar").MustBool(true)
  503. cfg.DisableBruteForceLoginProtection = security.Key("disable_brute_force_login_protection").MustBool(false)
  504. cfg.SecurityHTTPSCookies = security.Key("https_flag_cookies").MustBool(false)
  505. DisableBruteForceLoginProtection = cfg.DisableBruteForceLoginProtection
  506. // read snapshots settings
  507. snapshots := iniFile.Section("snapshots")
  508. ExternalSnapshotUrl = snapshots.Key("external_snapshot_url").String()
  509. ExternalSnapshotName = snapshots.Key("external_snapshot_name").String()
  510. ExternalEnabled = snapshots.Key("external_enabled").MustBool(true)
  511. SnapShotRemoveExpired = snapshots.Key("snapshot_remove_expired").MustBool(true)
  512. // read dashboard settings
  513. dashboards := iniFile.Section("dashboards")
  514. DashboardVersionsToKeep = dashboards.Key("versions_to_keep").MustInt(20)
  515. // read data source proxy white list
  516. DataProxyWhiteList = make(map[string]bool)
  517. for _, hostAndIp := range util.SplitString(security.Key("data_source_proxy_whitelist").String()) {
  518. DataProxyWhiteList[hostAndIp] = true
  519. }
  520. // admin
  521. AdminUser = security.Key("admin_user").String()
  522. AdminPassword = security.Key("admin_password").String()
  523. users := iniFile.Section("users")
  524. AllowUserSignUp = users.Key("allow_sign_up").MustBool(true)
  525. AllowUserOrgCreate = users.Key("allow_org_create").MustBool(true)
  526. AutoAssignOrg = users.Key("auto_assign_org").MustBool(true)
  527. AutoAssignOrgId = users.Key("auto_assign_org_id").MustInt(1)
  528. AutoAssignOrgRole = users.Key("auto_assign_org_role").In("Editor", []string{"Editor", "Admin", "Viewer"})
  529. VerifyEmailEnabled = users.Key("verify_email_enabled").MustBool(false)
  530. LoginHint = users.Key("login_hint").String()
  531. DefaultTheme = users.Key("default_theme").String()
  532. ExternalUserMngLinkUrl = users.Key("external_manage_link_url").String()
  533. ExternalUserMngLinkName = users.Key("external_manage_link_name").String()
  534. ExternalUserMngInfo = users.Key("external_manage_info").String()
  535. ViewersCanEdit = users.Key("viewers_can_edit").MustBool(false)
  536. // auth
  537. auth := iniFile.Section("auth")
  538. DisableLoginForm = auth.Key("disable_login_form").MustBool(false)
  539. DisableSignoutMenu = auth.Key("disable_signout_menu").MustBool(false)
  540. OAuthAutoLogin = auth.Key("oauth_auto_login").MustBool(false)
  541. SignoutRedirectUrl = auth.Key("signout_redirect_url").String()
  542. // anonymous access
  543. AnonymousEnabled = iniFile.Section("auth.anonymous").Key("enabled").MustBool(false)
  544. AnonymousOrgName = iniFile.Section("auth.anonymous").Key("org_name").String()
  545. AnonymousOrgRole = iniFile.Section("auth.anonymous").Key("org_role").String()
  546. // auth proxy
  547. authProxy := iniFile.Section("auth.proxy")
  548. AuthProxyEnabled = authProxy.Key("enabled").MustBool(false)
  549. AuthProxyHeaderName = authProxy.Key("header_name").String()
  550. AuthProxyHeaderProperty = authProxy.Key("header_property").String()
  551. AuthProxyAutoSignUp = authProxy.Key("auto_sign_up").MustBool(true)
  552. AuthProxyLdapSyncTtl = authProxy.Key("ldap_sync_ttl").MustInt()
  553. AuthProxyWhitelist = authProxy.Key("whitelist").String()
  554. AuthProxyHeaders = make(map[string]string)
  555. for _, propertyAndHeader := range util.SplitString(authProxy.Key("headers").String()) {
  556. split := strings.SplitN(propertyAndHeader, ":", 2)
  557. if len(split) == 2 {
  558. AuthProxyHeaders[split[0]] = split[1]
  559. }
  560. }
  561. // basic auth
  562. authBasic := iniFile.Section("auth.basic")
  563. BasicAuthEnabled = authBasic.Key("enabled").MustBool(true)
  564. // global plugin settings
  565. PluginAppsSkipVerifyTLS = iniFile.Section("plugins").Key("app_tls_skip_verify_insecure").MustBool(false)
  566. // Rendering
  567. renderSec := iniFile.Section("rendering")
  568. cfg.RendererUrl = renderSec.Key("server_url").String()
  569. cfg.RendererCallbackUrl = renderSec.Key("callback_url").String()
  570. if cfg.RendererCallbackUrl == "" {
  571. cfg.RendererCallbackUrl = AppUrl
  572. } else {
  573. if cfg.RendererCallbackUrl[len(cfg.RendererCallbackUrl)-1] != '/' {
  574. cfg.RendererCallbackUrl += "/"
  575. }
  576. _, err := url.Parse(cfg.RendererCallbackUrl)
  577. if err != nil {
  578. log.Fatal(4, "Invalid callback_url(%s): %s", cfg.RendererCallbackUrl, err)
  579. }
  580. }
  581. cfg.ImagesDir = filepath.Join(cfg.DataPath, "png")
  582. cfg.PhantomDir = filepath.Join(HomePath, "tools/phantomjs")
  583. cfg.TempDataLifetime = iniFile.Section("paths").Key("temp_data_lifetime").MustDuration(time.Second * 3600 * 24)
  584. cfg.MetricsEndpointEnabled = iniFile.Section("metrics").Key("enabled").MustBool(true)
  585. cfg.MetricsEndpointBasicAuthUsername = iniFile.Section("metrics").Key("basic_auth_username").String()
  586. cfg.MetricsEndpointBasicAuthPassword = iniFile.Section("metrics").Key("basic_auth_password").String()
  587. analytics := iniFile.Section("analytics")
  588. ReportingEnabled = analytics.Key("reporting_enabled").MustBool(true)
  589. CheckForUpdates = analytics.Key("check_for_updates").MustBool(true)
  590. GoogleAnalyticsId = analytics.Key("google_analytics_ua_id").String()
  591. GoogleTagManagerId = analytics.Key("google_tag_manager_id").String()
  592. ldapSec := iniFile.Section("auth.ldap")
  593. LdapEnabled = ldapSec.Key("enabled").MustBool(false)
  594. LdapConfigFile = ldapSec.Key("config_file").String()
  595. LdapAllowSignup = ldapSec.Key("allow_sign_up").MustBool(true)
  596. alerting := iniFile.Section("alerting")
  597. AlertingEnabled = alerting.Key("enabled").MustBool(true)
  598. ExecuteAlerts = alerting.Key("execute_alerts").MustBool(true)
  599. AlertingRenderLimit = alerting.Key("concurrent_render_limit").MustInt(5)
  600. AlertingErrorOrTimeout = alerting.Key("error_or_timeout").MustString("alerting")
  601. AlertingNoDataOrNullValues = alerting.Key("nodata_or_nullvalues").MustString("no_data")
  602. explore := iniFile.Section("explore")
  603. ExploreEnabled = explore.Key("enabled").MustBool(true)
  604. panels := iniFile.Section("panels")
  605. cfg.EnableAlphaPanels = panels.Key("enable_alpha").MustBool(false)
  606. cfg.DisableSanitizeHtml = panels.Key("disable_sanitize_html").MustBool(false)
  607. cfg.readSessionConfig()
  608. cfg.readSmtpSettings()
  609. cfg.readQuotaSettings()
  610. if VerifyEmailEnabled && !cfg.Smtp.Enabled {
  611. log.Warn("require_email_validation is enabled but smtp is disabled")
  612. }
  613. // check old key name
  614. GrafanaComUrl = iniFile.Section("grafana_net").Key("url").MustString("")
  615. if GrafanaComUrl == "" {
  616. GrafanaComUrl = iniFile.Section("grafana_com").Key("url").MustString("https://grafana.com")
  617. }
  618. imageUploadingSection := iniFile.Section("external_image_storage")
  619. ImageUploadProvider = imageUploadingSection.Key("provider").MustString("")
  620. enterprise := iniFile.Section("enterprise")
  621. cfg.EnterpriseLicensePath = enterprise.Key("license_path").MustString(filepath.Join(cfg.DataPath, "license.jwt"))
  622. return nil
  623. }
  624. func (cfg *Cfg) readSessionConfig() {
  625. sec := cfg.Raw.Section("session")
  626. SessionOptions = session.Options{}
  627. SessionOptions.Provider = sec.Key("provider").In("memory", []string{"memory", "file", "redis", "mysql", "postgres", "memcache"})
  628. SessionOptions.ProviderConfig = strings.Trim(sec.Key("provider_config").String(), "\" ")
  629. SessionOptions.CookieName = sec.Key("cookie_name").MustString("grafana_sess")
  630. SessionOptions.CookiePath = AppSubUrl
  631. SessionOptions.Secure = sec.Key("cookie_secure").MustBool()
  632. SessionOptions.Gclifetime = cfg.Raw.Section("session").Key("gc_interval_time").MustInt64(86400)
  633. SessionOptions.Maxlifetime = cfg.Raw.Section("session").Key("session_life_time").MustInt64(86400)
  634. SessionOptions.IDLength = 16
  635. if SessionOptions.Provider == "file" {
  636. SessionOptions.ProviderConfig = makeAbsolute(SessionOptions.ProviderConfig, cfg.DataPath)
  637. os.MkdirAll(path.Dir(SessionOptions.ProviderConfig), os.ModePerm)
  638. }
  639. if SessionOptions.CookiePath == "" {
  640. SessionOptions.CookiePath = "/"
  641. }
  642. SessionConnMaxLifetime = cfg.Raw.Section("session").Key("conn_max_lifetime").MustInt64(14400)
  643. }
  644. func (cfg *Cfg) initLogging(file *ini.File) {
  645. // split on comma
  646. logModes := strings.Split(file.Section("log").Key("mode").MustString("console"), ",")
  647. // also try space
  648. if len(logModes) == 1 {
  649. logModes = strings.Split(file.Section("log").Key("mode").MustString("console"), " ")
  650. }
  651. cfg.LogsPath = makeAbsolute(file.Section("paths").Key("logs").String(), HomePath)
  652. log.ReadLoggingConfig(logModes, cfg.LogsPath, file)
  653. }
  654. func (cfg *Cfg) LogConfigSources() {
  655. var text bytes.Buffer
  656. for _, file := range configFiles {
  657. logger.Info("Config loaded from", "file", file)
  658. }
  659. if len(appliedCommandLineProperties) > 0 {
  660. for _, prop := range appliedCommandLineProperties {
  661. logger.Info("Config overridden from command line", "arg", prop)
  662. }
  663. }
  664. if len(appliedEnvOverrides) > 0 {
  665. text.WriteString("\tEnvironment variables used:\n")
  666. for _, prop := range appliedEnvOverrides {
  667. logger.Info("Config overridden from Environment variable", "var", prop)
  668. }
  669. }
  670. logger.Info("Path Home", "path", HomePath)
  671. logger.Info("Path Data", "path", cfg.DataPath)
  672. logger.Info("Path Logs", "path", cfg.LogsPath)
  673. logger.Info("Path Plugins", "path", PluginsPath)
  674. logger.Info("Path Provisioning", "path", cfg.ProvisioningPath)
  675. logger.Info("App mode " + Env)
  676. }