2024-01-19 08:56:52 -06:00
|
|
|
package datasource
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2024-01-22 13:32:25 -06:00
|
|
|
"fmt"
|
2024-01-19 08:56:52 -06:00
|
|
|
|
|
|
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
2024-01-22 13:32:25 -06:00
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
|
|
|
|
"github.com/grafana/grafana/pkg/apis/datasource/v0alpha1"
|
|
|
|
"github.com/grafana/grafana/pkg/infra/appcontext"
|
2024-03-20 07:49:19 -05:00
|
|
|
"github.com/grafana/grafana/pkg/plugins"
|
2024-02-01 16:27:30 -06:00
|
|
|
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
|
|
|
|
"github.com/grafana/grafana/pkg/services/apiserver/utils"
|
2024-01-22 13:32:25 -06:00
|
|
|
"github.com/grafana/grafana/pkg/services/datasources"
|
|
|
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
|
|
|
|
)
|
|
|
|
|
|
|
|
// This provides access to settings saved in the database.
|
|
|
|
// Authorization checks will happen within each function, and the user in ctx will
|
|
|
|
// limit which namespace/tenant/org we are talking to
|
2024-01-24 09:44:40 -06:00
|
|
|
type PluginDatasourceProvider interface {
|
|
|
|
// Get gets a specific datasource (that the user in context can see)
|
2024-03-20 07:49:19 -05:00
|
|
|
Get(ctx context.Context, uid string) (*v0alpha1.DataSourceConnection, error)
|
2024-01-22 13:32:25 -06:00
|
|
|
|
2024-01-24 09:44:40 -06:00
|
|
|
// List lists all data sources the user in context can see
|
2024-03-20 07:49:19 -05:00
|
|
|
List(ctx context.Context) (*v0alpha1.DataSourceConnectionList, error)
|
2024-01-22 13:32:25 -06:00
|
|
|
|
|
|
|
// Return settings (decrypted!) for a specific plugin
|
|
|
|
// This will require "query" permission for the user in context
|
2024-03-20 07:49:19 -05:00
|
|
|
GetInstanceSettings(ctx context.Context, uid string) (*backend.DataSourceInstanceSettings, error)
|
2024-01-22 13:32:25 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// PluginContext requires adding system settings (feature flags, etc) to the datasource config
|
|
|
|
type PluginContextWrapper interface {
|
|
|
|
PluginContextForDataSource(ctx context.Context, datasourceSettings *backend.DataSourceInstanceSettings) (backend.PluginContext, error)
|
|
|
|
}
|
|
|
|
|
|
|
|
func ProvideDefaultPluginConfigs(
|
|
|
|
dsService datasources.DataSourceService,
|
|
|
|
dsCache datasources.CacheService,
|
2024-01-24 09:44:40 -06:00
|
|
|
contextProvider *plugincontext.Provider) PluginDatasourceProvider {
|
|
|
|
return &defaultPluginDatasourceProvider{
|
2024-03-20 07:49:19 -05:00
|
|
|
plugin: plugins.JSONData{
|
|
|
|
ID: datasources.DS_TESTDATA,
|
|
|
|
},
|
2024-01-22 13:32:25 -06:00
|
|
|
dsService: dsService,
|
|
|
|
dsCache: dsCache,
|
|
|
|
contextProvider: contextProvider,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-24 09:44:40 -06:00
|
|
|
type defaultPluginDatasourceProvider struct {
|
2024-03-20 07:49:19 -05:00
|
|
|
plugin plugins.JSONData
|
2024-01-22 13:32:25 -06:00
|
|
|
dsService datasources.DataSourceService
|
|
|
|
dsCache datasources.CacheService
|
|
|
|
contextProvider *plugincontext.Provider
|
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
2024-01-24 09:44:40 -06:00
|
|
|
_ PluginDatasourceProvider = (*defaultPluginDatasourceProvider)(nil)
|
2024-01-19 08:56:52 -06:00
|
|
|
)
|
|
|
|
|
2024-03-20 07:49:19 -05:00
|
|
|
func (q *defaultPluginDatasourceProvider) Get(ctx context.Context, uid string) (*v0alpha1.DataSourceConnection, error) {
|
2024-01-22 13:32:25 -06:00
|
|
|
info, err := request.NamespaceInfoFrom(ctx, true)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
user, err := appcontext.User(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
ds, err := q.dsCache.GetDatasourceByUID(ctx, uid, user, false)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return asConnection(ds, info.Value)
|
|
|
|
}
|
|
|
|
|
2024-03-20 07:49:19 -05:00
|
|
|
func (q *defaultPluginDatasourceProvider) List(ctx context.Context) (*v0alpha1.DataSourceConnectionList, error) {
|
2024-01-22 13:32:25 -06:00
|
|
|
info, err := request.NamespaceInfoFrom(ctx, true)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
dss, err := q.dsService.GetDataSourcesByType(ctx, &datasources.GetDataSourcesByTypeQuery{
|
2024-03-20 07:49:19 -05:00
|
|
|
OrgID: info.OrgID,
|
|
|
|
Type: q.plugin.ID,
|
|
|
|
AliasIDs: q.plugin.AliasIDs,
|
2024-01-22 13:32:25 -06:00
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
result := &v0alpha1.DataSourceConnectionList{
|
|
|
|
Items: []v0alpha1.DataSourceConnection{},
|
|
|
|
}
|
|
|
|
for _, ds := range dss {
|
|
|
|
v, _ := asConnection(ds, info.Value)
|
|
|
|
result.Items = append(result.Items, *v)
|
|
|
|
}
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
2024-03-20 07:49:19 -05:00
|
|
|
func (q *defaultPluginDatasourceProvider) GetInstanceSettings(ctx context.Context, uid string) (*backend.DataSourceInstanceSettings, error) {
|
2024-01-22 13:32:25 -06:00
|
|
|
if q.contextProvider == nil {
|
|
|
|
// NOTE!!! this is only here for the standalone example
|
|
|
|
// if we cleanup imports this can throw an error
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
return q.contextProvider.GetDataSourceInstanceSettings(ctx, uid)
|
|
|
|
}
|
|
|
|
|
|
|
|
func asConnection(ds *datasources.DataSource, ns string) (*v0alpha1.DataSourceConnection, error) {
|
|
|
|
v := &v0alpha1.DataSourceConnection{
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
Name: ds.UID,
|
|
|
|
Namespace: ns,
|
|
|
|
CreationTimestamp: metav1.NewTime(ds.Created),
|
|
|
|
ResourceVersion: fmt.Sprintf("%d", ds.Updated.UnixMilli()),
|
|
|
|
},
|
|
|
|
Title: ds.Name,
|
|
|
|
}
|
|
|
|
v.UID = utils.CalculateClusterWideUID(v) // indicates if the value changed on the server
|
|
|
|
meta, err := utils.MetaAccessor(v)
|
|
|
|
if err != nil {
|
|
|
|
meta.SetUpdatedTimestamp(&ds.Updated)
|
|
|
|
}
|
|
|
|
return v, err
|
2024-01-19 08:56:52 -06:00
|
|
|
}
|