setting.go 27 KB

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