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/cmd/grafana-cli/commands/install_command.go

178 lines
3.6 KiB

package commands
import (
"archive/zip"
"bytes"
"errors"
"fmt"
"github.com/grafana/grafana/pkg/cmd/grafana-cli/log"
m "github.com/grafana/grafana/pkg/cmd/grafana-cli/models"
s "github.com/grafana/grafana/pkg/cmd/grafana-cli/services"
"io"
"io/ioutil"
"net/http"
"os"
"path"
"regexp"
)
func validateInput(c CommandLine, pluginFolder string) error {
arg := c.Args().First()
if arg == "" {
return errors.New("please specify plugin to install")
}
pluginDir := c.GlobalString("path")
if pluginDir == "" {
return errors.New("missing path flag")
}
fileInfo, err := os.Stat(pluginDir)
if err != nil {
if err = os.MkdirAll(pluginDir, os.ModePerm); err != nil {
return errors.New("path is not a directory")
}
return nil
}
if !fileInfo.IsDir() {
return errors.New("path is not a directory")
}
return nil
}
func installCommand(c CommandLine) error {
pluginFolder := c.GlobalString("path")
if err := validateInput(c, pluginFolder); err != nil {
return err
}
pluginToInstall := c.Args().First()
version := c.Args().Get(1)
if version == "" {
log.Infof("version: latest\n")
} else {
log.Infof("version: %v\n", version)
}
return InstallPlugin(pluginToInstall, version, c)
}
func InstallPlugin(pluginName, version string, c CommandLine) error {
plugin, err := s.GetPlugin(pluginName, c.GlobalString("repo"))
pluginFolder := c.GlobalString("path")
if err != nil {
return err
}
v, err := SelectVersion(plugin, version)
if err != nil {
return err
}
if version == "" {
version = v.Version
}
downloadURL := fmt.Sprintf("%s/%s/versions/%s/download",
c.GlobalString("repo"),
pluginName,
version)
log.Infof("installing %v @ %v\n", plugin.Id, version)
log.Infof("from url: %v\n", downloadURL)
log.Infof("into: %v\n", pluginFolder)
err = downloadFile(plugin.Id, pluginFolder, downloadURL)
if err != nil {
return err
}
log.Infof("Installed %v successfully ✔\n", plugin.Id)
/* Enable once we need support for downloading depedencies
res, _ := s.ReadPlugin(pluginFolder, pluginName)
for _, v := range res.Dependency.Plugins {
InstallPlugin(v.Id, version, c)
log.Infof("Installed dependency: %v ✔\n", v.Id)
}
*/
return err
}
func SelectVersion(plugin m.Plugin, version string) (m.Version, error) {
if version == "" {
return plugin.Versions[0], nil
}
for _, v := range plugin.Versions {
if v.Version == version {
return v, nil
}
}
return m.Version{}, errors.New("Could not find the version your looking for")
}
func RemoveGitBuildFromName(pluginName, filename string) string {
r := regexp.MustCompile("^[a-zA-Z0-9_.-]*/")
return r.ReplaceAllString(filename, pluginName+"/")
}
var retryCount = 0
func downloadFile(pluginName, filePath, url string) (err error) {
defer func() {
if r := recover(); r != nil {
retryCount++
if retryCount == 1 {
9 years ago
log.Debug("\nFailed downloading. Will retry once.\n")
downloadFile(pluginName, filePath, url)
} else {
9 years ago
panic(r)
}
}
}()
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
r, err := zip.NewReader(bytes.NewReader(body), resp.ContentLength)
if err != nil {
return err
}
for _, zf := range r.File {
newFile := path.Join(filePath, RemoveGitBuildFromName(pluginName, zf.Name))
if zf.FileInfo().IsDir() {
os.Mkdir(newFile, 0777)
} else {
dst, err := os.Create(newFile)
if err != nil {
log.Errorf("%v", err)
}
defer dst.Close()
src, err := zf.Open()
if err != nil {
log.Errorf("%v", err)
}
defer src.Close()
io.Copy(dst, src)
}
}
return nil
}