services.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. package services
  2. import (
  3. "crypto/tls"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "io/ioutil"
  8. "net"
  9. "net/http"
  10. "net/url"
  11. "path"
  12. "runtime"
  13. "time"
  14. "github.com/grafana/grafana/pkg/cmd/grafana-cli/logger"
  15. m "github.com/grafana/grafana/pkg/cmd/grafana-cli/models"
  16. )
  17. var (
  18. IoHelper m.IoUtil = IoUtilImp{}
  19. HttpClient http.Client
  20. grafanaVersion string
  21. NotFoundError = errors.New("404 not found error")
  22. )
  23. func Init(version string, skipTLSVerify bool) {
  24. grafanaVersion = version
  25. tr := &http.Transport{
  26. Proxy: http.ProxyFromEnvironment,
  27. DialContext: (&net.Dialer{
  28. Timeout: 30 * time.Second,
  29. KeepAlive: 30 * time.Second,
  30. DualStack: true,
  31. }).DialContext,
  32. MaxIdleConns: 100,
  33. IdleConnTimeout: 90 * time.Second,
  34. TLSHandshakeTimeout: 10 * time.Second,
  35. ExpectContinueTimeout: 1 * time.Second,
  36. TLSClientConfig: &tls.Config{
  37. InsecureSkipVerify: skipTLSVerify,
  38. },
  39. }
  40. HttpClient = http.Client{
  41. Timeout: 10 * time.Second,
  42. Transport: tr,
  43. }
  44. }
  45. func ListAllPlugins(repoUrl string) (m.PluginRepo, error) {
  46. body, err := sendRequest(repoUrl, "repo")
  47. if err != nil {
  48. logger.Info("Failed to send request", "error", err)
  49. return m.PluginRepo{}, fmt.Errorf("Failed to send request. error: %v", err)
  50. }
  51. if err != nil {
  52. return m.PluginRepo{}, err
  53. }
  54. var data m.PluginRepo
  55. err = json.Unmarshal(body, &data)
  56. if err != nil {
  57. logger.Info("Failed to unmarshal plugin repo response error:", err)
  58. return m.PluginRepo{}, err
  59. }
  60. return data, nil
  61. }
  62. func ReadPlugin(pluginDir, pluginName string) (m.InstalledPlugin, error) {
  63. distPluginDataPath := path.Join(pluginDir, pluginName, "dist", "plugin.json")
  64. var data []byte
  65. var err error
  66. data, err = IoHelper.ReadFile(distPluginDataPath)
  67. if err != nil {
  68. pluginDataPath := path.Join(pluginDir, pluginName, "plugin.json")
  69. data, err = IoHelper.ReadFile(pluginDataPath)
  70. if err != nil {
  71. return m.InstalledPlugin{}, errors.New("Could not find dist/plugin.json or plugin.json on " + pluginName + " in " + pluginDir)
  72. }
  73. }
  74. res := m.InstalledPlugin{}
  75. json.Unmarshal(data, &res)
  76. if res.Info.Version == "" {
  77. res.Info.Version = "0.0.0"
  78. }
  79. if res.Id == "" {
  80. return m.InstalledPlugin{}, errors.New("could not find plugin " + pluginName + " in " + pluginDir)
  81. }
  82. return res, nil
  83. }
  84. func GetLocalPlugins(pluginDir string) []m.InstalledPlugin {
  85. result := make([]m.InstalledPlugin, 0)
  86. files, _ := IoHelper.ReadDir(pluginDir)
  87. for _, f := range files {
  88. res, err := ReadPlugin(pluginDir, f.Name())
  89. if err == nil {
  90. result = append(result, res)
  91. }
  92. }
  93. return result
  94. }
  95. func RemoveInstalledPlugin(pluginPath, pluginName string) error {
  96. logger.Infof("Removing plugin: %v\n", pluginName)
  97. pluginDir := path.Join(pluginPath, pluginName)
  98. _, err := IoHelper.Stat(pluginDir)
  99. if err != nil {
  100. return err
  101. }
  102. return IoHelper.RemoveAll(pluginDir)
  103. }
  104. func GetPlugin(pluginId, repoUrl string) (m.Plugin, error) {
  105. logger.Debugf("getting plugin metadata from: %v pluginId: %v \n", repoUrl, pluginId)
  106. body, err := sendRequest(repoUrl, "repo", pluginId)
  107. if err != nil {
  108. logger.Info("Failed to send request: ", err)
  109. if err == NotFoundError {
  110. return m.Plugin{}, fmt.Errorf("Failed to find requested plugin, check if the plugin_id is correct. error: %v", err)
  111. }
  112. return m.Plugin{}, fmt.Errorf("Failed to send request. error: %v", err)
  113. }
  114. if err != nil {
  115. return m.Plugin{}, err
  116. }
  117. var data m.Plugin
  118. err = json.Unmarshal(body, &data)
  119. if err != nil {
  120. logger.Info("Failed to unmarshal plugin repo response error:", err)
  121. return m.Plugin{}, err
  122. }
  123. return data, nil
  124. }
  125. func sendRequest(repoUrl string, subPaths ...string) ([]byte, error) {
  126. u, _ := url.Parse(repoUrl)
  127. for _, v := range subPaths {
  128. u.Path = path.Join(u.Path, v)
  129. }
  130. req, err := http.NewRequest(http.MethodGet, u.String(), nil)
  131. req.Header.Set("grafana-version", grafanaVersion)
  132. req.Header.Set("grafana-os", runtime.GOOS)
  133. req.Header.Set("grafana-arch", runtime.GOARCH)
  134. req.Header.Set("User-Agent", "grafana "+grafanaVersion)
  135. if err != nil {
  136. return []byte{}, err
  137. }
  138. res, err := HttpClient.Do(req)
  139. if err != nil {
  140. return []byte{}, err
  141. }
  142. if res.StatusCode == 404 {
  143. return []byte{}, NotFoundError
  144. }
  145. if res.StatusCode/100 != 2 {
  146. return []byte{}, fmt.Errorf("Api returned invalid status: %s", res.Status)
  147. }
  148. body, err := ioutil.ReadAll(res.Body)
  149. defer res.Body.Close()
  150. return body, err
  151. }