setting.go 24 KB

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