mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Chore: Change endpoint to check versions in cli (#78008)
This commit is contained in:
committed by
GitHub
parent
97c79f2c34
commit
f8a6380510
@@ -79,3 +79,11 @@ type ErrChecksumMismatch struct {
|
||||
func (e ErrChecksumMismatch) Error() string {
|
||||
return fmt.Sprintf("expected SHA256 checksum does not match the downloaded archive (%s) - please contact security@grafana.com", e.archiveURL)
|
||||
}
|
||||
|
||||
type ErrCorePlugin struct {
|
||||
id string
|
||||
}
|
||||
|
||||
func (e ErrCorePlugin) Error() string {
|
||||
return fmt.Sprintf("plugin %s is a core plugin and cannot be installed separately", e.id)
|
||||
}
|
||||
|
@@ -12,14 +12,15 @@ type PluginArchiveInfo struct {
|
||||
Checksum string
|
||||
}
|
||||
|
||||
// PluginRepo is (a subset of) the JSON response from /api/plugins/repo/$pluginID
|
||||
type PluginRepo struct {
|
||||
Versions []Version `json:"versions"`
|
||||
// PluginVersions is the JSON response from /api/plugins/$pluginID/versions
|
||||
type PluginVersions struct {
|
||||
Versions []Version `json:"items"`
|
||||
}
|
||||
|
||||
type Version struct {
|
||||
Version string `json:"version"`
|
||||
Arch map[string]ArchMeta `json:"arch"`
|
||||
Arch map[string]ArchMeta `json:"packages"`
|
||||
URL string `json:"url"`
|
||||
}
|
||||
|
||||
type ArchMeta struct {
|
||||
|
@@ -5,8 +5,10 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/grafana/grafana/pkg/plugins/config"
|
||||
"github.com/grafana/grafana/pkg/plugins/log"
|
||||
@@ -87,7 +89,19 @@ func (m *Manager) PluginVersion(pluginID, version string, compatOpts CompatOpts)
|
||||
return VersionData{}, errors.New("no system compatibility requirements set")
|
||||
}
|
||||
|
||||
return SelectSystemCompatibleVersion(m.log, versions, pluginID, version, sysCompatOpts)
|
||||
compatibleVer, err := SelectSystemCompatibleVersion(m.log, versions, pluginID, version, sysCompatOpts)
|
||||
if err != nil {
|
||||
return VersionData{}, err
|
||||
}
|
||||
|
||||
isGrafanaCorePlugin := strings.HasPrefix(compatibleVer.URL, "https://github.com/grafana/grafana/tree/main/public/app/plugins/")
|
||||
_, hasAnyArch := compatibleVer.Arch["any"]
|
||||
if isGrafanaCorePlugin && hasAnyArch {
|
||||
// Trying to install a coupled core plugin
|
||||
return VersionData{}, ErrCorePlugin{id: pluginID}
|
||||
}
|
||||
|
||||
return compatibleVer, nil
|
||||
}
|
||||
|
||||
func (m *Manager) downloadURL(pluginID, version string) string {
|
||||
@@ -102,19 +116,25 @@ func (m *Manager) grafanaCompatiblePluginVersions(pluginID string, compatOpts Co
|
||||
return nil, err
|
||||
}
|
||||
|
||||
u.Path = path.Join(u.Path, "repo", pluginID)
|
||||
u.Path = path.Join(u.Path, pluginID, "versions")
|
||||
|
||||
body, err := m.client.SendReq(u, compatOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var v PluginRepo
|
||||
var v PluginVersions
|
||||
err = json.Unmarshal(body, &v)
|
||||
if err != nil {
|
||||
m.log.Error("Failed to unmarshal plugin repo response", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(v.Versions) == 0 {
|
||||
// /plugins/{pluginId}/versions returns 200 even if the plugin doesn't exists
|
||||
// but the response is empty. In this case we return 404.
|
||||
return nil, newErrResponse4xx(http.StatusNotFound).withMessage("Plugin not found")
|
||||
}
|
||||
|
||||
return v.Versions, nil
|
||||
}
|
||||
|
@@ -23,6 +23,9 @@ func TestGetPluginArchive(t *testing.T) {
|
||||
tcs := []struct {
|
||||
name string
|
||||
sha string
|
||||
apiOpSys string
|
||||
apiArch string
|
||||
apiUrl string
|
||||
err error
|
||||
}{
|
||||
{
|
||||
@@ -34,6 +37,18 @@ func TestGetPluginArchive(t *testing.T) {
|
||||
sha: "1a2b3c",
|
||||
err: &ErrChecksumMismatch{},
|
||||
},
|
||||
{
|
||||
name: "Core plugin",
|
||||
sha: "69f698961b6ea651211a187874434821c4727cc22de022e3a7059116d21c75b1",
|
||||
apiOpSys: "any",
|
||||
apiUrl: "https://github.com/grafana/grafana/tree/main/public/app/plugins/test",
|
||||
err: &ErrCorePlugin{},
|
||||
},
|
||||
{
|
||||
name: "Decoupled core plugin",
|
||||
sha: "69f698961b6ea651211a187874434821c4727cc22de022e3a7059116d21c75b1",
|
||||
apiUrl: "https://github.com/grafana/grafana/tree/main/public/app/plugins/test",
|
||||
},
|
||||
}
|
||||
|
||||
pluginZip := createPluginArchive(t)
|
||||
@@ -57,17 +72,23 @@ func TestGetPluginArchive(t *testing.T) {
|
||||
grafanaVersion = "10.0.0"
|
||||
)
|
||||
|
||||
srv := mockPluginRepoAPI(t,
|
||||
srvData{
|
||||
srvd := srvData{
|
||||
pluginID: pluginID,
|
||||
version: version,
|
||||
opSys: opSys,
|
||||
arch: arch,
|
||||
opSys: tc.apiOpSys,
|
||||
arch: tc.apiArch,
|
||||
url: tc.apiUrl,
|
||||
grafanaVersion: grafanaVersion,
|
||||
sha: tc.sha,
|
||||
archive: d,
|
||||
},
|
||||
)
|
||||
}
|
||||
if srvd.opSys == "" {
|
||||
srvd.opSys = opSys
|
||||
}
|
||||
if srvd.arch == "" && srvd.opSys != "any" {
|
||||
srvd.arch = arch
|
||||
}
|
||||
srv := mockPluginVersionsAPI(t, srvd)
|
||||
t.Cleanup(srv.Close)
|
||||
|
||||
m := NewManager(ManagerCfg{
|
||||
@@ -125,34 +146,38 @@ type srvData struct {
|
||||
sha string
|
||||
grafanaVersion string
|
||||
archive []byte
|
||||
url string
|
||||
}
|
||||
|
||||
func mockPluginRepoAPI(t *testing.T, data srvData) *httptest.Server {
|
||||
func mockPluginVersionsAPI(t *testing.T, data srvData) *httptest.Server {
|
||||
t.Helper()
|
||||
|
||||
mux := http.NewServeMux()
|
||||
// mock plugin version data
|
||||
mux.HandleFunc(fmt.Sprintf("/repo/%s", data.pluginID), func(w http.ResponseWriter, r *http.Request) {
|
||||
mux.HandleFunc(fmt.Sprintf("/%s/versions", data.pluginID), func(w http.ResponseWriter, r *http.Request) {
|
||||
require.Equal(t, data.grafanaVersion, r.Header.Get("grafana-version"))
|
||||
require.Equal(t, data.opSys, r.Header.Get("grafana-os"))
|
||||
require.Equal(t, data.arch, r.Header.Get("grafana-arch"))
|
||||
require.NotNil(t, fmt.Sprintf("grafana %s", data.grafanaVersion), r.Header.Get("User-Agent"))
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
platform := data.opSys
|
||||
if data.arch != "" {
|
||||
platform += "-" + data.arch
|
||||
}
|
||||
_, _ = w.Write([]byte(fmt.Sprintf(`
|
||||
{
|
||||
"versions": [{
|
||||
"items": [{
|
||||
"version": "%s",
|
||||
"arch": {
|
||||
"%s-%s": {
|
||||
"packages": {
|
||||
"%s": {
|
||||
"sha256": "%s"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": "%s"
|
||||
}]
|
||||
}
|
||||
`, data.version, data.opSys, data.arch, data.sha),
|
||||
`, data.version, platform, data.sha, data.url),
|
||||
))
|
||||
})
|
||||
|
||||
|
@@ -9,6 +9,8 @@ import (
|
||||
type VersionData struct {
|
||||
Version string
|
||||
Checksum string
|
||||
Arch map[string]ArchMeta
|
||||
URL string
|
||||
}
|
||||
|
||||
// SelectSystemCompatibleVersion selects the most appropriate plugin version based on os + architecture
|
||||
@@ -33,6 +35,8 @@ func SelectSystemCompatibleVersion(log log.PrettyLogger, versions []Version, plu
|
||||
return VersionData{
|
||||
Version: latestForArch.Version,
|
||||
Checksum: checksum(latestForArch, compatOpts),
|
||||
Arch: latestForArch.Arch,
|
||||
URL: latestForArch.URL,
|
||||
}, nil
|
||||
}
|
||||
for _, v := range versions {
|
||||
@@ -65,6 +69,8 @@ func SelectSystemCompatibleVersion(log log.PrettyLogger, versions []Version, plu
|
||||
return VersionData{
|
||||
Version: ver.Version,
|
||||
Checksum: checksum(ver, compatOpts),
|
||||
Arch: ver.Arch,
|
||||
URL: ver.URL,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user