mirror of
https://github.com/grafana/grafana.git
synced 2026-02-19 02:30:53 -05:00
Some checks failed
Actionlint / Lint GitHub Actions files (push) Waiting to run
Backend Code Checks / Detect whether code changed (push) Waiting to run
Backend Code Checks / Validate Backend Configs (push) Blocked by required conditions
Backend Unit Tests / Detect whether code changed (push) Waiting to run
Backend Unit Tests / Grafana (1/8) (push) Blocked by required conditions
Backend Unit Tests / Grafana (2/8) (push) Blocked by required conditions
Backend Unit Tests / Grafana (3/8) (push) Blocked by required conditions
Backend Unit Tests / Grafana (4/8) (push) Blocked by required conditions
Backend Unit Tests / Grafana (5/8) (push) Blocked by required conditions
Backend Unit Tests / Grafana (6/8) (push) Blocked by required conditions
Backend Unit Tests / Grafana (7/8) (push) Blocked by required conditions
Backend Unit Tests / Grafana (8/8) (push) Blocked by required conditions
Backend Unit Tests / Grafana Enterprise (1/8) (push) Blocked by required conditions
Backend Unit Tests / Grafana Enterprise (2/8) (push) Blocked by required conditions
Backend Unit Tests / Grafana Enterprise (3/8) (push) Blocked by required conditions
Backend Unit Tests / Grafana Enterprise (4/8) (push) Blocked by required conditions
Backend Unit Tests / Grafana Enterprise (5/8) (push) Blocked by required conditions
Backend Unit Tests / Grafana Enterprise (6/8) (push) Blocked by required conditions
Backend Unit Tests / Grafana Enterprise (7/8) (push) Blocked by required conditions
Backend Unit Tests / Grafana Enterprise (8/8) (push) Blocked by required conditions
Backend Unit Tests / All backend unit tests complete (push) Blocked by required conditions
CodeQL checks / Detect whether code changed (push) Waiting to run
CodeQL checks / Analyze (push) Blocked by required conditions
Lint Frontend / Detect whether code changed (push) Waiting to run
Lint Frontend / Lint (push) Blocked by required conditions
Lint Frontend / Typecheck (push) Blocked by required conditions
Lint Frontend / Verify API clients (push) Waiting to run
Lint Frontend / Verify API clients (enterprise) (push) Waiting to run
golangci-lint / Detect whether code changed (push) Waiting to run
golangci-lint / go-fmt (push) Blocked by required conditions
golangci-lint / lint-go (push) Blocked by required conditions
Verify i18n / verify-i18n (push) Waiting to run
End-to-end tests / Detect whether code changed (push) Waiting to run
End-to-end tests / Build & Package Grafana (push) Blocked by required conditions
End-to-end tests / Build E2E test runner (push) Blocked by required conditions
End-to-end tests / push-docker-image (push) Blocked by required conditions
End-to-end tests / dashboards-suite (old arch) (push) Blocked by required conditions
End-to-end tests / panels-suite (old arch) (push) Blocked by required conditions
End-to-end tests / smoke-tests-suite (old arch) (push) Blocked by required conditions
End-to-end tests / various-suite (old arch) (push) Blocked by required conditions
End-to-end tests / Verify Storybook (Playwright) (push) Blocked by required conditions
End-to-end tests / Playwright E2E tests (1/8) (push) Blocked by required conditions
End-to-end tests / Playwright E2E tests (2/8) (push) Blocked by required conditions
End-to-end tests / Playwright E2E tests (3/8) (push) Blocked by required conditions
End-to-end tests / Playwright E2E tests (4/8) (push) Blocked by required conditions
End-to-end tests / Playwright E2E tests (5/8) (push) Blocked by required conditions
End-to-end tests / Playwright E2E tests (6/8) (push) Blocked by required conditions
End-to-end tests / Playwright E2E tests (7/8) (push) Blocked by required conditions
End-to-end tests / Playwright E2E tests (8/8) (push) Blocked by required conditions
End-to-end tests / run-azure-monitor-e2e (push) Blocked by required conditions
End-to-end tests / All Playwright tests complete (push) Blocked by required conditions
End-to-end tests / A11y test (push) Blocked by required conditions
End-to-end tests / Publish metrics (push) Blocked by required conditions
End-to-end tests / All E2E tests complete (push) Blocked by required conditions
Frontend tests / Detect whether code changed (push) Waiting to run
Frontend tests / Unit tests (1 / 16) (push) Blocked by required conditions
Frontend tests / Unit tests (10 / 16) (push) Blocked by required conditions
Frontend tests / Unit tests (11 / 16) (push) Blocked by required conditions
Frontend tests / Unit tests (12 / 16) (push) Blocked by required conditions
Frontend tests / Unit tests (13 / 16) (push) Blocked by required conditions
Frontend tests / Unit tests (14 / 16) (push) Blocked by required conditions
Frontend tests / Unit tests (15 / 16) (push) Blocked by required conditions
Frontend tests / Unit tests (16 / 16) (push) Blocked by required conditions
Frontend tests / Unit tests (2 / 16) (push) Blocked by required conditions
Frontend tests / Unit tests (3 / 16) (push) Blocked by required conditions
Frontend tests / Unit tests (4 / 16) (push) Blocked by required conditions
Frontend tests / Unit tests (5 / 16) (push) Blocked by required conditions
Frontend tests / Unit tests (6 / 16) (push) Blocked by required conditions
Frontend tests / Unit tests (7 / 16) (push) Blocked by required conditions
Frontend tests / Unit tests (8 / 16) (push) Blocked by required conditions
Frontend tests / Unit tests (9 / 16) (push) Blocked by required conditions
Frontend tests / Decoupled plugin tests (push) Blocked by required conditions
Frontend tests / Packages unit tests (push) Blocked by required conditions
Frontend tests / All frontend unit tests complete (push) Blocked by required conditions
Frontend tests / Devenv frontend-service build (push) Blocked by required conditions
Integration Tests / Detect whether code changed (push) Waiting to run
Integration Tests / Sqlite (1/4) (push) Blocked by required conditions
Integration Tests / Sqlite (2/4) (push) Blocked by required conditions
Integration Tests / Sqlite (3/4) (push) Blocked by required conditions
Integration Tests / Sqlite (4/4) (push) Blocked by required conditions
Integration Tests / Sqlite Without CGo (1/4) (push) Blocked by required conditions
Integration Tests / Sqlite Without CGo (2/4) (push) Blocked by required conditions
Integration Tests / Sqlite Without CGo (3/4) (push) Blocked by required conditions
Integration Tests / Sqlite Without CGo (4/4) (push) Blocked by required conditions
Integration Tests / Sqlite Without CGo (profiled) (push) Blocked by required conditions
Integration Tests / MySQL (1/16) (push) Blocked by required conditions
Integration Tests / MySQL (10/16) (push) Blocked by required conditions
Integration Tests / MySQL (11/16) (push) Blocked by required conditions
Integration Tests / MySQL (12/16) (push) Blocked by required conditions
Integration Tests / MySQL (13/16) (push) Blocked by required conditions
Integration Tests / MySQL (14/16) (push) Blocked by required conditions
Integration Tests / MySQL (15/16) (push) Blocked by required conditions
Integration Tests / MySQL (16/16) (push) Blocked by required conditions
Integration Tests / MySQL (2/16) (push) Blocked by required conditions
Integration Tests / MySQL (3/16) (push) Blocked by required conditions
Integration Tests / MySQL (4/16) (push) Blocked by required conditions
Integration Tests / MySQL (5/16) (push) Blocked by required conditions
Integration Tests / MySQL (6/16) (push) Blocked by required conditions
Integration Tests / MySQL (7/16) (push) Blocked by required conditions
Integration Tests / MySQL (8/16) (push) Blocked by required conditions
Integration Tests / MySQL (9/16) (push) Blocked by required conditions
Integration Tests / Postgres (1/16) (push) Blocked by required conditions
Integration Tests / Postgres (10/16) (push) Blocked by required conditions
Integration Tests / Postgres (11/16) (push) Blocked by required conditions
Integration Tests / Postgres (12/16) (push) Blocked by required conditions
Integration Tests / Postgres (13/16) (push) Blocked by required conditions
Integration Tests / Postgres (14/16) (push) Blocked by required conditions
Integration Tests / Postgres (15/16) (push) Blocked by required conditions
Integration Tests / Postgres (16/16) (push) Blocked by required conditions
Integration Tests / Postgres (2/16) (push) Blocked by required conditions
Integration Tests / Postgres (3/16) (push) Blocked by required conditions
Integration Tests / Postgres (4/16) (push) Blocked by required conditions
Integration Tests / Postgres (5/16) (push) Blocked by required conditions
Integration Tests / Postgres (6/16) (push) Blocked by required conditions
Integration Tests / Postgres (7/16) (push) Blocked by required conditions
Integration Tests / Postgres (8/16) (push) Blocked by required conditions
Integration Tests / Postgres (9/16) (push) Blocked by required conditions
Integration Tests / All backend integration tests complete (push) Blocked by required conditions
Reject GitHub secrets / reject-gh-secrets (push) Waiting to run
Build Release Packages / setup (push) Waiting to run
Build Release Packages / Dispatch grafana-enterprise build (push) Blocked by required conditions
Build Release Packages / / darwin-amd64 (push) Blocked by required conditions
Build Release Packages / / darwin-arm64 (push) Blocked by required conditions
Build Release Packages / / linux-amd64 (push) Blocked by required conditions
Build Release Packages / / linux-armv6 (push) Blocked by required conditions
Build Release Packages / / linux-armv7 (push) Blocked by required conditions
Build Release Packages / / linux-arm64 (push) Blocked by required conditions
Build Release Packages / / linux-s390x (push) Blocked by required conditions
Build Release Packages / / windows-amd64 (push) Blocked by required conditions
Build Release Packages / / windows-arm64 (push) Blocked by required conditions
Build Release Packages / Upload artifacts (push) Blocked by required conditions
Build Release Packages / publish-dockerhub (push) Blocked by required conditions
Build Release Packages / Dispatch publish NPM canaries (push) Blocked by required conditions
Build Release Packages / notify-pr (push) Blocked by required conditions
Run dashboard schema v2 e2e / dashboard-schema-v2-e2e (push) Waiting to run
Shellcheck / Shellcheck scripts (push) Waiting to run
Run Storybook a11y tests / Detect whether code changed (push) Waiting to run
Run Storybook a11y tests / Run Storybook a11y tests (light theme) (push) Blocked by required conditions
Run Storybook a11y tests / Run Storybook a11y tests (dark theme) (push) Blocked by required conditions
Swagger generated code / Detect whether code changed (push) Waiting to run
Swagger generated code / Verify committed API specs match (push) Blocked by required conditions
Dispatch sync to mirror / dispatch-job (push) Waiting to run
Trivy Scan / trivy-scan (push) Waiting to run
trigger-dashboard-search-e2e / trigger-search-e2e (push) Has been cancelled
* remove dependency on packages * update tests * trigger
209 lines
7.9 KiB
Go
209 lines
7.9 KiB
Go
package setting
|
|
|
|
import (
|
|
"os"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"gopkg.in/ini.v1"
|
|
|
|
"github.com/grafana/grafana/pkg/plugins/config"
|
|
"github.com/grafana/grafana/pkg/util"
|
|
)
|
|
|
|
const (
|
|
PluginUpdateStrategyLatest = "latest"
|
|
PluginUpdateStrategyMinor = "minor"
|
|
)
|
|
|
|
func extractPluginSettings(sections []*ini.Section) config.PluginSettings {
|
|
psMap := config.PluginSettings{}
|
|
for _, section := range sections {
|
|
sectionName := section.Name()
|
|
if !strings.HasPrefix(sectionName, "plugin.") {
|
|
continue
|
|
}
|
|
|
|
pluginID := strings.Replace(sectionName, "plugin.", "", 1)
|
|
psMap[pluginID] = section.KeysHash()
|
|
}
|
|
|
|
return psMap
|
|
}
|
|
|
|
var (
|
|
defaultPreinstallPlugins = map[string]InstallPlugin{
|
|
// Default preinstalled plugins
|
|
"grafana-lokiexplore-app": {ID: "grafana-lokiexplore-app"},
|
|
"grafana-pyroscope-app": {ID: "grafana-pyroscope-app"},
|
|
"grafana-exploretraces-app": {ID: "grafana-exploretraces-app"},
|
|
"grafana-metricsdrilldown-app": {ID: "grafana-metricsdrilldown-app"},
|
|
}
|
|
)
|
|
|
|
func (cfg *Cfg) migrateInstallPluginsToPreinstallPluginsSync(rawInstallPlugins, installPluginsForce string, preinstallPluginsSync map[string]InstallPlugin) {
|
|
if strings.ToLower(installPluginsForce) == "true" || rawInstallPlugins == "" {
|
|
cfg.Logger.Debug("GF_INSTALL_PLUGINS_FORCE is set to true, skipping migration of GF_INSTALL_PLUGINS to GF_PLUGINS_PREINSTALL_SYNC")
|
|
return
|
|
}
|
|
installPluginsEntries := strings.Split(rawInstallPlugins, ",")
|
|
|
|
// Format 1: ID only (e.g., "grafana-clock-panel")
|
|
// Format 2: ID with version (e.g., "grafana-clock-panel 1.0.1")
|
|
// Format 3: URL with folder (e.g., "https://grafana.com/api/plugins/grafana-clock-panel/versions/latest/download;grafana-clock-panel")
|
|
pluginRegex := regexp.MustCompile(`(?:([^;]+);)?([^;\s]+)(?:\s+(.+))?`)
|
|
for _, entry := range installPluginsEntries {
|
|
trimmedEntry := strings.TrimSpace(entry)
|
|
if trimmedEntry == "" {
|
|
continue
|
|
}
|
|
|
|
matches := pluginRegex.FindStringSubmatch(trimmedEntry)
|
|
|
|
if matches == nil {
|
|
cfg.Logger.Debug("No match found for entry: ", trimmedEntry)
|
|
continue
|
|
}
|
|
|
|
url := ""
|
|
if len(matches) > 1 {
|
|
url = strings.TrimSpace(matches[1])
|
|
}
|
|
|
|
id := ""
|
|
if len(matches) > 2 {
|
|
id = strings.TrimSpace(matches[2])
|
|
}
|
|
if _, exists := preinstallPluginsSync[id]; exists {
|
|
continue
|
|
}
|
|
|
|
version := ""
|
|
if len(matches) > 3 {
|
|
version = strings.TrimSpace(matches[3])
|
|
}
|
|
if id != "" {
|
|
preinstallPluginsSync[id] = InstallPlugin{ID: id, Version: version, URL: url}
|
|
} else {
|
|
cfg.Logger.Debug("No ID found for entry: ", trimmedEntry, "matches: ", matches)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (cfg *Cfg) processPreinstallPlugins(rawInstallPlugins []string, preinstallPlugins map[string]InstallPlugin) {
|
|
// Add the plugins defined in the configuration
|
|
for _, plugin := range rawInstallPlugins {
|
|
parts := strings.Split(plugin, "@")
|
|
id := parts[0]
|
|
version := ""
|
|
url := ""
|
|
if len(parts) > 1 {
|
|
version = parts[1]
|
|
if len(parts) > 2 {
|
|
url = strings.Join(parts[2:], "@")
|
|
}
|
|
}
|
|
|
|
preinstallPlugins[id] = InstallPlugin{id, version, url}
|
|
}
|
|
}
|
|
|
|
// readPluginAPIRestrictionsSection reads a plugin API restrictions section and returns a map of API names to plugin lists
|
|
func readPluginAPIRestrictionsSection(iniFile *ini.File, sectionName string) map[string][]string {
|
|
result := make(map[string][]string)
|
|
|
|
if !iniFile.HasSection(sectionName) {
|
|
return result
|
|
}
|
|
|
|
section := iniFile.Section(sectionName)
|
|
for _, key := range section.Keys() {
|
|
apiName := key.Name()
|
|
pluginList := util.SplitString(key.MustString(""))
|
|
if len(pluginList) > 0 {
|
|
result[apiName] = pluginList
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func (cfg *Cfg) readPluginSettings(iniFile *ini.File) error {
|
|
pluginsSection := iniFile.Section("plugins")
|
|
|
|
cfg.PluginsEnableAlpha = pluginsSection.Key("enable_alpha").MustBool(false)
|
|
cfg.PluginsAppsSkipVerifyTLS = pluginsSection.Key("app_tls_skip_verify_insecure").MustBool(false)
|
|
cfg.PluginSettings = extractPluginSettings(iniFile.Sections())
|
|
cfg.PluginSkipPublicKeyDownload = pluginsSection.Key("public_key_retrieval_disabled").MustBool(false)
|
|
cfg.PluginForcePublicKeyDownload = pluginsSection.Key("public_key_retrieval_on_startup").MustBool(false)
|
|
|
|
cfg.PluginsAllowUnsigned = util.SplitString(pluginsSection.Key("allow_loading_unsigned_plugins").MustString(""))
|
|
cfg.DisablePlugins = util.SplitString(pluginsSection.Key("disable_plugins").MustString(""))
|
|
cfg.ForwardHostEnvVars = util.SplitString(pluginsSection.Key("forward_host_env_vars").MustString(""))
|
|
disablePreinstall := pluginsSection.Key("preinstall_disabled").MustBool(false)
|
|
if !disablePreinstall {
|
|
rawInstallPluginsAsync := util.SplitString(pluginsSection.Key("preinstall").MustString(""))
|
|
preinstallPluginsAsync := make(map[string]InstallPlugin)
|
|
// Add the default preinstalled plugins to pre install plugins async list
|
|
for _, plugin := range defaultPreinstallPlugins {
|
|
preinstallPluginsAsync[plugin.ID] = plugin
|
|
}
|
|
if cfg.IsFeatureToggleEnabled("grafanaAdvisor") { // Use literal string to avoid circular dependency
|
|
preinstallPluginsAsync["grafana-advisor-app"] = InstallPlugin{"grafana-advisor-app", "", ""}
|
|
}
|
|
if cfg.IsFeatureToggleEnabled("interactiveLearning") { // Use literal string to avoid circular dependency
|
|
preinstallPluginsAsync["grafana-pathfinder-app"] = InstallPlugin{"grafana-pathfinder-app", "", ""}
|
|
}
|
|
cfg.processPreinstallPlugins(rawInstallPluginsAsync, preinstallPluginsAsync)
|
|
|
|
rawInstallPluginsSync := util.SplitString(pluginsSection.Key("preinstall_sync").MustString(""))
|
|
preinstallPluginsSync := make(map[string]InstallPlugin)
|
|
cfg.processPreinstallPlugins(rawInstallPluginsSync, preinstallPluginsSync)
|
|
cfg.migrateInstallPluginsToPreinstallPluginsSync(os.Getenv("GF_INSTALL_PLUGINS"), os.Getenv("GF_INSTALL_PLUGINS_FORCE"), preinstallPluginsSync)
|
|
// Remove from the list the plugins that have been disabled
|
|
for _, disabledPlugin := range cfg.DisablePlugins {
|
|
delete(preinstallPluginsAsync, disabledPlugin)
|
|
delete(preinstallPluginsSync, disabledPlugin)
|
|
}
|
|
for _, plugin := range preinstallPluginsSync {
|
|
cfg.PreinstallPluginsSync = append(cfg.PreinstallPluginsSync, plugin)
|
|
// preinstallSync plugin has priority over preinstallAsync
|
|
delete(preinstallPluginsAsync, plugin.ID)
|
|
}
|
|
for _, plugin := range preinstallPluginsAsync {
|
|
cfg.PreinstallPluginsAsync = append(cfg.PreinstallPluginsAsync, plugin)
|
|
}
|
|
|
|
installPluginsInAsync := pluginsSection.Key("preinstall_async").MustBool(true)
|
|
if !installPluginsInAsync {
|
|
for key, plugin := range preinstallPluginsAsync {
|
|
if _, exists := preinstallPluginsSync[key]; !exists {
|
|
cfg.PreinstallPluginsSync = append(cfg.PreinstallPluginsSync, plugin)
|
|
}
|
|
}
|
|
cfg.PreinstallPluginsAsync = nil
|
|
}
|
|
|
|
cfg.PreinstallAutoUpdate = pluginsSection.Key("preinstall_auto_update").MustBool(true)
|
|
}
|
|
|
|
cfg.PluginCatalogURL = pluginsSection.Key("plugin_catalog_url").MustString("https://grafana.com/grafana/plugins/")
|
|
cfg.PluginAdminEnabled = pluginsSection.Key("plugin_admin_enabled").MustBool(true)
|
|
cfg.PluginAdminExternalManageEnabled = pluginsSection.Key("plugin_admin_external_manage_enabled").MustBool(false)
|
|
cfg.PluginCatalogHiddenPlugins = util.SplitString(pluginsSection.Key("plugin_catalog_hidden_plugins").MustString(""))
|
|
|
|
// Pull disabled plugins from the catalog
|
|
cfg.PluginCatalogHiddenPlugins = append(cfg.PluginCatalogHiddenPlugins, cfg.DisablePlugins...)
|
|
|
|
// Plugins CDN settings
|
|
cfg.PluginsCDNURLTemplate = strings.TrimRight(pluginsSection.Key("cdn_base_url").MustString(""), "/")
|
|
cfg.PluginLogBackendRequests = pluginsSection.Key("log_backend_requests").MustBool(false)
|
|
|
|
cfg.PluginUpdateStrategy = pluginsSection.Key("update_strategy").In(PluginUpdateStrategyLatest, []string{PluginUpdateStrategyLatest, PluginUpdateStrategyMinor})
|
|
|
|
// Plugin API restrictions - read from sections
|
|
cfg.PluginRestrictedAPIsAllowList = readPluginAPIRestrictionsSection(iniFile, "plugins.restricted_apis_allowlist")
|
|
cfg.PluginRestrictedAPIsBlockList = readPluginAPIRestrictionsSection(iniFile, "plugins.restricted_apis_blocklist")
|
|
|
|
return nil
|
|
}
|