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/fakes/fakes.go

584 lines
15 KiB

package fakes
import (
"archive/zip"
"context"
"fmt"
"io/fs"
"sync"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/auth"
"github.com/grafana/grafana/pkg/plugins/backendplugin"
"github.com/grafana/grafana/pkg/plugins/log"
"github.com/grafana/grafana/pkg/plugins/plugindef"
"github.com/grafana/grafana/pkg/plugins/repo"
"github.com/grafana/grafana/pkg/plugins/storage"
)
type FakePluginInstaller struct {
AddFunc func(ctx context.Context, pluginID, version string, opts plugins.CompatOpts) error
// Remove removes a plugin from the store.
RemoveFunc func(ctx context.Context, pluginID string) error
}
func (i *FakePluginInstaller) Add(ctx context.Context, pluginID, version string, opts plugins.CompatOpts) error {
if i.AddFunc != nil {
return i.AddFunc(ctx, pluginID, version, opts)
}
return nil
}
func (i *FakePluginInstaller) Remove(ctx context.Context, pluginID string) error {
if i.RemoveFunc != nil {
return i.RemoveFunc(ctx, pluginID)
}
return nil
}
type FakeLoader struct {
LoadFunc func(_ context.Context, _ plugins.PluginSource) ([]*plugins.Plugin, error)
UnloadFunc func(_ context.Context, _ *plugins.Plugin) (*plugins.Plugin, error)
}
func (l *FakeLoader) Load(ctx context.Context, src plugins.PluginSource) ([]*plugins.Plugin, error) {
if l.LoadFunc != nil {
return l.LoadFunc(ctx, src)
}
return nil, nil
}
func (l *FakeLoader) Unload(ctx context.Context, p *plugins.Plugin) (*plugins.Plugin, error) {
if l.UnloadFunc != nil {
return l.UnloadFunc(ctx, p)
}
return nil, nil
}
type FakePluginClient struct {
ID string
Managed bool
Log log.Logger
startCount int
stopCount int
exited bool
decommissioned bool
backend.CollectMetricsHandlerFunc
backend.CheckHealthHandlerFunc
backend.QueryDataHandlerFunc
backend.CallResourceHandlerFunc
mutex sync.RWMutex
backendplugin.Plugin
}
func (pc *FakePluginClient) PluginID() string {
return pc.ID
}
func (pc *FakePluginClient) Logger() log.Logger {
return pc.Log
}
func (pc *FakePluginClient) Start(_ context.Context) error {
pc.mutex.Lock()
defer pc.mutex.Unlock()
pc.exited = false
pc.startCount++
return nil
}
func (pc *FakePluginClient) Stop(_ context.Context) error {
pc.mutex.Lock()
defer pc.mutex.Unlock()
pc.stopCount++
pc.exited = true
return nil
}
func (pc *FakePluginClient) IsManaged() bool {
return pc.Managed
}
func (pc *FakePluginClient) Exited() bool {
pc.mutex.RLock()
defer pc.mutex.RUnlock()
return pc.exited
}
func (pc *FakePluginClient) Decommission() error {
pc.mutex.Lock()
defer pc.mutex.Unlock()
pc.decommissioned = true
return nil
}
func (pc *FakePluginClient) IsDecommissioned() bool {
pc.mutex.RLock()
defer pc.mutex.RUnlock()
return pc.decommissioned
}
func (pc *FakePluginClient) CollectMetrics(ctx context.Context, req *backend.CollectMetricsRequest) (*backend.CollectMetricsResult, error) {
if pc.CollectMetricsHandlerFunc != nil {
return pc.CollectMetricsHandlerFunc(ctx, req)
}
return nil, plugins.ErrMethodNotImplemented
}
func (pc *FakePluginClient) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
if pc.CheckHealthHandlerFunc != nil {
return pc.CheckHealthHandlerFunc(ctx, req)
}
return nil, plugins.ErrMethodNotImplemented
}
func (pc *FakePluginClient) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
if pc.QueryDataHandlerFunc != nil {
return pc.QueryDataHandlerFunc(ctx, req)
}
return nil, plugins.ErrMethodNotImplemented
}
func (pc *FakePluginClient) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
if pc.CallResourceHandlerFunc != nil {
return pc.CallResourceHandlerFunc(ctx, req, sender)
}
return plugins.ErrMethodNotImplemented
}
func (pc *FakePluginClient) SubscribeStream(_ context.Context, _ *backend.SubscribeStreamRequest) (*backend.SubscribeStreamResponse, error) {
return nil, plugins.ErrMethodNotImplemented
}
func (pc *FakePluginClient) PublishStream(_ context.Context, _ *backend.PublishStreamRequest) (*backend.PublishStreamResponse, error) {
return nil, plugins.ErrMethodNotImplemented
}
func (pc *FakePluginClient) RunStream(_ context.Context, _ *backend.RunStreamRequest, _ *backend.StreamSender) error {
return plugins.ErrMethodNotImplemented
}
type FakePluginRegistry struct {
Store map[string]*plugins.Plugin
}
func NewFakePluginRegistry() *FakePluginRegistry {
return &FakePluginRegistry{
Store: make(map[string]*plugins.Plugin),
}
}
func (f *FakePluginRegistry) Plugin(_ context.Context, id string) (*plugins.Plugin, bool) {
p, exists := f.Store[id]
return p, exists
}
func (f *FakePluginRegistry) Plugins(_ context.Context) []*plugins.Plugin {
res := make([]*plugins.Plugin, 0, len(f.Store))
for _, p := range f.Store {
res = append(res, p)
}
return res
}
func (f *FakePluginRegistry) Add(_ context.Context, p *plugins.Plugin) error {
f.Store[p.ID] = p
return nil
}
func (f *FakePluginRegistry) Remove(_ context.Context, id string) error {
delete(f.Store, id)
return nil
}
type FakePluginRepo struct {
GetPluginArchiveFunc func(_ context.Context, pluginID, version string, _ repo.CompatOpts) (*repo.PluginArchive, error)
GetPluginArchiveByURLFunc func(_ context.Context, archiveURL string, _ repo.CompatOpts) (*repo.PluginArchive, error)
GetPluginArchiveInfoFunc func(_ context.Context, pluginID, version string, _ repo.CompatOpts) (*repo.PluginArchiveInfo, error)
}
// GetPluginArchive fetches the requested plugin archive.
func (r *FakePluginRepo) GetPluginArchive(ctx context.Context, pluginID, version string, opts repo.CompatOpts) (*repo.PluginArchive, error) {
if r.GetPluginArchiveFunc != nil {
return r.GetPluginArchiveFunc(ctx, pluginID, version, opts)
}
return &repo.PluginArchive{}, nil
}
// GetPluginArchiveByURL fetches the requested plugin from the specified URL.
func (r *FakePluginRepo) GetPluginArchiveByURL(ctx context.Context, archiveURL string, opts repo.CompatOpts) (*repo.PluginArchive, error) {
if r.GetPluginArchiveByURLFunc != nil {
return r.GetPluginArchiveByURLFunc(ctx, archiveURL, opts)
}
return &repo.PluginArchive{}, nil
}
// GetPluginArchiveInfo fetches information for downloading the requested plugin.
func (r *FakePluginRepo) GetPluginArchiveInfo(ctx context.Context, pluginID, version string, opts repo.CompatOpts) (*repo.PluginArchiveInfo, error) {
if r.GetPluginArchiveInfoFunc != nil {
return r.GetPluginArchiveInfoFunc(ctx, pluginID, version, opts)
}
return &repo.PluginArchiveInfo{}, nil
}
type FakePluginStorage struct {
ExtractFunc func(_ context.Context, pluginID string, dirNameFunc storage.DirNameGeneratorFunc, z *zip.ReadCloser) (*storage.ExtractedPluginArchive, error)
}
func NewFakePluginStorage() *FakePluginStorage {
return &FakePluginStorage{}
}
func (s *FakePluginStorage) Extract(ctx context.Context, pluginID string, dirNameFunc storage.DirNameGeneratorFunc, z *zip.ReadCloser) (*storage.ExtractedPluginArchive, error) {
if s.ExtractFunc != nil {
return s.ExtractFunc(ctx, pluginID, dirNameFunc, z)
}
return &storage.ExtractedPluginArchive{}, nil
}
type FakeProcessManager struct {
StartFunc func(_ context.Context, p *plugins.Plugin) error
StopFunc func(_ context.Context, p *plugins.Plugin) error
Started map[string]int
Stopped map[string]int
}
func NewFakeProcessManager() *FakeProcessManager {
return &FakeProcessManager{
Started: make(map[string]int),
Stopped: make(map[string]int),
}
}
func (m *FakeProcessManager) Start(ctx context.Context, p *plugins.Plugin) error {
m.Started[p.ID]++
if m.StartFunc != nil {
return m.StartFunc(ctx, p)
}
return nil
}
func (m *FakeProcessManager) Stop(ctx context.Context, p *plugins.Plugin) error {
m.Stopped[p.ID]++
if m.StopFunc != nil {
return m.StopFunc(ctx, p)
}
return nil
}
type FakeBackendProcessProvider struct {
Requested map[string]int
Invoked map[string]int
BackendFactoryFunc func(context.Context, *plugins.Plugin) backendplugin.PluginFactoryFunc
}
func NewFakeBackendProcessProvider() *FakeBackendProcessProvider {
f := &FakeBackendProcessProvider{
Requested: make(map[string]int),
Invoked: make(map[string]int),
}
f.BackendFactoryFunc = func(ctx context.Context, p *plugins.Plugin) backendplugin.PluginFactoryFunc {
f.Requested[p.ID]++
return func(pluginID string, _ log.Logger, _ func() []string) (backendplugin.Plugin, error) {
f.Invoked[pluginID]++
return &FakePluginClient{}, nil
}
}
return f
}
func (pr *FakeBackendProcessProvider) BackendFactory(ctx context.Context, p *plugins.Plugin) backendplugin.PluginFactoryFunc {
return pr.BackendFactoryFunc(ctx, p)
}
type FakeLicensingService struct {
LicenseEdition string
TokenRaw string
LicensePath string
LicenseAppURL string
}
func NewFakeLicensingService() *FakeLicensingService {
return &FakeLicensingService{}
}
func (s *FakeLicensingService) Edition() string {
return s.LicenseEdition
}
func (s *FakeLicensingService) Path() string {
return s.LicensePath
}
func (s *FakeLicensingService) AppURL() string {
return s.LicenseAppURL
}
func (s *FakeLicensingService) Environment() []string {
return []string{fmt.Sprintf("GF_ENTERPRISE_LICENSE_TEXT=%s", s.TokenRaw)}
}
RBAC: Allow role registration for plugins (#57387) * Picking role registration from OnCall POC branch * Fix test * Remove include actions from this PR * Removing unused permission * Adding test to DeclarePluginRoles * Add testcase to RegisterFixed role * Additional test case * Adding tests to validate plugins roles * Add test to plugin loader * Nit. * Scuemata validation * Changing the design to decouple accesscontrol from plugin management Co-authored-by: Kalle Persson <kalle.persson@grafana.com> * Fixing tests Co-authored-by: Jguer <joao.guerreiro@grafana.com> * Add missing files Co-authored-by: Jguer <joao.guerreiro@grafana.com> * Remove feature toggle check from loader * Remove feature toggleimport * Feedback Co-Authored-By: marefr <marcus.efraimsson@gmail.com> * Fix test' * Make plugins.RoleRegistry interface typed * Remove comment question * No need for json tags anymore * Nit. log * Adding the schema validation * Remove group to take plugin Name instead * Revert sqlstore -> db * Nit. * Nit. on tests Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> * Update pkg/services/accesscontrol/plugins.go Co-authored-by: Ieva <ieva.vasiljeva@grafana.com> * Log message Co-Authored-By: marefr <marcus.efraimsson@gmail.com> * Log message Co-Authored-By: marefr <marcus.efraimsson@gmail.com> * Remove unecessary method. Update test name. Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> * Fix linting * Update cue descriptions * Fix test Co-authored-by: Kalle Persson <kalle.persson@grafana.com> Co-authored-by: Jguer <joao.guerreiro@grafana.com> Co-authored-by: marefr <marcus.efraimsson@gmail.com> Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com>
3 years ago
type FakeRoleRegistry struct {
ExpectedErr error
}
func NewFakeRoleRegistry() *FakeRoleRegistry {
return &FakeRoleRegistry{}
}
func (f *FakeRoleRegistry) DeclarePluginRoles(_ context.Context, _ string, _ string, _ []plugins.RoleRegistration) error {
return f.ExpectedErr
}
type FakePluginFiles struct {
OpenFunc func(name string) (fs.File, error)
RemoveFunc func() error
base string
}
func NewFakePluginFiles(base string) *FakePluginFiles {
return &FakePluginFiles{
base: base,
}
}
func (f *FakePluginFiles) Open(name string) (fs.File, error) {
if f.OpenFunc != nil {
return f.OpenFunc(name)
}
return nil, nil
}
func (f *FakePluginFiles) Base() string {
return f.base
}
func (f *FakePluginFiles) Files() ([]string, error) {
return []string{}, nil
}
func (f *FakePluginFiles) Remove() error {
if f.RemoveFunc != nil {
return f.RemoveFunc()
}
return nil
}
type FakeSourceRegistry struct {
ListFunc func(_ context.Context) []plugins.PluginSource
}
func (s *FakeSourceRegistry) List(ctx context.Context) []plugins.PluginSource {
if s.ListFunc != nil {
return s.ListFunc(ctx)
}
return []plugins.PluginSource{}
}
type FakePluginSource struct {
PluginClassFunc func(ctx context.Context) plugins.Class
PluginURIsFunc func(ctx context.Context) []string
DefaultSignatureFunc func(ctx context.Context) (plugins.Signature, bool)
}
func (s *FakePluginSource) PluginClass(ctx context.Context) plugins.Class {
if s.PluginClassFunc != nil {
return s.PluginClassFunc(ctx)
}
return ""
}
func (s *FakePluginSource) PluginURIs(ctx context.Context) []string {
if s.PluginURIsFunc != nil {
return s.PluginURIsFunc(ctx)
}
return []string{}
}
func (s *FakePluginSource) DefaultSignature(ctx context.Context) (plugins.Signature, bool) {
if s.DefaultSignatureFunc != nil {
return s.DefaultSignatureFunc(ctx)
}
return plugins.Signature{}, false
}
type FakePluginFileStore struct {
FileFunc func(ctx context.Context, pluginID, filename string) (*plugins.File, error)
}
func (f *FakePluginFileStore) File(ctx context.Context, pluginID, filename string) (*plugins.File, error) {
if f.FileFunc != nil {
return f.FileFunc(ctx, pluginID, filename)
}
return nil, nil
}
type FakeAuthService struct {
Result *auth.ExternalService
}
func (f *FakeAuthService) RegisterExternalService(ctx context.Context, name string, svc *plugindef.ExternalServiceRegistration) (*auth.ExternalService, error) {
return f.Result, nil
}
type FakeDiscoverer struct {
DiscoverFunc func(ctx context.Context, src plugins.PluginSource) ([]*plugins.FoundBundle, error)
}
func (f *FakeDiscoverer) Discover(ctx context.Context, src plugins.PluginSource) ([]*plugins.FoundBundle, error) {
if f.DiscoverFunc != nil {
return f.DiscoverFunc(ctx, src)
}
return []*plugins.FoundBundle{}, nil
}
type FakeBootstrapper struct {
BootstrapFunc func(ctx context.Context, src plugins.PluginSource, bundles []*plugins.FoundBundle) ([]*plugins.Plugin, error)
}
func (f *FakeBootstrapper) Bootstrap(ctx context.Context, src plugins.PluginSource, bundles []*plugins.FoundBundle) ([]*plugins.Plugin, error) {
if f.BootstrapFunc != nil {
return f.BootstrapFunc(ctx, src, bundles)
}
return []*plugins.Plugin{}, nil
}
type FakeValidator struct {
ValidateFunc func(ctx context.Context, ps []*plugins.Plugin) ([]*plugins.Plugin, error)
}
func (f *FakeValidator) Validate(ctx context.Context, ps []*plugins.Plugin) ([]*plugins.Plugin, error) {
if f.ValidateFunc != nil {
return f.ValidateFunc(ctx, ps)
}
return []*plugins.Plugin{}, nil
}
type FakeInitializer struct {
IntializeFunc func(ctx context.Context, ps []*plugins.Plugin) ([]*plugins.Plugin, error)
}
func (f *FakeInitializer) Initialize(ctx context.Context, ps []*plugins.Plugin) ([]*plugins.Plugin, error) {
if f.IntializeFunc != nil {
return f.IntializeFunc(ctx, ps)
}
return []*plugins.Plugin{}, nil
}
type FakeTerminator struct {
TerminateFunc func(ctx context.Context, p *plugins.Plugin) (*plugins.Plugin, error)
}
func (f *FakeTerminator) Terminate(ctx context.Context, p *plugins.Plugin) (*plugins.Plugin, error) {
if f.TerminateFunc != nil {
return f.TerminateFunc(ctx, p)
}
return nil, nil
}
type FakeBackendPlugin struct {
Managed bool
StartCount int
StopCount int
Decommissioned bool
Running bool
// ExitedCheckDoneOrStopped is used to signal that the Exited() or Stop() method has been called.
ExitedCheckDoneOrStopped chan struct{}
mutex sync.RWMutex
backendplugin.Plugin
}
func NewFakeBackendPlugin(managed bool) *FakeBackendPlugin {
return &FakeBackendPlugin{
Managed: managed,
ExitedCheckDoneOrStopped: make(chan struct{}),
}
}
func (p *FakeBackendPlugin) Start(_ context.Context) error {
p.mutex.Lock()
defer p.mutex.Unlock()
p.Running = true
p.StartCount++
return nil
}
func (p *FakeBackendPlugin) Stop(_ context.Context) error {
p.mutex.Lock()
defer p.mutex.Unlock()
p.Running = false
p.StopCount++
go func() { p.ExitedCheckDoneOrStopped <- struct{}{} }()
return nil
}
func (p *FakeBackendPlugin) Decommission() error {
p.mutex.Lock()
defer p.mutex.Unlock()
p.Decommissioned = true
return nil
}
func (p *FakeBackendPlugin) IsDecommissioned() bool {
p.mutex.RLock()
defer p.mutex.RUnlock()
return p.Decommissioned
}
func (p *FakeBackendPlugin) IsManaged() bool {
p.mutex.RLock()
defer p.mutex.RUnlock()
return p.Managed
}
func (p *FakeBackendPlugin) Exited() bool {
p.mutex.RLock()
defer p.mutex.RUnlock()
go func() { p.ExitedCheckDoneOrStopped <- struct{}{} }()
return !p.Running
}
func (p *FakeBackendPlugin) Kill() {
p.mutex.Lock()
defer p.mutex.Unlock()
p.Running = false
}
type FakeFeatureToggles struct {
features map[string]bool
}
func NewFakeFeatureToggles(features ...string) *FakeFeatureToggles {
m := make(map[string]bool)
for _, f := range features {
m[f] = true
}
return &FakeFeatureToggles{
features: m,
}
}
func (f *FakeFeatureToggles) GetEnabled(_ context.Context) map[string]bool {
return f.features
}
func (f *FakeFeatureToggles) IsEnabled(feature string) bool {
return f.features[feature]
}