setting.go 23 KB

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