The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
grafana/pkg/plugins/plugins.go

501 lines
14 KiB

package plugins
import (
"context"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"reflect"
"runtime"
"strings"
"time"
"github.com/grafana/grafana/pkg/infra/fs"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/metrics"
"github.com/grafana/grafana/pkg/plugins/backendplugin"
"github.com/grafana/grafana/pkg/registry"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/util/errutil"
)
var (
DataSources map[string]*DataSourcePlugin
Panels map[string]*PanelPlugin
StaticRoutes []*PluginStaticRoute
Apps map[string]*AppPlugin
Plugins map[string]*PluginBase
PluginTypes map[string]interface{}
Renderer *RendererPlugin
Transform *TransformPlugin
GrafanaLatestVersion string
GrafanaHasUpdate bool
plog log.Logger
pluginScanningErrors map[string]*PluginError
)
type unsignedPluginConditionFunc = func(plugin *PluginBase) bool
type PluginScanner struct {
pluginPath string
errors []error
backendPluginManager backendplugin.Manager
cfg *setting.Cfg
requireSigned bool
log log.Logger
plugins map[string]*PluginBase
allowUnsignedPluginsCondition unsignedPluginConditionFunc
}
type PluginManager struct {
BackendPluginManager backendplugin.Manager `inject:""`
Cfg *setting.Cfg `inject:""`
log log.Logger
scanningErrors []error
// AllowUnsignedPluginsCondition changes the policy for allowing unsigned plugins. Signature validation only runs when plugins are starting
// and running plugins will not be terminated if they violate the new policy.
AllowUnsignedPluginsCondition unsignedPluginConditionFunc
}
func init() {
registry.RegisterService(&PluginManager{})
}
func (pm *PluginManager) Init() error {
pm.log = log.New("plugins")
plog = log.New("plugins")
DataSources = map[string]*DataSourcePlugin{}
StaticRoutes = []*PluginStaticRoute{}
Panels = map[string]*PanelPlugin{}
Apps = map[string]*AppPlugin{}
Plugins = map[string]*PluginBase{}
PluginTypes = map[string]interface{}{
"panel": PanelPlugin{},
"datasource": DataSourcePlugin{},
"app": AppPlugin{},
"renderer": RendererPlugin{},
"transform": TransformPlugin{},
}
pluginScanningErrors = map[string]*PluginError{}
pm.log.Info("Starting plugin search")
plugDir := filepath.Join(setting.StaticRootPath, "app/plugins")
pm.log.Debug("Scanning core plugin directory", "dir", plugDir)
if err := pm.scan(plugDir, false); err != nil {
return errutil.Wrapf(err, "failed to scan core plugin directory '%s'", plugDir)
}
plugDir = pm.Cfg.BundledPluginsPath
pm.log.Debug("Scanning bundled plugins directory", "dir", plugDir)
exists, err := fs.Exists(plugDir)
if err != nil {
return err
}
if exists {
if err := pm.scan(plugDir, false); err != nil {
return errutil.Wrapf(err, "failed to scan bundled plugins directory '%s'", plugDir)
}
}
// check if plugins dir exists
exists, err = fs.Exists(setting.PluginsPath)
if err != nil {
return err
}
if !exists {
if err = os.MkdirAll(setting.PluginsPath, os.ModePerm); err != nil {
pm.log.Error("failed to create external plugins directory", "dir", setting.PluginsPath, "error", err)
} else {
pm.log.Info("External plugins directory created", "directory", setting.PluginsPath)
}
} else {
pm.log.Debug("Scanning external plugins directory", "dir", setting.PluginsPath)
if err := pm.scan(setting.PluginsPath, true); err != nil {
return errutil.Wrapf(err, "failed to scan external plugins directory '%s'",
setting.PluginsPath)
}
}
if err := pm.scanPluginPaths(); err != nil {
return err
}
for _, panel := range Panels {
panel.initFrontendPlugin()
}
for _, ds := range DataSources {
ds.initFrontendPlugin()
}
for _, app := range Apps {
app.initApp()
}
if Renderer != nil {
Renderer.initFrontendPlugin()
}
for _, p := range Plugins {
if p.IsCorePlugin {
p.Signature = PluginSignatureInternal
} else {
metrics.SetPluginBuildInformation(p.Id, p.Type, p.Info.Version)
}
}
return nil
}
func (pm *PluginManager) Run(ctx context.Context) error {
pm.updateAppDashboards()
pm.checkForUpdates()
ticker := time.NewTicker(time.Minute * 10)
run := true
for run {
select {
case <-ticker.C:
pm.checkForUpdates()
case <-ctx.Done():
run = false
}
}
return ctx.Err()
}
// scanPluginPaths scans configured plugin paths.
func (pm *PluginManager) scanPluginPaths() error {
for pluginID, settings := range pm.Cfg.PluginSettings {
path, exists := settings["path"]
if !exists || path == "" {
continue
}
if err := pm.scan(path, true); err != nil {
return errutil.Wrapf(err, "failed to scan directory configured for plugin '%s': '%s'", pluginID, path)
}
}
return nil
}
// scan a directory for plugins.
func (pm *PluginManager) scan(pluginDir string, requireSigned bool) error {
scanner := &PluginScanner{
pluginPath: pluginDir,
backendPluginManager: pm.BackendPluginManager,
cfg: pm.Cfg,
requireSigned: requireSigned,
log: pm.log,
plugins: map[string]*PluginBase{},
allowUnsignedPluginsCondition: pm.AllowUnsignedPluginsCondition,
}
// 1st pass: Scan plugins, also mapping plugins to their respective directories
if err := util.Walk(pluginDir, true, true, scanner.walker); err != nil {
if errors.Is(err, os.ErrNotExist) {
pm.log.Debug("Couldn't scan directory since it doesn't exist", "pluginDir", pluginDir)
return nil
}
if errors.Is(err, os.ErrPermission) {
pm.log.Debug("Couldn't scan directory due to lack of permissions", "pluginDir", pluginDir)
return nil
}
if pluginDir != "data/plugins" {
pm.log.Warn("Could not scan dir", "pluginDir", pluginDir, "err", err)
}
return err
}
pm.log.Debug("Initial plugin loading done")
// 2nd pass: Validate and register plugins
for dpath, plugin := range scanner.plugins {
// Try to find any root plugin
ancestors := strings.Split(dpath, string(filepath.Separator))
ancestors = ancestors[0 : len(ancestors)-1]
aPath := ""
if runtime.GOOS != "windows" && filepath.IsAbs(dpath) {
aPath = "/"
}
for _, a := range ancestors {
aPath = filepath.Join(aPath, a)
if root, ok := scanner.plugins[aPath]; ok {
plugin.Root = root
break
}
}
pm.log.Debug("Found plugin", "id", plugin.Id, "signature", plugin.Signature, "hasRoot", plugin.Root != nil)
signingError := scanner.validateSignature(plugin)
if signingError != nil {
pm.log.Debug("Failed to validate plugin signature. Will skip loading", "id", plugin.Id,
"signature", plugin.Signature, "status", signingError.ErrorCode)
pluginScanningErrors[plugin.Id] = signingError
continue
}
pm.log.Debug("Attempting to add plugin", "id", plugin.Id)
pluginGoType, exists := PluginTypes[plugin.Type]
if !exists {
return fmt.Errorf("unknown plugin type %q", plugin.Type)
}
jsonFPath := filepath.Join(plugin.PluginDir, "plugin.json")
// External plugins need a module.js file for SystemJS to load
if !strings.HasPrefix(jsonFPath, setting.StaticRootPath) && !scanner.IsBackendOnlyPlugin(plugin.Type) {
module := filepath.Join(plugin.PluginDir, "module.js")
exists, err := fs.Exists(module)
if err != nil {
return err
}
if !exists {
scanner.log.Warn("Plugin missing module.js",
"name", plugin.Name,
"warning", "Missing module.js, If you loaded this plugin from git, make sure to compile it.",
"path", module)
}
}
reader, err := os.Open(jsonFPath)
if err != nil {
return err
}
defer reader.Close()
jsonParser := json.NewDecoder(reader)
loader := reflect.New(reflect.TypeOf(pluginGoType)).Interface().(PluginLoader)
// Load the full plugin, and add it to manager
if err := loader.Load(jsonParser, plugin, scanner.backendPluginManager); err != nil {
if errors.Is(err, duplicatePluginError{}) {
pm.log.Warn("Plugin is duplicate", "error", err)
scanner.errors = append(scanner.errors, err)
continue
}
return err
}
pm.log.Debug("Successfully added plugin", "id", plugin.Id)
}
if len(scanner.errors) > 0 {
pm.log.Warn("Some plugins failed to load", "errors", scanner.errors)
pm.scanningErrors = scanner.errors
}
return nil
}
// GetDatasource returns a datasource based on passed pluginID if it exists
//
// This function fetches the datasource from the global variable DataSources in this package.
// Rather then refactor all dependencies on the global variable we can use this as an transition.
func (pm *PluginManager) GetDatasource(pluginID string) (*DataSourcePlugin, bool) {
ds, exist := DataSources[pluginID]
return ds, exist
}
func (s *PluginScanner) walker(currentPath string, f os.FileInfo, err error) error {
// We scan all the subfolders for plugin.json (with some exceptions) so that we also load embedded plugins, for
// example https://github.com/raintank/worldping-app/tree/master/dist/grafana-worldmap-panel worldmap panel plugin
// is embedded in worldping app.
if err != nil {
return err
}
if f.Name() == "node_modules" || f.Name() == "Chromium.app" {
return util.ErrWalkSkipDir
}
if f.IsDir() {
return nil
}
if f.Name() != "plugin.json" {
return nil
}
if err := s.loadPlugin(currentPath); err != nil {
s.log.Error("Failed to load plugin", "error", err, "pluginPath", filepath.Dir(currentPath))
s.errors = append(s.errors, err)
}
return nil
}
func (s *PluginScanner) loadPlugin(pluginJSONFilePath string) error {
s.log.Debug("Loading plugin", "path", pluginJSONFilePath)
currentDir := filepath.Dir(pluginJSONFilePath)
reader, err := os.Open(pluginJSONFilePath)
if err != nil {
return err
}
defer reader.Close()
jsonParser := json.NewDecoder(reader)
pluginCommon := PluginBase{}
if err := jsonParser.Decode(&pluginCommon); err != nil {
return err
}
if pluginCommon.Id == "" || pluginCommon.Type == "" {
return errors.New("did not find type or id properties in plugin.json")
}
// The expressions feature toggle corresponds to transform plug-ins.
if pluginCommon.Type == "transform" {
isEnabled := s.cfg.IsExpressionsEnabled()
if !isEnabled {
s.log.Debug("Transform plugin is disabled since the expressions feature toggle is not enabled",
"pluginID", pluginCommon.Id)
return nil
}
}
pluginCommon.PluginDir = filepath.Dir(pluginJSONFilePath)
pluginCommon.Signature = getPluginSignatureState(s.log, &pluginCommon)
s.plugins[currentDir] = &pluginCommon
return nil
}
func (*PluginScanner) IsBackendOnlyPlugin(pluginType string) bool {
return pluginType == "renderer" || pluginType == "transform"
}
// validateSignature validates a plugin's signature.
func (s *PluginScanner) validateSignature(plugin *PluginBase) *PluginError {
if plugin.Signature == PluginSignatureValid {
s.log.Debug("Plugin has valid signature", "id", plugin.Id)
return nil
}
if plugin.Root != nil {
// If a descendant plugin with invalid signature, set signature to that of root
if plugin.IsCorePlugin || plugin.Signature == PluginSignatureInternal {
s.log.Debug("Not setting descendant plugin's signature to that of root since it's core or internal",
"plugin", plugin.Id, "signature", plugin.Signature, "isCore", plugin.IsCorePlugin)
} else {
s.log.Debug("Setting descendant plugin's signature to that of root", "plugin", plugin.Id,
"root", plugin.Root.Id, "signature", plugin.Signature, "rootSignature", plugin.Root.Signature)
plugin.Signature = plugin.Root.Signature
if plugin.Signature == PluginSignatureValid {
s.log.Debug("Plugin has valid signature (inherited from root)", "id", plugin.Id)
return nil
}
}
} else {
s.log.Debug("Non-valid plugin Signature", "pluginID", plugin.Id, "pluginDir", plugin.PluginDir,
"state", plugin.Signature)
}
// For the time being, we choose to only require back-end plugins to be signed
// NOTE: the state is calculated again when setting metadata on the object
if !plugin.Backend || !s.requireSigned {
return nil
}
switch plugin.Signature {
case PluginSignatureUnsigned:
if allowed := s.allowUnsigned(plugin); !allowed {
s.log.Debug("Plugin is unsigned", "id", plugin.Id)
s.errors = append(s.errors, fmt.Errorf("plugin %q is unsigned", plugin.Id))
return &PluginError{
ErrorCode: signatureMissing,
}
}
s.log.Warn("Running an unsigned backend plugin", "pluginID", plugin.Id, "pluginDir",
plugin.PluginDir)
return nil
case PluginSignatureInvalid:
s.log.Debug("Plugin %q has an invalid signature", plugin.Id)
s.errors = append(s.errors, fmt.Errorf("plugin %q has an invalid signature", plugin.Id))
return &PluginError{
ErrorCode: signatureInvalid,
}
case PluginSignatureModified:
s.log.Debug("Plugin %q has a modified signature", plugin.Id)
s.errors = append(s.errors, fmt.Errorf("plugin %q's signature has been modified", plugin.Id))
return &PluginError{
ErrorCode: signatureModified,
}
default:
panic(fmt.Sprintf("Plugin %q has unrecognized plugin signature state %q", plugin.Id, plugin.Signature))
}
}
func (s *PluginScanner) allowUnsigned(plugin *PluginBase) bool {
if s.allowUnsignedPluginsCondition != nil {
return s.allowUnsignedPluginsCondition(plugin)
}
if setting.Env == setting.Dev {
return true
}
for _, plug := range s.cfg.PluginsAllowUnsigned {
if plug == plugin.Id {
return true
}
}
return false
}
func ScanningErrors() []PluginError {
scanningErrs := make([]PluginError, 0)
for id, e := range pluginScanningErrors {
scanningErrs = append(scanningErrs, PluginError{
ErrorCode: e.ErrorCode,
PluginID: id,
})
}
return scanningErrs
}
func GetPluginMarkdown(pluginId string, name string) ([]byte, error) {
plug, exists := Plugins[pluginId]
if !exists {
return nil, PluginNotFoundError{pluginId}
}
path := filepath.Join(plug.PluginDir, fmt.Sprintf("%s.md", strings.ToUpper(name)))
exists, err := fs.Exists(path)
if err != nil {
return nil, err
}
if !exists {
path = filepath.Join(plug.PluginDir, fmt.Sprintf("%s.md", strings.ToLower(name)))
}
exists, err = fs.Exists(path)
if err != nil {
return nil, err
}
if !exists {
return make([]byte, 0), nil
}
Outdent code after if block that ends with return (golint) This commit fixes the following golint warnings: pkg/bus/bus.go:64:9: if block ends with a return statement, so drop this else and outdent its block pkg/bus/bus.go:84:9: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:137:10: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:177:9: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:183:10: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:199:9: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:208:9: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/components/dynmap/dynmap.go:236:9: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:242:10: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:257:9: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:263:10: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:278:9: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:284:10: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:299:9: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:331:9: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:350:9: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:356:10: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:366:12: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:390:9: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:396:10: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:405:12: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:427:9: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:433:10: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:442:12: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:459:9: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:465:10: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:474:12: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:491:9: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:497:10: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:506:12: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:523:9: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:529:10: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:538:12: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:555:9: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:561:10: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:570:12: if block ends with a return statement, so drop this else and outdent its block pkg/login/ldap.go:55:11: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/login/ldap_test.go:372:10: if block ends with a return statement, so drop this else and outdent its block pkg/middleware/middleware_test.go:213:12: if block ends with a return statement, so drop this else and outdent its block pkg/plugins/dashboard_importer.go:153:11: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/plugins/dashboards_updater.go:39:9: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/plugins/dashboards_updater.go:121:10: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/plugins/plugins.go:210:9: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/plugins/plugins.go:235:9: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/services/alerting/eval_context.go:111:9: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/services/alerting/notifier.go:92:9: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/services/alerting/notifier.go:98:9: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/services/alerting/notifier.go:122:10: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/services/alerting/rule.go:108:10: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/services/alerting/rule.go:118:10: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/services/alerting/rule.go:121:11: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/services/alerting/notifiers/telegram.go:94:10: if block ends with a return statement, so drop this else and outdent its block pkg/services/sqlstore/annotation.go:34:11: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/services/sqlstore/annotation.go:99:11: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/services/sqlstore/dashboard_test.go:107:13: if block ends with a return statement, so drop this else and outdent its block pkg/services/sqlstore/plugin_setting.go:78:10: if block ends with a return statement, so drop this else and outdent its block pkg/services/sqlstore/preferences.go:91:10: if block ends with a return statement, so drop this else and outdent its block pkg/services/sqlstore/user.go:50:10: if block ends with a return statement, so drop this else and outdent its block pkg/services/sqlstore/migrator/migrator.go:106:11: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/services/sqlstore/migrator/postgres_dialect.go:48:10: if block ends with a return statement, so drop this else and outdent its block pkg/tsdb/time_range.go:59:9: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/tsdb/time_range.go:67:9: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/tsdb/cloudwatch/metric_find_query.go:225:9: if block ends with a return statement, so drop this else and outdent its block pkg/util/filepath.go:68:11: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary)
8 years ago
data, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
Outdent code after if block that ends with return (golint) This commit fixes the following golint warnings: pkg/bus/bus.go:64:9: if block ends with a return statement, so drop this else and outdent its block pkg/bus/bus.go:84:9: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:137:10: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:177:9: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:183:10: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:199:9: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:208:9: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/components/dynmap/dynmap.go:236:9: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:242:10: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:257:9: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:263:10: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:278:9: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:284:10: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:299:9: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:331:9: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:350:9: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:356:10: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:366:12: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:390:9: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:396:10: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:405:12: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:427:9: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:433:10: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:442:12: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:459:9: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:465:10: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:474:12: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:491:9: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:497:10: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:506:12: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:523:9: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:529:10: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:538:12: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:555:9: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:561:10: if block ends with a return statement, so drop this else and outdent its block pkg/components/dynmap/dynmap.go:570:12: if block ends with a return statement, so drop this else and outdent its block pkg/login/ldap.go:55:11: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/login/ldap_test.go:372:10: if block ends with a return statement, so drop this else and outdent its block pkg/middleware/middleware_test.go:213:12: if block ends with a return statement, so drop this else and outdent its block pkg/plugins/dashboard_importer.go:153:11: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/plugins/dashboards_updater.go:39:9: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/plugins/dashboards_updater.go:121:10: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/plugins/plugins.go:210:9: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/plugins/plugins.go:235:9: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/services/alerting/eval_context.go:111:9: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/services/alerting/notifier.go:92:9: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/services/alerting/notifier.go:98:9: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/services/alerting/notifier.go:122:10: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/services/alerting/rule.go:108:10: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/services/alerting/rule.go:118:10: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/services/alerting/rule.go:121:11: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/services/alerting/notifiers/telegram.go:94:10: if block ends with a return statement, so drop this else and outdent its block pkg/services/sqlstore/annotation.go:34:11: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/services/sqlstore/annotation.go:99:11: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/services/sqlstore/dashboard_test.go:107:13: if block ends with a return statement, so drop this else and outdent its block pkg/services/sqlstore/plugin_setting.go:78:10: if block ends with a return statement, so drop this else and outdent its block pkg/services/sqlstore/preferences.go:91:10: if block ends with a return statement, so drop this else and outdent its block pkg/services/sqlstore/user.go:50:10: if block ends with a return statement, so drop this else and outdent its block pkg/services/sqlstore/migrator/migrator.go:106:11: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/services/sqlstore/migrator/postgres_dialect.go:48:10: if block ends with a return statement, so drop this else and outdent its block pkg/tsdb/time_range.go:59:9: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/tsdb/time_range.go:67:9: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) pkg/tsdb/cloudwatch/metric_find_query.go:225:9: if block ends with a return statement, so drop this else and outdent its block pkg/util/filepath.go:68:11: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary)
8 years ago
return data, nil
}