03a9650c57
this makes it possible for the plugin repo to provide the correct package if arch and os matters
181 lines
4.0 KiB
Go
181 lines
4.0 KiB
Go
package services
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net"
|
|
"net/http"
|
|
"net/url"
|
|
"path"
|
|
"runtime"
|
|
"time"
|
|
|
|
"github.com/grafana/grafana/pkg/cmd/grafana-cli/logger"
|
|
m "github.com/grafana/grafana/pkg/cmd/grafana-cli/models"
|
|
)
|
|
|
|
var (
|
|
IoHelper m.IoUtil = IoUtilImp{}
|
|
HttpClient http.Client
|
|
grafanaVersion string
|
|
)
|
|
|
|
func Init(version string, skipTLSVerify bool) {
|
|
grafanaVersion = version
|
|
|
|
tr := &http.Transport{
|
|
Proxy: http.ProxyFromEnvironment,
|
|
DialContext: (&net.Dialer{
|
|
Timeout: 30 * time.Second,
|
|
KeepAlive: 30 * time.Second,
|
|
DualStack: true,
|
|
}).DialContext,
|
|
MaxIdleConns: 100,
|
|
IdleConnTimeout: 90 * time.Second,
|
|
TLSHandshakeTimeout: 10 * time.Second,
|
|
ExpectContinueTimeout: 1 * time.Second,
|
|
TLSClientConfig: &tls.Config{
|
|
InsecureSkipVerify: skipTLSVerify,
|
|
},
|
|
}
|
|
|
|
HttpClient = http.Client{
|
|
Timeout: 10 * time.Second,
|
|
Transport: tr,
|
|
}
|
|
}
|
|
|
|
func ListAllPlugins(repoUrl string) (m.PluginRepo, error) {
|
|
body, err := sendRequest(repoUrl, "repo")
|
|
|
|
if err != nil {
|
|
logger.Info("Failed to send request", "error", err)
|
|
return m.PluginRepo{}, fmt.Errorf("Failed to send request. error: %v", err)
|
|
}
|
|
|
|
if err != nil {
|
|
return m.PluginRepo{}, err
|
|
}
|
|
|
|
var data m.PluginRepo
|
|
err = json.Unmarshal(body, &data)
|
|
if err != nil {
|
|
logger.Info("Failed to unmarshal graphite response error: %v", err)
|
|
return m.PluginRepo{}, err
|
|
}
|
|
|
|
return data, nil
|
|
}
|
|
|
|
func ReadPlugin(pluginDir, pluginName string) (m.InstalledPlugin, error) {
|
|
distPluginDataPath := path.Join(pluginDir, pluginName, "dist", "plugin.json")
|
|
|
|
var data []byte
|
|
var err error
|
|
data, err = IoHelper.ReadFile(distPluginDataPath)
|
|
|
|
if err != nil {
|
|
pluginDataPath := path.Join(pluginDir, pluginName, "plugin.json")
|
|
data, err = IoHelper.ReadFile(pluginDataPath)
|
|
|
|
if err != nil {
|
|
return m.InstalledPlugin{}, errors.New("Could not find dist/plugin.json or plugin.json on " + pluginName + " in " + pluginDir)
|
|
}
|
|
}
|
|
|
|
res := m.InstalledPlugin{}
|
|
json.Unmarshal(data, &res)
|
|
|
|
if res.Info.Version == "" {
|
|
res.Info.Version = "0.0.0"
|
|
}
|
|
|
|
if res.Id == "" {
|
|
return m.InstalledPlugin{}, errors.New("could not find plugin " + pluginName + " in " + pluginDir)
|
|
}
|
|
|
|
return res, nil
|
|
}
|
|
|
|
func GetLocalPlugins(pluginDir string) []m.InstalledPlugin {
|
|
result := make([]m.InstalledPlugin, 0)
|
|
files, _ := IoHelper.ReadDir(pluginDir)
|
|
for _, f := range files {
|
|
res, err := ReadPlugin(pluginDir, f.Name())
|
|
if err == nil {
|
|
result = append(result, res)
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func RemoveInstalledPlugin(pluginPath, pluginName string) error {
|
|
logger.Infof("Removing plugin: %v\n", pluginName)
|
|
pluginDir := path.Join(pluginPath, pluginName)
|
|
|
|
_, err := IoHelper.Stat(pluginDir)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return IoHelper.RemoveAll(pluginDir)
|
|
}
|
|
|
|
func GetPlugin(pluginId, repoUrl string) (m.Plugin, error) {
|
|
body, err := sendRequest(repoUrl, "repo", pluginId)
|
|
|
|
if err != nil {
|
|
logger.Info("Failed to send request", "error", err)
|
|
return m.Plugin{}, fmt.Errorf("Failed to send request. error: %v", err)
|
|
}
|
|
|
|
if err != nil {
|
|
return m.Plugin{}, err
|
|
}
|
|
|
|
var data m.Plugin
|
|
err = json.Unmarshal(body, &data)
|
|
if err != nil {
|
|
logger.Info("Failed to unmarshal graphite response error: %v", err)
|
|
return m.Plugin{}, err
|
|
}
|
|
|
|
return data, nil
|
|
}
|
|
|
|
func sendRequest(repoUrl string, subPaths ...string) ([]byte, error) {
|
|
u, _ := url.Parse(repoUrl)
|
|
for _, v := range subPaths {
|
|
u.Path = path.Join(u.Path, v)
|
|
}
|
|
|
|
req, err := http.NewRequest(http.MethodGet, u.String(), nil)
|
|
|
|
req.Header.Set("grafana-version", grafanaVersion)
|
|
req.Header.Set("grafana-os", runtime.GOOS)
|
|
req.Header.Set("grafana-arch", runtime.GOARCH)
|
|
req.Header.Set("User-Agent", "grafana "+grafanaVersion)
|
|
|
|
if err != nil {
|
|
return []byte{}, err
|
|
}
|
|
|
|
res, err := HttpClient.Do(req)
|
|
if err != nil {
|
|
return []byte{}, err
|
|
}
|
|
|
|
if res.StatusCode/100 != 2 {
|
|
return []byte{}, fmt.Errorf("Api returned invalid status: %s", res.Status)
|
|
}
|
|
|
|
body, err := ioutil.ReadAll(res.Body)
|
|
defer res.Body.Close()
|
|
|
|
return body, err
|
|
}
|