grafana/pkg/cmd/grafana-cli/services/api_client.go
Will Browne e0e2535c96
Plugins: Tidy up CLI code (#67813)
* more tidying

* move some things around

* more tidying

* fix linter
2023-05-08 10:58:47 +02:00

137 lines
3.4 KiB
Go

package services
import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"path"
"runtime"
"github.com/grafana/grafana/pkg/cmd/grafana-cli/logger"
"github.com/grafana/grafana/pkg/cmd/grafana-cli/models"
)
func GetPluginInfoFromRepo(pluginId, repoUrl string) (models.Plugin, error) {
logger.Debugf("getting plugin metadata from: %v pluginId: %v \n", repoUrl, pluginId)
body, err := sendRequestGetBytes(HttpClient, repoUrl, "repo", pluginId)
if err != nil {
if errors.Is(err, ErrNotFoundError) {
return models.Plugin{}, fmt.Errorf("%v: %w",
fmt.Sprintf("Failed to find requested plugin, check if the plugin_id (%s) is correct", pluginId), err)
}
return models.Plugin{}, fmt.Errorf("%v: %w", "Failed to send request", err)
}
var data models.Plugin
err = json.Unmarshal(body, &data)
if err != nil {
logger.Info("Failed to unmarshal plugin repo response error:", err)
return models.Plugin{}, err
}
return data, nil
}
func ListAllPlugins(repoUrl string) (models.PluginRepo, error) {
body, err := sendRequestGetBytes(HttpClient, repoUrl, "repo")
if err != nil {
logger.Info("Failed to send request", "error", err)
return models.PluginRepo{}, fmt.Errorf("%v: %w", "Failed to send request", err)
}
var data models.PluginRepo
err = json.Unmarshal(body, &data)
if err != nil {
logger.Info("Failed to unmarshal plugin repo response error:", err)
return models.PluginRepo{}, err
}
return data, nil
}
func sendRequestGetBytes(client http.Client, repoUrl string, subPaths ...string) ([]byte, error) {
bodyReader, err := sendRequest(client, repoUrl, subPaths...)
if err != nil {
return []byte{}, err
}
defer func() {
if err := bodyReader.Close(); err != nil {
logger.Warn("Failed to close stream", "err", err)
}
}()
return io.ReadAll(bodyReader)
}
func sendRequest(client http.Client, repoUrl string, subPaths ...string) (io.ReadCloser, error) {
req, err := createRequest(repoUrl, subPaths...)
if err != nil {
return nil, err
}
res, err := client.Do(req)
if err != nil {
return nil, err
}
return handleResponse(res)
}
func createRequest(repoUrl string, subPaths ...string) (*http.Request, error) {
u, err := url.Parse(repoUrl)
if err != nil {
return nil, err
}
for _, v := range subPaths {
u.Path = path.Join(u.Path, v)
}
req, err := http.NewRequest(http.MethodGet, u.String(), nil)
if err != nil {
return nil, err
}
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)
return req, err
}
func handleResponse(res *http.Response) (io.ReadCloser, error) {
if res.StatusCode == 404 {
return nil, ErrNotFoundError
}
if res.StatusCode/100 != 2 && res.StatusCode/100 != 4 {
return nil, fmt.Errorf("API returned invalid status: %s", res.Status)
}
if res.StatusCode/100 == 4 {
body, err := io.ReadAll(res.Body)
defer func() {
if err := res.Body.Close(); err != nil {
logger.Warn("Failed to close response body", "err", err)
}
}()
if err != nil || len(body) == 0 {
return nil, &BadRequestError{Status: res.Status}
}
var message string
var jsonBody map[string]string
err = json.Unmarshal(body, &jsonBody)
if err != nil || len(jsonBody["message"]) == 0 {
message = string(body)
} else {
message = jsonBody["message"]
}
return nil, &BadRequestError{Status: res.Status, Message: message}
}
return res.Body, nil
}