2016-02-15 14:09:34 +01:00
|
|
|
package services
|
|
|
|
|
|
|
|
|
|
import (
|
2016-09-15 16:01:06 +02:00
|
|
|
"crypto/tls"
|
2016-02-15 14:09:34 +01:00
|
|
|
"encoding/json"
|
|
|
|
|
"errors"
|
2016-03-11 14:34:48 +01:00
|
|
|
"fmt"
|
2016-09-15 16:01:06 +02:00
|
|
|
"io/ioutil"
|
2016-11-01 08:58:44 +01:00
|
|
|
"net"
|
2016-09-15 16:01:06 +02:00
|
|
|
"net/http"
|
|
|
|
|
"net/url"
|
2016-03-28 21:42:26 +02:00
|
|
|
"path"
|
2016-09-15 16:01:06 +02:00
|
|
|
"time"
|
2016-03-28 21:42:26 +02:00
|
|
|
|
2016-06-03 12:19:04 +02:00
|
|
|
"github.com/grafana/grafana/pkg/cmd/grafana-cli/logger"
|
2016-02-15 14:09:34 +01:00
|
|
|
m "github.com/grafana/grafana/pkg/cmd/grafana-cli/models"
|
|
|
|
|
)
|
|
|
|
|
|
2016-09-15 16:01:06 +02:00
|
|
|
var (
|
|
|
|
|
IoHelper m.IoUtil = IoUtilImp{}
|
|
|
|
|
HttpClient http.Client
|
|
|
|
|
grafanaVersion string
|
|
|
|
|
)
|
|
|
|
|
|
2017-09-28 11:10:59 +01:00
|
|
|
func Init(version string, skipTLSVerify bool) {
|
2016-09-15 16:01:06 +02:00
|
|
|
grafanaVersion = version
|
|
|
|
|
|
|
|
|
|
tr := &http.Transport{
|
2016-11-01 08:58:44 +01:00
|
|
|
Proxy: http.ProxyFromEnvironment,
|
|
|
|
|
DialContext: (&net.Dialer{
|
|
|
|
|
Timeout: 30 * time.Second,
|
|
|
|
|
KeepAlive: 30 * time.Second,
|
2017-09-27 22:25:00 -07:00
|
|
|
DualStack: true,
|
2016-11-01 08:58:44 +01:00
|
|
|
}).DialContext,
|
|
|
|
|
MaxIdleConns: 100,
|
|
|
|
|
IdleConnTimeout: 90 * time.Second,
|
|
|
|
|
TLSHandshakeTimeout: 10 * time.Second,
|
|
|
|
|
ExpectContinueTimeout: 1 * time.Second,
|
2017-09-28 11:10:59 +01:00
|
|
|
TLSClientConfig: &tls.Config{
|
|
|
|
|
InsecureSkipVerify: skipTLSVerify,
|
|
|
|
|
},
|
2016-09-15 16:01:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HttpClient = http.Client{
|
2018-04-16 20:04:58 +02:00
|
|
|
Timeout: 10 * time.Second,
|
2016-09-15 16:01:06 +02:00
|
|
|
Transport: tr,
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-02-15 14:09:34 +01:00
|
|
|
|
2016-03-07 13:27:51 +01:00
|
|
|
func ListAllPlugins(repoUrl string) (m.PluginRepo, error) {
|
2016-10-21 16:03:02 +02:00
|
|
|
body, err := sendRequest(repoUrl, "repo")
|
2016-09-15 16:01:06 +02:00
|
|
|
|
2016-03-29 16:04:24 +08:00
|
|
|
if err != nil {
|
2016-10-21 16:03:02 +02:00
|
|
|
logger.Info("Failed to send request", "error", err)
|
|
|
|
|
return m.PluginRepo{}, fmt.Errorf("Failed to send request. error: %v", err)
|
2016-03-29 16:04:24 +08:00
|
|
|
}
|
2016-09-15 16:01:06 +02:00
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
return m.PluginRepo{}, err
|
2016-03-11 14:34:48 +01:00
|
|
|
}
|
2016-02-15 14:09:34 +01:00
|
|
|
|
2016-09-15 16:01:06 +02:00
|
|
|
var data m.PluginRepo
|
|
|
|
|
err = json.Unmarshal(body, &data)
|
2016-02-15 14:09:34 +01:00
|
|
|
if err != nil {
|
2016-09-15 16:01:06 +02:00
|
|
|
logger.Info("Failed to unmarshal graphite response error: %v", err)
|
|
|
|
|
return m.PluginRepo{}, err
|
2016-02-15 14:09:34 +01:00
|
|
|
}
|
|
|
|
|
|
2016-09-15 16:01:06 +02:00
|
|
|
return data, nil
|
2016-02-15 14:09:34 +01:00
|
|
|
}
|
|
|
|
|
|
2016-02-16 08:49:27 +01:00
|
|
|
func ReadPlugin(pluginDir, pluginName string) (m.InstalledPlugin, error) {
|
2016-06-23 08:35:40 +02:00
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-02-15 14:09:34 +01:00
|
|
|
|
|
|
|
|
res := m.InstalledPlugin{}
|
2016-06-23 08:35:40 +02:00
|
|
|
json.Unmarshal(data, &res)
|
2016-02-15 14:09:34 +01:00
|
|
|
|
|
|
|
|
if res.Info.Version == "" {
|
|
|
|
|
res.Info.Version = "0.0.0"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if res.Id == "" {
|
2016-05-12 04:43:31 -04:00
|
|
|
return m.InstalledPlugin{}, errors.New("could not find plugin " + pluginName + " in " + pluginDir)
|
2016-02-15 14:09:34 +01:00
|
|
|
}
|
|
|
|
|
|
2016-02-16 08:49:27 +01:00
|
|
|
return res, nil
|
2016-02-15 14:09:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func GetLocalPlugins(pluginDir string) []m.InstalledPlugin {
|
|
|
|
|
result := make([]m.InstalledPlugin, 0)
|
|
|
|
|
files, _ := IoHelper.ReadDir(pluginDir)
|
|
|
|
|
for _, f := range files {
|
2016-02-16 08:49:27 +01:00
|
|
|
res, err := ReadPlugin(pluginDir, f.Name())
|
|
|
|
|
if err == nil {
|
|
|
|
|
result = append(result, res)
|
|
|
|
|
}
|
2016-02-15 14:09:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-25 01:18:49 +02:00
|
|
|
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)
|
2016-02-15 14:09:34 +01:00
|
|
|
}
|
|
|
|
|
|
2016-03-07 13:27:51 +01:00
|
|
|
func GetPlugin(pluginId, repoUrl string) (m.Plugin, error) {
|
2016-10-21 16:03:02 +02:00
|
|
|
body, err := sendRequest(repoUrl, "repo", pluginId)
|
2016-09-15 16:01:06 +02:00
|
|
|
|
|
|
|
|
if err != nil {
|
2016-10-21 16:03:02 +02:00
|
|
|
logger.Info("Failed to send request", "error", err)
|
|
|
|
|
return m.Plugin{}, fmt.Errorf("Failed to send request. error: %v", err)
|
2016-09-15 16:01:06 +02:00
|
|
|
}
|
2016-02-15 14:09:34 +01:00
|
|
|
|
2016-05-12 04:43:31 -04:00
|
|
|
if err != nil {
|
|
|
|
|
return m.Plugin{}, err
|
|
|
|
|
}
|
2016-09-15 16:01:06 +02:00
|
|
|
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-21 16:03:02 +02:00
|
|
|
func sendRequest(repoUrl string, subPaths ...string) ([]byte, error) {
|
2016-09-15 16:01:06 +02:00
|
|
|
u, _ := url.Parse(repoUrl)
|
|
|
|
|
for _, v := range subPaths {
|
|
|
|
|
u.Path = path.Join(u.Path, v)
|
2016-02-15 14:09:34 +01:00
|
|
|
}
|
|
|
|
|
|
2016-09-15 16:01:06 +02:00
|
|
|
req, err := http.NewRequest(http.MethodGet, u.String(), nil)
|
|
|
|
|
|
|
|
|
|
req.Header.Set("grafana-version", grafanaVersion)
|
|
|
|
|
req.Header.Set("User-Agent", "grafana "+grafanaVersion)
|
|
|
|
|
|
2016-05-12 04:43:31 -04:00
|
|
|
if err != nil {
|
2016-09-15 16:01:06 +02:00
|
|
|
return []byte{}, err
|
2016-05-12 04:43:31 -04:00
|
|
|
}
|
|
|
|
|
|
2016-09-15 16:01:06 +02:00
|
|
|
res, err := HttpClient.Do(req)
|
2016-10-21 16:03:02 +02:00
|
|
|
if err != nil {
|
|
|
|
|
return []byte{}, err
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-12 22:31:28 +02:00
|
|
|
if res.StatusCode/100 != 2 {
|
|
|
|
|
return []byte{}, fmt.Errorf("Api returned invalid status: %s", res.Status)
|
|
|
|
|
}
|
2016-09-15 16:01:06 +02:00
|
|
|
|
|
|
|
|
body, err := ioutil.ReadAll(res.Body)
|
|
|
|
|
defer res.Body.Close()
|
|
|
|
|
|
|
|
|
|
return body, err
|
2016-02-15 14:09:34 +01:00
|
|
|
}
|