setting.go 30 KB

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