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/tsdb/azuremonitor/utils/utils.go

89 lines
2.5 KiB

package utils
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
"github.com/grafana/grafana-plugin-sdk-go/experimental/errorsource"
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/types"
)
const SubscriptionsApiVersion = "2020-01-01"
func GetFirstSubscriptionOrDefault(ctx context.Context, dsInfo types.DatasourceInfo, logger log.Logger) (string, error) {
if dsInfo.Settings.SubscriptionId != "" {
return dsInfo.Settings.SubscriptionId, nil
}
url := fmt.Sprintf("%v/subscriptions?api-version=%v", dsInfo.Routes["Azure Monitor"].URL, SubscriptionsApiVersion)
request, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return "", err
}
res, err := dsInfo.Services["Azure Monitor"].HTTPClient.Do(request)
if err != nil {
return "", errorsource.DownstreamError(fmt.Errorf("failed to retrieve subscriptions: %v", err), false)
}
defer func() {
if err := res.Body.Close(); err != nil {
logger.Warn("Failed to close response body", "err", err)
}
}()
subscriptions, err := ParseSubscriptions(res, logger)
if err != nil {
return "", fmt.Errorf("failed to parse subscriptions: %v", err)
}
if len(subscriptions) == 0 {
return "", errorsource.DownstreamError(fmt.Errorf("no subscriptions found: %v", err), false)
}
return subscriptions[0], nil
}
func ParseSubscriptions(res *http.Response, logger log.Logger) ([]string, error) {
var target struct {
Value []struct {
SubscriptionId string `json:"subscriptionId"`
}
}
err := json.NewDecoder(res.Body).Decode(&target)
if err != nil {
return nil, err
}
defer func() {
if err := res.Body.Close(); err != nil {
logger.Warn("Failed to close response body", "err", err)
}
}()
result := make([]string, len(target.Value))
for i, v := range target.Value {
result[i] = v.SubscriptionId
}
return result, nil
}
func ApplySourceFromError(errorMessage error, err error) error {
var sourceError errorsource.Error
if errors.As(err, &sourceError) {
return errorsource.SourceError(sourceError.Source(), errorMessage, false)
}
return errorMessage
}
func CreateResponseErrorFromStatusCode(statusCode int, status string, body []byte) error {
statusErr := fmt.Errorf("request failed, status: %s, body: %s", status, string(body))
if backend.ErrorSourceFromHTTPStatus(statusCode) == backend.ErrorSourceDownstream {
return backend.DownstreamError(statusErr)
}
return backend.PluginError(statusErr)
}