Advisor: Add mock checks to standalone setup (#113406)
This commit is contained in:
@@ -15,3 +15,20 @@ generate: install-app-sdk update-app-sdk
|
|||||||
.PHONY: run
|
.PHONY: run
|
||||||
run:
|
run:
|
||||||
@go run ./pkg/standalone/server.go --etcd-servers=http://127.0.0.1:22379 --secure-port 7445
|
@go run ./pkg/standalone/server.go --etcd-servers=http://127.0.0.1:22379 --secure-port 7445
|
||||||
|
|
||||||
|
.PHONY: create-checks
|
||||||
|
create-checks:
|
||||||
|
@echo "Creating plugin check..."
|
||||||
|
@curl -k -X POST https://localhost:7445/apis/advisor.grafana.app/v0alpha1/namespaces/stacks-1/checks \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"kind":"Check","apiVersion":"advisor.grafana.app/v0alpha1","spec":{"data":{}},"metadata":{"generateName":"check-","labels":{"advisor.grafana.app/type":"plugin"},"namespace":"stacks-1"},"status":{"report":{"count":0,"failures":[]}}}' \
|
||||||
|
&& echo "Plugin check created successfully"
|
||||||
|
@echo "Creating datasource check..."
|
||||||
|
@curl -k -X POST https://localhost:7445/apis/advisor.grafana.app/v0alpha1/namespaces/stacks-1/checks \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"kind":"Check","apiVersion":"advisor.grafana.app/v0alpha1","spec":{"data":{}},"metadata":{"generateName":"check-","labels":{"advisor.grafana.app/type":"datasource"},"namespace":"stacks-1"},"status":{"report":{"count":0,"failures":[]}}}' \
|
||||||
|
&& echo "Datasource check created successfully"
|
||||||
|
|
||||||
|
delete-checks:
|
||||||
|
@curl -k -X DELETE https://localhost:7445/apis/advisor.grafana.app/v0alpha1/namespaces/stacks-1/checks \
|
||||||
|
&& echo "All checks deleted successfully"
|
||||||
|
|||||||
@@ -163,3 +163,17 @@ make run # Start the advisor app in standalone mode
|
|||||||
```
|
```
|
||||||
|
|
||||||
This will start the advisor app on port 7445. You can then access the advisor app at `http://localhost:7445`.
|
This will start the advisor app on port 7445. You can then access the advisor app at `http://localhost:7445`.
|
||||||
|
|
||||||
|
To see some sample checks, you can run the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make create-checks
|
||||||
|
```
|
||||||
|
|
||||||
|
Then you can see list in the URL: `http://localhost:7445/apis/advisor.grafana.app/v0alpha1/namespaces/stacks-1/checks`
|
||||||
|
|
||||||
|
To delete all checks, you can run the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make delete-checks
|
||||||
|
```
|
||||||
|
|||||||
@@ -1,12 +1,59 @@
|
|||||||
package mockchecks
|
package mockchecks
|
||||||
|
|
||||||
import "github.com/grafana/grafana/apps/advisor/pkg/app/checks"
|
import (
|
||||||
|
"github.com/grafana/grafana/apps/advisor/pkg/app/checkregistry/mockchecks/mocksvcs"
|
||||||
|
"github.com/grafana/grafana/apps/advisor/pkg/app/checks"
|
||||||
|
"github.com/grafana/grafana/apps/advisor/pkg/app/checks/datasourcecheck"
|
||||||
|
"github.com/grafana/grafana/apps/advisor/pkg/app/checks/plugincheck"
|
||||||
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
|
"github.com/grafana/grafana/pkg/plugins/repo"
|
||||||
|
"github.com/grafana/grafana/pkg/services/datasources"
|
||||||
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginchecker"
|
||||||
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
|
||||||
|
)
|
||||||
|
|
||||||
// mockchecks.CheckRegistry is a mock implementation of the checkregistry.CheckService interface
|
// mockchecks.CheckRegistry is a mock implementation of the checkregistry.CheckService interface
|
||||||
// TODO: Add mocked checks here
|
// TODO: Add mocked checks here
|
||||||
type CheckRegistry struct {
|
type CheckRegistry struct {
|
||||||
|
datasourceSvc datasources.DataSourceService
|
||||||
|
pluginStore pluginstore.Store
|
||||||
|
pluginClient plugins.Client
|
||||||
|
pluginRepo repo.Service
|
||||||
|
GrafanaVersion string
|
||||||
|
pluginContextProvider datasourcecheck.PluginContextProvider
|
||||||
|
updateChecker pluginchecker.PluginUpdateChecker
|
||||||
|
pluginErrorResolver plugins.ErrorResolver
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *CheckRegistry) Checks() []checks.Check {
|
func (m *CheckRegistry) Checks() []checks.Check {
|
||||||
return []checks.Check{}
|
return []checks.Check{
|
||||||
|
datasourcecheck.New(
|
||||||
|
m.datasourceSvc,
|
||||||
|
m.pluginStore,
|
||||||
|
m.pluginContextProvider,
|
||||||
|
m.pluginClient,
|
||||||
|
m.pluginRepo,
|
||||||
|
m.GrafanaVersion,
|
||||||
|
),
|
||||||
|
plugincheck.New(
|
||||||
|
m.pluginStore,
|
||||||
|
m.pluginRepo,
|
||||||
|
m.updateChecker,
|
||||||
|
m.pluginErrorResolver,
|
||||||
|
m.GrafanaVersion,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() *CheckRegistry {
|
||||||
|
return &CheckRegistry{
|
||||||
|
datasourceSvc: &mocksvcs.DatasourceSvc{},
|
||||||
|
pluginStore: &mocksvcs.PluginStore{},
|
||||||
|
pluginClient: &mocksvcs.PluginClient{},
|
||||||
|
pluginRepo: &mocksvcs.PluginRepo{},
|
||||||
|
pluginContextProvider: &mocksvcs.PluginContextProvider{},
|
||||||
|
updateChecker: &mocksvcs.UpdateChecker{},
|
||||||
|
pluginErrorResolver: &mocksvcs.PluginErrorResolver{},
|
||||||
|
GrafanaVersion: "1.0.0",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package mocksvcs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/services/datasources"
|
||||||
|
)
|
||||||
|
|
||||||
|
var dss = map[string]*datasources.DataSource{
|
||||||
|
"prometheus-uid": {
|
||||||
|
ID: 1,
|
||||||
|
UID: "prometheus-uid",
|
||||||
|
Name: "Prometheus",
|
||||||
|
Type: "prometheus",
|
||||||
|
},
|
||||||
|
"mysql-uid": {
|
||||||
|
ID: 2,
|
||||||
|
UID: "mysql-uid",
|
||||||
|
Name: "MySQL",
|
||||||
|
Type: "mysql",
|
||||||
|
},
|
||||||
|
"unknown-uid": {
|
||||||
|
ID: 3,
|
||||||
|
UID: "unknown-uid",
|
||||||
|
Name: "Unknown",
|
||||||
|
Type: "unknown",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
type DatasourceSvc struct {
|
||||||
|
datasources.DataSourceService
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *DatasourceSvc) GetDataSources(ctx context.Context, query *datasources.GetDataSourcesQuery) ([]*datasources.DataSource, error) {
|
||||||
|
sources := make([]*datasources.DataSource, 0, len(dss))
|
||||||
|
for _, ds := range dss {
|
||||||
|
sources = append(sources, ds)
|
||||||
|
}
|
||||||
|
return sources, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *DatasourceSvc) GetDataSource(ctx context.Context, query *datasources.GetDataSourceQuery) (*datasources.DataSource, error) {
|
||||||
|
return dss[query.UID], nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package mocksvcs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PluginClient struct {
|
||||||
|
plugins.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PluginClient) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
|
||||||
|
return &backend.CheckHealthResult{
|
||||||
|
Status: backend.HealthStatusOk,
|
||||||
|
Message: "Plugin is healthy",
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package mocksvcs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
|
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||||
|
"github.com/grafana/grafana/pkg/services/datasources"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PluginContextProvider struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// ACTUALLY USED by datasourcecheck
|
||||||
|
func (m *PluginContextProvider) GetWithDataSource(ctx context.Context, pluginID string, user identity.Requester, ds *datasources.DataSource) (backend.PluginContext, error) {
|
||||||
|
// Create a plugin context with sample data based on the datasource
|
||||||
|
pluginContext := backend.PluginContext{
|
||||||
|
PluginID: pluginID,
|
||||||
|
PluginVersion: "1.0.0",
|
||||||
|
OrgID: 1,
|
||||||
|
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{
|
||||||
|
ID: ds.ID,
|
||||||
|
UID: ds.UID,
|
||||||
|
Name: ds.Name,
|
||||||
|
URL: ds.URL,
|
||||||
|
JSONData: []byte(`{
|
||||||
|
"httpMethod": "GET",
|
||||||
|
"timeout": "30s",
|
||||||
|
"keepCookies": []
|
||||||
|
}`),
|
||||||
|
DecryptedSecureJSONData: map[string]string{
|
||||||
|
"password": "sample-password",
|
||||||
|
"apiKey": "sample-api-key",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
GrafanaConfig: backend.NewGrafanaCfg(map[string]string{
|
||||||
|
"app_url": "http://localhost:3000",
|
||||||
|
"default_timezone": "UTC",
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add user context if provided
|
||||||
|
if user != nil && !user.IsNil() {
|
||||||
|
pluginContext.User = &backend.User{
|
||||||
|
Login: user.GetLogin(),
|
||||||
|
Name: user.GetName(),
|
||||||
|
Email: user.GetEmail(),
|
||||||
|
Role: string(user.GetOrgRole()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pluginContext, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package mocksvcs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PluginErrorResolver struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume no plugin with errors
|
||||||
|
func (m *PluginErrorResolver) PluginErrors(ctx context.Context) []*plugins.Error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PluginErrorResolver) PluginError(ctx context.Context, pluginID string) *plugins.Error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package mocksvcs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/plugins/repo"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PluginRepo struct {
|
||||||
|
repo.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PluginRepo) GetPluginsInfo(ctx context.Context, options repo.GetPluginsInfoOptions, compatOpts repo.CompatOpts) ([]repo.PluginInfo, error) {
|
||||||
|
return []repo.PluginInfo{
|
||||||
|
{
|
||||||
|
ID: 1,
|
||||||
|
Slug: "grafana-piechart-panel",
|
||||||
|
Version: "1.6.0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: 2,
|
||||||
|
Slug: "prometheus",
|
||||||
|
Version: "10.0.0",
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
package mocksvcs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PluginStore struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
var ps = map[string]pluginstore.Plugin{
|
||||||
|
"prometheus": {
|
||||||
|
JSONData: plugins.JSONData{
|
||||||
|
ID: "prometheus",
|
||||||
|
Type: plugins.TypeDataSource,
|
||||||
|
Name: "Prometheus",
|
||||||
|
Info: plugins.Info{
|
||||||
|
Author: plugins.InfoLink{
|
||||||
|
Name: "Grafana Labs",
|
||||||
|
},
|
||||||
|
Version: "10.0.0",
|
||||||
|
},
|
||||||
|
Category: "Time series databases",
|
||||||
|
State: plugins.ReleaseStateAlpha,
|
||||||
|
Backend: true,
|
||||||
|
Metrics: true,
|
||||||
|
Logs: true,
|
||||||
|
Alerting: true,
|
||||||
|
Explore: true,
|
||||||
|
},
|
||||||
|
Class: plugins.ClassCore,
|
||||||
|
Signature: plugins.SignatureStatusInternal,
|
||||||
|
SignatureType: plugins.SignatureTypeGrafana,
|
||||||
|
SignatureOrg: "grafana.com",
|
||||||
|
},
|
||||||
|
"test-datasource": {
|
||||||
|
JSONData: plugins.JSONData{
|
||||||
|
ID: "grafana-piechart-panel",
|
||||||
|
Type: plugins.TypePanel,
|
||||||
|
Name: "Pie Chart",
|
||||||
|
Info: plugins.Info{
|
||||||
|
Author: plugins.InfoLink{
|
||||||
|
Name: "Grafana Labs",
|
||||||
|
},
|
||||||
|
Version: "1.6.0",
|
||||||
|
},
|
||||||
|
Category: "Visualization",
|
||||||
|
State: plugins.ReleaseStateAlpha,
|
||||||
|
},
|
||||||
|
Class: plugins.ClassCore,
|
||||||
|
Signature: plugins.SignatureStatusInternal,
|
||||||
|
SignatureType: plugins.SignatureTypeGrafana,
|
||||||
|
SignatureOrg: "grafana.com",
|
||||||
|
},
|
||||||
|
"grafana-piechart-panel": {
|
||||||
|
JSONData: plugins.JSONData{
|
||||||
|
ID: "prometheus",
|
||||||
|
Type: plugins.TypeDataSource,
|
||||||
|
Name: "Prometheus",
|
||||||
|
Info: plugins.Info{
|
||||||
|
Author: plugins.InfoLink{
|
||||||
|
Name: "Grafana Labs",
|
||||||
|
},
|
||||||
|
Version: "10.0.0",
|
||||||
|
},
|
||||||
|
Category: "Time series databases",
|
||||||
|
State: plugins.ReleaseStateAlpha,
|
||||||
|
Backend: true,
|
||||||
|
Metrics: true,
|
||||||
|
Logs: true,
|
||||||
|
Alerting: true,
|
||||||
|
Explore: true,
|
||||||
|
},
|
||||||
|
Class: plugins.ClassCore,
|
||||||
|
Signature: plugins.SignatureStatusInternal,
|
||||||
|
SignatureType: plugins.SignatureTypeGrafana,
|
||||||
|
SignatureOrg: "grafana.com",
|
||||||
|
},
|
||||||
|
"test-app": {
|
||||||
|
JSONData: plugins.JSONData{
|
||||||
|
ID: "test-app",
|
||||||
|
Type: plugins.TypeApp,
|
||||||
|
Name: "Test App",
|
||||||
|
Info: plugins.Info{
|
||||||
|
Author: plugins.InfoLink{
|
||||||
|
Name: "Test Author",
|
||||||
|
},
|
||||||
|
Version: "2.0.0",
|
||||||
|
},
|
||||||
|
Category: "Application",
|
||||||
|
State: plugins.ReleaseStateAlpha,
|
||||||
|
AutoEnabled: true,
|
||||||
|
},
|
||||||
|
Class: plugins.ClassExternal,
|
||||||
|
Signature: plugins.SignatureStatusValid,
|
||||||
|
SignatureType: plugins.SignatureTypeCommercial,
|
||||||
|
SignatureOrg: "test.com",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *PluginStore) Plugin(ctx context.Context, pluginID string) (pluginstore.Plugin, bool) {
|
||||||
|
p, ok := ps[pluginID]
|
||||||
|
return p, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *PluginStore) Plugins(ctx context.Context, pluginTypes ...plugins.Type) []pluginstore.Plugin {
|
||||||
|
plugins := make([]pluginstore.Plugin, 0, len(ps))
|
||||||
|
for _, p := range ps {
|
||||||
|
plugins = append(plugins, p)
|
||||||
|
}
|
||||||
|
return plugins
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package mocksvcs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UpdateChecker struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *UpdateChecker) IsUpdatable(ctx context.Context, plugin pluginstore.Plugin) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *UpdateChecker) CanUpdate(pluginId string, currentVersion string, targetVersion string, onlyMinor bool) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
@@ -26,7 +26,7 @@ const (
|
|||||||
type check struct {
|
type check struct {
|
||||||
DatasourceSvc datasources.DataSourceService
|
DatasourceSvc datasources.DataSourceService
|
||||||
PluginStore pluginstore.Store
|
PluginStore pluginstore.Store
|
||||||
PluginContextProvider pluginContextProvider
|
PluginContextProvider PluginContextProvider
|
||||||
PluginClient plugins.Client
|
PluginClient plugins.Client
|
||||||
PluginRepo repo.Service
|
PluginRepo repo.Service
|
||||||
GrafanaVersion string
|
GrafanaVersion string
|
||||||
@@ -37,7 +37,7 @@ type check struct {
|
|||||||
func New(
|
func New(
|
||||||
datasourceSvc datasources.DataSourceService,
|
datasourceSvc datasources.DataSourceService,
|
||||||
pluginStore pluginstore.Store,
|
pluginStore pluginstore.Store,
|
||||||
pluginContextProvider pluginContextProvider,
|
pluginContextProvider PluginContextProvider,
|
||||||
pluginClient plugins.Client,
|
pluginClient plugins.Client,
|
||||||
pluginRepo repo.Service,
|
pluginRepo repo.Service,
|
||||||
grafanaVersion string,
|
grafanaVersion string,
|
||||||
@@ -168,6 +168,6 @@ func (c *check) canBeInstalled(ctx context.Context, pluginType string) (bool, er
|
|||||||
return isAvailableInRepo, nil
|
return isAvailableInRepo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type pluginContextProvider interface {
|
type PluginContextProvider interface {
|
||||||
GetWithDataSource(ctx context.Context, pluginID string, user identity.Requester, ds *datasources.DataSource) (backend.PluginContext, error)
|
GetWithDataSource(ctx context.Context, pluginID string, user identity.Requester, ds *datasources.DataSource) (backend.PluginContext, error)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type healthCheckStep struct {
|
type healthCheckStep struct {
|
||||||
PluginContextProvider pluginContextProvider
|
PluginContextProvider PluginContextProvider
|
||||||
PluginClient plugins.Client
|
PluginClient plugins.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ func main() {
|
|||||||
KubeConfig: rest.Config{}, // this will be replaced by the apiserver loopback config
|
KubeConfig: rest.Config{}, // this will be replaced by the apiserver loopback config
|
||||||
ManifestData: *apis.LocalManifest().ManifestData,
|
ManifestData: *apis.LocalManifest().ManifestData,
|
||||||
SpecificConfig: checkregistry.AdvisorAppConfig{
|
SpecificConfig: checkregistry.AdvisorAppConfig{
|
||||||
CheckRegistry: &mockchecks.CheckRegistry{},
|
CheckRegistry: mockchecks.New(),
|
||||||
PluginConfig: map[string]string{},
|
PluginConfig: map[string]string{},
|
||||||
StackID: "1", // Numeric stack ID for standalone mode
|
StackID: "1", // Numeric stack ID for standalone mode
|
||||||
OrgService: nil, // Not needed when StackID is set
|
OrgService: nil, // Not needed when StackID is set
|
||||||
|
|||||||
Reference in New Issue
Block a user