mirror of
https://github.com/grafana/grafana.git
synced 2025-07-28 21:52:23 +08:00

* make explicit class check when attempting to remove plugin * simplify plugin file tracking * fix test * apply feedback * fix linter
134 lines
3.4 KiB
Go
134 lines
3.4 KiB
Go
package commands
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"runtime"
|
|
"strings"
|
|
|
|
"github.com/fatih/color"
|
|
"github.com/grafana/grafana/pkg/cmd/grafana-cli/logger"
|
|
"github.com/grafana/grafana/pkg/cmd/grafana-cli/models"
|
|
"github.com/grafana/grafana/pkg/cmd/grafana-cli/services"
|
|
"github.com/grafana/grafana/pkg/cmd/grafana-cli/utils"
|
|
"github.com/grafana/grafana/pkg/plugins/repo"
|
|
"github.com/grafana/grafana/pkg/plugins/storage"
|
|
)
|
|
|
|
func validateInput(c utils.CommandLine, pluginFolder string) error {
|
|
arg := c.Args().First()
|
|
if arg == "" {
|
|
return errors.New("please specify plugin to install")
|
|
}
|
|
|
|
pluginsDir := c.PluginDirectory()
|
|
if pluginsDir == "" {
|
|
return errors.New("missing pluginsDir flag")
|
|
}
|
|
|
|
fileInfo, err := os.Stat(pluginsDir)
|
|
if err != nil {
|
|
if err = os.MkdirAll(pluginsDir, os.ModePerm); err != nil {
|
|
return fmt.Errorf("pluginsDir (%s) is not a writable directory", pluginsDir)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
if !fileInfo.IsDir() {
|
|
return errors.New("path is not a directory")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func logRestartNotice() {
|
|
logger.Info(color.GreenString("Please restart Grafana after installing or removing plugins. Refer to Grafana documentation for instructions if necessary.\n\n"))
|
|
}
|
|
|
|
func (cmd Command) installCommand(c utils.CommandLine) error {
|
|
pluginFolder := c.PluginDirectory()
|
|
if err := validateInput(c, pluginFolder); err != nil {
|
|
return err
|
|
}
|
|
|
|
pluginID := c.Args().First()
|
|
version := c.Args().Get(1)
|
|
err := installPlugin(context.Background(), pluginID, version, c)
|
|
if err == nil {
|
|
logRestartNotice()
|
|
}
|
|
return err
|
|
}
|
|
|
|
// installPlugin downloads the plugin code as a zip file from the Grafana.com API
|
|
// and then extracts the zip into the plugin's directory.
|
|
func installPlugin(ctx context.Context, pluginID, version string, c utils.CommandLine) error {
|
|
skipTLSVerify := c.Bool("insecure")
|
|
repository := repo.New(skipTLSVerify, c.PluginRepoURL(), services.Logger)
|
|
|
|
compatOpts := repo.NewCompatOpts(services.GrafanaVersion, runtime.GOOS, runtime.GOARCH)
|
|
|
|
var archive *repo.PluginArchive
|
|
var err error
|
|
pluginZipURL := c.PluginURL()
|
|
if pluginZipURL != "" {
|
|
if archive, err = repository.GetPluginArchiveByURL(ctx, pluginZipURL, compatOpts); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
if archive, err = repository.GetPluginArchive(ctx, pluginID, version, compatOpts); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
pluginFs := storage.FileSystem(services.Logger, c.PluginDirectory())
|
|
extractedArchive, err := pluginFs.Extract(ctx, pluginID, archive.File)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, dep := range extractedArchive.Dependencies {
|
|
services.Logger.Infof("Fetching %s dependency...", dep.ID)
|
|
d, err := repository.GetPluginArchive(ctx, dep.ID, dep.Version, compatOpts)
|
|
if err != nil {
|
|
return fmt.Errorf("%v: %w", fmt.Sprintf("failed to download plugin %s from repository", dep.ID), err)
|
|
}
|
|
|
|
_, err = pluginFs.Extract(ctx, dep.ID, d.File)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func osAndArchString() string {
|
|
osString := strings.ToLower(runtime.GOOS)
|
|
arch := runtime.GOARCH
|
|
return osString + "-" + arch
|
|
}
|
|
|
|
func supportsCurrentArch(version *models.Version) bool {
|
|
if version.Arch == nil {
|
|
return true
|
|
}
|
|
for arch := range version.Arch {
|
|
if arch == osAndArchString() || arch == "any" {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func latestSupportedVersion(plugin *models.Plugin) *models.Version {
|
|
for _, v := range plugin.Versions {
|
|
ver := v
|
|
if supportsCurrentArch(&ver) {
|
|
return &ver
|
|
}
|
|
}
|
|
return nil
|
|
}
|