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/manager/loader/angular/angularinspector/angularinspector.go

79 lines
2.9 KiB

Plugins: Angular detector: Remote patterns fetching (#69843) * Plugins: Angular detector: Remote patterns fetching * Renamed PatternType to GCOMPatternType * Renamed files * Renamed more files * Moved files again * Add type checks, unexport GCOM structs * Cache failures, update log messages, fix GCOM URL * Fail silently for unknown pattern types, update docstrings * Fix tests * Rename gcomPattern.Value to gcomPattern.Pattern * Refactoring * Add FlagPluginsRemoteAngularDetectionPatterns feature flag * Fix tests * Re-generate feature flags * Add TestProvideInspector, renamed TestDefaultStaticDetectorsInspector * Add TestProvideInspector * Add TestContainsBytesDetector and TestRegexDetector * Renamed getter to provider * More tests * TestStaticDetectorsProvider, TestSequenceDetectorsProvider * GCOM tests * Lint * Made detector.detect unexported, updated docstrings * Allow changing grafana.com URL * Fix API path, add more logs * Update tryUpdateRemoteDetectors docstring * Use angulardetector http client * Return false, nil if module.js does not exist * Chore: Split angualrdetector into angularinspector and angulardetector packages Moved files around, changed references and fixed tests: - Split the old angulardetector package into angular/angulardetector and angular/angularinspector - angulardetector provides the detection structs/interfaces (Detector, DetectorsProvider...) - angularinspector provides the actual angular detection service used directly in pluginsintegration - Exported most of the stuff that was private and now put into angulardetector, as it is not required by angularinspector * Renamed detector.go -> angulardetector.go and inspector.go -> angularinspector.go Forgot to rename those two files to match the package's names * Renamed angularinspector.ProvideInspector to angularinspector.ProvideService * Renamed "harcoded" to "static" and "remote" to "dynamic" from PR review, matches the same naming schema used for signing keys fetching * Fix merge conflict on updated angular patterns * Removed GCOM cache * Renamed Detect to DetectAngular and Detector to AngularDetector * Fix call to NewGCOMDetectorsProvider in newDynamicInspector * Removed unused test function newError500GCOMScenario * Added angularinspector service definition in pluginsintegration * Moved dynamic inspector into pluginsintegration * Move gcom angulardetectorsprovider into pluginsintegration * Log errUnknownPatternType at debug level * re-generate feature flags * fix error log
3 years ago
package angularinspector
import (
"context"
"errors"
"fmt"
"io"
"regexp"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/manager/loader/angular/angulardetector"
)
// Inspector can inspect a plugin and determine if it's an Angular plugin or not.
type Inspector interface {
// Inspect takes a plugin and checks if the plugin is using Angular.
Inspect(ctx context.Context, p *plugins.Plugin) (bool, error)
}
// PatternsListInspector is an Inspector that matches a plugin's module.js against all the patterns returned by
// the detectorsProvider, in sequence.
type PatternsListInspector struct {
// DetectorsProvider returns the detectors that will be used by Inspect.
DetectorsProvider angulardetector.DetectorsProvider
}
func (i *PatternsListInspector) Inspect(ctx context.Context, p *plugins.Plugin) (isAngular bool, err error) {
f, err := p.FS.Open("module.js")
if err != nil {
if errors.Is(err, plugins.ErrFileNotExist) {
// We may not have a module.js for some backend plugins, so ignore the error if module.js does not exist
return false, nil
}
return false, err
}
defer func() {
if closeErr := f.Close(); closeErr != nil && err == nil {
err = fmt.Errorf("close module.js: %w", closeErr)
}
}()
b, err := io.ReadAll(f)
if err != nil {
return false, fmt.Errorf("module.js readall: %w", err)
}
for _, d := range i.DetectorsProvider.ProvideDetectors(ctx) {
if d.DetectAngular(b) {
isAngular = true
break
}
}
return
}
// defaultDetectors contains all the detectors to DetectAngular Angular plugins.
// They are executed in the specified order.
var defaultDetectors = []angulardetector.AngularDetector{
&angulardetector.ContainsBytesDetector{Pattern: []byte("PanelCtrl")},
&angulardetector.ContainsBytesDetector{Pattern: []byte("ConfigCtrl")},
&angulardetector.ContainsBytesDetector{Pattern: []byte("app/plugins/sdk")},
&angulardetector.ContainsBytesDetector{Pattern: []byte("angular.isNumber(")},
&angulardetector.ContainsBytesDetector{Pattern: []byte("editor.html")},
&angulardetector.ContainsBytesDetector{Pattern: []byte("ctrl.annotation")},
&angulardetector.ContainsBytesDetector{Pattern: []byte("getLegacyAngularInjector")},
&angulardetector.RegexDetector{Regex: regexp.MustCompile(`["']QueryCtrl["']`)},
}
// NewDefaultStaticDetectorsProvider returns a new StaticDetectorsProvider with the default (static, hardcoded) angular
// detection patterns (defaultDetectors)
func NewDefaultStaticDetectorsProvider() angulardetector.DetectorsProvider {
return &angulardetector.StaticDetectorsProvider{Detectors: defaultDetectors}
}
// NewStaticInspector returns the default Inspector, which is a PatternsListInspector that only uses the
// static (hardcoded) angular detection patterns.
func NewStaticInspector() (Inspector, error) {
return &PatternsListInspector{DetectorsProvider: NewDefaultStaticDetectorsProvider()}, nil
}