CloudMonitoring: switch from ApplyRoute to AuthMiddleware (#40787)

This commit is contained in:
Isabella Siu 2021-10-26 10:17:12 -04:00 committed by GitHub
parent 2c3b35df64
commit 8ee3afa4c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 117 additions and 62 deletions

View File

@ -23,7 +23,6 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
"github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana/pkg/api/pluginproxy"
"github.com/grafana/grafana/pkg/infra/httpclient"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/plugins"
@ -63,6 +62,8 @@ var (
)
const (
dsName = "stackdriver"
gceAuthentication string = "gce"
jwtAuthentication string = "jwt"
metricQueryType string = "metrics"
@ -87,7 +88,7 @@ func ProvideService(cfg *setting.Cfg, httpClientProvider httpclient.Provider, pl
QueryDataHandler: s,
})
if err := s.backendPluginManager.Register("stackdriver", factory); err != nil {
if err := s.backendPluginManager.Register(dsName, factory); err != nil {
slog.Error("Failed to register plugin", "error", err)
}
return s
@ -112,9 +113,10 @@ type datasourceInfo struct {
url string
authenticationType string
defaultProject string
clientEmail string
tokenUri string
client *http.Client
jsonData map[string]interface{}
decryptedSecureJSONData map[string]string
}
@ -126,16 +128,6 @@ func newInstanceSettings(httpClientProvider httpclient.Provider) datasource.Inst
return nil, fmt.Errorf("error reading settings: %w", err)
}
opts, err := settings.HTTPClientOptions()
if err != nil {
return nil, err
}
client, err := httpClientProvider.New(opts)
if err != nil {
return nil, err
}
authType := jwtAuthentication
if authTypeOverride, ok := jsonData["authenticationType"].(string); ok && authTypeOverride != "" {
authType = authTypeOverride
@ -146,16 +138,38 @@ func newInstanceSettings(httpClientProvider httpclient.Provider) datasource.Inst
defaultProject = jsonData["defaultProject"].(string)
}
return &datasourceInfo{
var clientEmail string
if jsonData["clientEmail"] != nil {
clientEmail = jsonData["clientEmail"].(string)
}
var tokenUri string
if jsonData["tokenUri"] != nil {
tokenUri = jsonData["tokenUri"].(string)
}
dsInfo := &datasourceInfo{
id: settings.ID,
updated: settings.Updated,
url: settings.URL,
authenticationType: authType,
defaultProject: defaultProject,
client: client,
jsonData: jsonData,
clientEmail: clientEmail,
tokenUri: tokenUri,
decryptedSecureJSONData: settings.DecryptedSecureJSONData,
}, nil
}
opts, err := settings.HTTPClientOptions()
if err != nil {
return nil, err
}
dsInfo.client, err = newHTTPClient(dsInfo, opts, httpClientProvider)
if err != nil {
return nil, err
}
return dsInfo, nil
}
}
@ -340,14 +354,6 @@ func (s *Service) buildQueryExecutors(req *backend.QueryDataRequest) ([]cloudMon
return cloudMonitoringQueryExecutors, nil
}
func reverse(s string) string {
chars := []rune(s)
for i, j := 0, len(chars)-1; i < j; i, j = i+1, j-1 {
chars[i], chars[j] = chars[j], chars[i]
}
return string(chars)
}
func interpolateFilterWildcards(value string) string {
matches := strings.Count(value, "*")
switch {
@ -478,19 +484,6 @@ func calculateAlignmentPeriod(alignmentPeriod string, intervalMs int64, duration
return alignmentPeriod
}
func toSnakeCase(str string) string {
return strings.ToLower(matchAllCap.ReplaceAllString(str, "${1}_${2}"))
}
func containsLabel(labels []string, newLabel string) bool {
for _, val := range labels {
if val == newLabel {
return true
}
}
return false
}
func formatLegendKeys(metricType string, defaultMetricName string, labels map[string]string,
additionalLabels map[string]string, query *cloudMonitoringTimeSeriesFilter) string {
if query.AliasBy == "" {
@ -589,34 +582,14 @@ func (s *Service) createRequest(ctx context.Context, pluginCtx backend.PluginCon
if body != nil {
method = http.MethodPost
}
req, err := http.NewRequest(method, "https://monitoring.googleapis.com/", body)
req, err := http.NewRequest(method, cloudMonitoringRoute.url, body)
if err != nil {
slog.Error("Failed to create request", "error", err)
return nil, fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
// find plugin
plugin := s.pluginManager.GetDataSource(pluginCtx.PluginID)
if plugin == nil {
return nil, errors.New("unable to find datasource plugin CloudMonitoring")
}
var cloudMonitoringRoute *plugins.AppPluginRoute
for _, route := range plugin.Routes {
if route.Path == "cloudmonitoring" {
cloudMonitoringRoute = route
break
}
}
pluginproxy.ApplyRoute(ctx, req, proxyPass, cloudMonitoringRoute, pluginproxy.DSInfo{
ID: dsInfo.id,
Updated: dsInfo.updated,
JSONData: dsInfo.jsonData,
DecryptedSecureJSONData: dsInfo.decryptedSecureJSONData,
}, s.cfg)
req.URL.Path = proxyPass
return req, nil
}

View File

@ -0,0 +1,56 @@
package cloudmonitoring
import (
"net/http"
"github.com/grafana/grafana-google-sdk-go/pkg/tokenprovider"
"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
infrahttp "github.com/grafana/grafana/pkg/infra/httpclient"
)
var cloudMonitoringRoute = struct {
path string
method string
url string
scopes []string
}{
path: "cloudmonitoring",
method: "GET",
url: "https://monitoring.googleapis.com",
scopes: []string{"https://www.googleapis.com/auth/monitoring.read"},
}
func getMiddleware(model *datasourceInfo) (httpclient.Middleware, error) {
providerConfig := tokenprovider.Config{
RoutePath: cloudMonitoringRoute.path,
RouteMethod: cloudMonitoringRoute.method,
DataSourceID: model.id,
DataSourceUpdated: model.updated,
Scopes: cloudMonitoringRoute.scopes,
}
var provider tokenprovider.TokenProvider
switch model.authenticationType {
case gceAuthentication:
provider = tokenprovider.NewGceAccessTokenProvider(providerConfig)
case jwtAuthentication:
providerConfig.JwtTokenConfig = &tokenprovider.JwtTokenConfig{
Email: model.clientEmail,
URI: model.tokenUri,
PrivateKey: []byte(model.decryptedSecureJSONData["privateKey"]),
}
provider = tokenprovider.NewJwtAccessTokenProvider(providerConfig)
}
return tokenprovider.AuthMiddleware(provider), nil
}
func newHTTPClient(model *datasourceInfo, opts httpclient.Options, clientProvider infrahttp.Provider) (*http.Client, error) {
m, err := getMiddleware(model)
if err != nil {
return nil, err
}
opts.Middlewares = append(opts.Middlewares, m)
return clientProvider.New(opts)
}

View File

@ -29,7 +29,7 @@ func (timeSeriesFilter *cloudMonitoringTimeSeriesFilter) run(ctx context.Context
slog.Info("No project name set on query, using project name from datasource", "projectName", projectName)
}
r, err := s.createRequest(ctx, req.PluginContext, &dsInfo, path.Join("cloudmonitoringv3/projects", projectName, "timeSeries"), nil)
r, err := s.createRequest(ctx, req.PluginContext, &dsInfo, path.Join("/v3/projects", projectName, "timeSeries"), nil)
if err != nil {
dr.Error = err
return dr, cloudMonitoringResponse{}, "", nil

View File

@ -49,7 +49,7 @@ func (timeSeriesQuery cloudMonitoringTimeSeriesQuery) run(ctx context.Context, r
dr.Error = err
return dr, cloudMonitoringResponse{}, "", nil
}
r, err := s.createRequest(ctx, req.PluginContext, &dsInfo, path.Join("cloudmonitoringv3/projects", projectName, "timeSeries:query"), bytes.NewBuffer(buf))
r, err := s.createRequest(ctx, req.PluginContext, &dsInfo, path.Join("/v3/projects", projectName, "timeSeries:query"), bytes.NewBuffer(buf))
if err != nil {
dr.Error = err
return dr, cloudMonitoringResponse{}, "", nil

View File

@ -0,0 +1,26 @@
package cloudmonitoring
import (
"strings"
)
func reverse(s string) string {
chars := []rune(s)
for i, j := 0, len(chars)-1; i < j; i, j = i+1, j-1 {
chars[i], chars[j] = chars[j], chars[i]
}
return string(chars)
}
func toSnakeCase(str string) string {
return strings.ToLower(matchAllCap.ReplaceAllString(str, "${1}_${2}"))
}
func containsLabel(labels []string, newLabel string) bool {
for _, val := range labels {
if val == newLabel {
return true
}
}
return false
}