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/repo/service.go

120 lines
3.3 KiB

package repo
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/url"
"path"
"github.com/grafana/grafana/pkg/plugins/config"
"github.com/grafana/grafana/pkg/plugins/log"
)
type Manager struct {
client *Client
baseURL string
log log.PrettyLogger
}
func ProvideService(cfg *config.Cfg) (*Manager, error) {
baseURL, err := url.JoinPath(cfg.GrafanaComURL, "/api/plugins")
if err != nil {
return nil, err
}
return NewManager(ManagerCfg{
SkipTLSVerify: false,
BaseURL: baseURL,
Logger: log.NewPrettyLogger("plugin.repository"),
}), nil
}
type ManagerCfg struct {
SkipTLSVerify bool
BaseURL string
Logger log.PrettyLogger
}
func NewManager(cfg ManagerCfg) *Manager {
return &Manager{
baseURL: cfg.BaseURL,
client: NewClient(cfg.SkipTLSVerify, cfg.Logger),
log: cfg.Logger,
}
}
// GetPluginArchive fetches the requested plugin archive
func (m *Manager) GetPluginArchive(ctx context.Context, pluginID, version string, compatOpts CompatOpts) (*PluginArchive, error) {
dlOpts, err := m.GetPluginArchiveInfo(ctx, pluginID, version, compatOpts)
if err != nil {
return nil, err
}
return m.client.Download(ctx, dlOpts.URL, dlOpts.Checksum, compatOpts)
}
// GetPluginArchiveByURL fetches the requested plugin archive from the provided `pluginZipURL`
func (m *Manager) GetPluginArchiveByURL(ctx context.Context, pluginZipURL string, compatOpts CompatOpts) (*PluginArchive, error) {
return m.client.Download(ctx, pluginZipURL, "", compatOpts)
}
// GetPluginArchiveInfo returns the options for downloading the requested plugin (with optional `version`)
func (m *Manager) GetPluginArchiveInfo(_ context.Context, pluginID, version string, compatOpts CompatOpts) (*PluginArchiveInfo, error) {
v, err := m.PluginVersion(pluginID, version, compatOpts)
if err != nil {
return nil, err
}
return &PluginArchiveInfo{
Version: v.Version,
Checksum: v.Checksum,
URL: m.downloadURL(pluginID, v.Version),
}, nil
}
// PluginVersion will return plugin version based on the requested information
func (m *Manager) PluginVersion(pluginID, version string, compatOpts CompatOpts) (VersionData, error) {
versions, err := m.grafanaCompatiblePluginVersions(pluginID, compatOpts)
if err != nil {
return VersionData{}, err
}
sysCompatOpts, exists := compatOpts.System()
if !exists {
return VersionData{}, errors.New("no system compatibility requirements set")
}
return SelectSystemCompatibleVersion(m.log, versions, pluginID, version, sysCompatOpts)
}
func (m *Manager) downloadURL(pluginID, version string) string {
return fmt.Sprintf("%s/%s/versions/%s/download", m.baseURL, pluginID, version)
}
// grafanaCompatiblePluginVersions will get version info from /api/plugins/repo/$pluginID based on
// the provided compatibility information (sent via HTTP headers)
func (m *Manager) grafanaCompatiblePluginVersions(pluginID string, compatOpts CompatOpts) ([]Version, error) {
u, err := url.Parse(m.baseURL)
if err != nil {
return nil, err
}
u.Path = path.Join(u.Path, "repo", pluginID)
body, err := m.client.SendReq(u, compatOpts)
if err != nil {
return nil, err
}
var v PluginRepo
err = json.Unmarshal(body, &v)
if err != nil {
m.log.Error("Failed to unmarshal plugin repo response", err)
return nil, err
}
return v.Versions, nil
}