grafana/pkg/plugins/repo/service.go
Will Browne 12dc56ad0c
Plugins: Refactor plugin repository API (#69063)
* support grafana wildcard version

* undo go.mod changes

* tidy

* flesh out tests

* refactor

* add tests

* tidy naming

* undo some changes

* split interfaces

* separation

* update new signature

* simplify

* update var namings

* unexport types

* introduce opts pattern

* reorder test

* fix compat checks

* middle ground

* unexport client

* move back

* fix tests

* inline logger

* make client usable

* use fake logger

* tidy errors

* remove unused types

* fix test

* review fixes

* rework compatibility

* adjust installer

* fix tests

* opts => cfg

* remove unused var

* fix var name
2023-05-30 11:48:52 +02:00

121 lines
3.3 KiB
Go

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
}