grafana/pkg/build/plugins/download.go
Jo 062d255124
Handle ioutil deprecations (#53526)
* replace ioutil.ReadFile -> os.ReadFile

* replace ioutil.ReadAll -> io.ReadAll

* replace ioutil.TempFile -> os.CreateTemp

* replace ioutil.NopCloser -> io.NopCloser

* replace ioutil.WriteFile -> os.WriteFile

* replace ioutil.TempDir -> os.MkdirTemp

* replace ioutil.Discard -> io.Discard
2022-08-10 15:37:51 +02:00

118 lines
3.0 KiB
Go

package plugins
import (
"context"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"os"
"path/filepath"
"github.com/grafana/grafana/pkg/build/errutil"
"github.com/grafana/grafana/pkg/build/syncutil"
)
// logCloseError executes the closeFunc; if it returns an error, it is logged by the log package.
func logCloseError(closeFunc func() error) {
if err := closeFunc(); err != nil {
log.Println(err)
}
}
// logCloseError executes the closeFunc; if it returns an error, it is logged by the log package.
func logError(err error) {
if err != nil {
log.Println(err)
}
}
// pluginManifest has details of an external plugin package.
type pluginManifest struct {
Name string `json:"name"`
Version string `json:"version"`
Checksum string `json:"checksum"`
}
// pluginsManifest represents a manifest of Grafana's external plugins.
type pluginsManifest struct {
Plugins []pluginManifest `json:"plugins"`
}
// downloadPlugins downloads Grafana plugins that should be bundled into packages.
//
// The plugin archives are downloaded into <grafanaDir>/plugins-bundled.
func Download(ctx context.Context, grafanaDir string, p syncutil.WorkerPool) error {
g, _ := errutil.GroupWithContext(ctx)
log.Println("Downloading external plugins...")
var m pluginsManifest
manifestPath := filepath.Join(grafanaDir, "plugins-bundled", "external.json")
//nolint:gosec
manifestB, err := os.ReadFile(manifestPath)
if err != nil {
return fmt.Errorf("failed to open plugins manifest %q: %w", manifestPath, err)
}
if err := json.Unmarshal(manifestB, &m); err != nil {
return err
}
for i := range m.Plugins {
pm := m.Plugins[i]
p.Schedule(g.Wrap(func() error {
tgt := filepath.Join(grafanaDir, "plugins-bundled", fmt.Sprintf("%s-%s.zip", pm.Name, pm.Version))
out, err := os.Create(tgt)
if err != nil {
return err
}
defer logCloseError(out.Close)
u := fmt.Sprintf("http://storage.googleapis.com/plugins-ci/plugins/%s/%s-%s.zip", pm.Name, pm.Name,
pm.Version)
log.Printf("Downloading plugin %q to %q...", u, tgt)
// nolint:gosec
resp, err := http.Get(u)
if err != nil {
return fmt.Errorf("downloading %q failed: %w", u, err)
}
defer logError(resp.Body.Close())
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("failed to download %q, status code %d", u, resp.StatusCode)
}
if _, err := io.Copy(out, resp.Body); err != nil {
return fmt.Errorf("downloading %q failed: %w", u, err)
}
if err := out.Close(); err != nil {
return fmt.Errorf("downloading %q failed: %w", u, err)
}
//nolint:gosec
fd, err := os.Open(tgt)
if err != nil {
return err
}
defer logCloseError(fd.Close)
h := sha256.New()
if _, err := io.Copy(h, fd); err != nil {
return err
}
chksum := hex.EncodeToString(h.Sum(nil))
if chksum != pm.Checksum {
return fmt.Errorf("plugin %q has bad checksum: %s (expected %s)", u, chksum, pm.Checksum)
}
return Unzip(tgt, filepath.Join(grafanaDir, "plugins-bundled"))
}))
}
return g.Wait()
}