Files
grafana/pkg/tsdb/cloud-monitoring/httpclient.go
Andreas ChristouandLarissa Wandzura f704b8aa79 Cloud Monitoring: Add support for Google Cloud universe_domain (#115931)
* feat(cloud-monitoring): add support for Google Cloud universe_domain (#110083)

This change introduces support for Google Cloud's `universe_domain`, enabling connections to sovereign cloud environments with custom API endpoints.

- Adds an optional "Universe Domain" field in the Google Cloud Monitoring data source configuration (frontend and backend).
- Allows specifying a custom API domain (e.g., `s3nsapis.fr`) for use in sovereign environments.
- Defaults to `googleapis.com` to ensure backward compatibility for existing configurations.

Signed-off-by: Andreas Christou <andreas.christou@grafana.com>

* Minor docs update

* Doc updates

* Update editor

* Update docs/sources/datasources/google-cloud-monitoring/_index.md

Co-authored-by: Larissa Wandzura <126723338+lwandz13@users.noreply.github.com>

* Lint

* Review

---------

Signed-off-by: Andreas Christou <andreas.christou@grafana.com>
Co-authored-by: Larissa Wandzura <126723338+lwandz13@users.noreply.github.com>
2026-01-14 13:16:09 +00:00

87 lines
2.4 KiB
Go

package cloudmonitoring
import (
"net/http"
"github.com/grafana/grafana-google-sdk-go/pkg/tokenprovider"
"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
)
const (
cloudMonitor = "cloudmonitoring"
resourceManager = "cloudresourcemanager"
cloudMonitorScope = "https://www.googleapis.com/auth/monitoring.read"
resourceManagerScope = "https://www.googleapis.com/auth/cloudplatformprojects.readonly"
)
type routeInfo struct {
method string
url string
scopes []string
}
var routes = map[string]routeInfo{
cloudMonitor: {
method: "GET",
url: "https://monitoring.",
scopes: []string{cloudMonitorScope},
},
resourceManager: {
method: "GET",
url: "https://cloudresourcemanager.",
scopes: []string{resourceManagerScope},
},
}
func getMiddleware(model *datasourceInfo, routePath string) (httpclient.Middleware, error) {
providerConfig := tokenprovider.Config{
RoutePath: routePath,
RouteMethod: routes[routePath].method,
DataSourceID: model.id,
DataSourceUpdated: model.updated,
Scopes: routes[routePath].scopes,
}
var provider tokenprovider.TokenProvider
switch model.authenticationType {
case gceAuthentication:
if model.usingImpersonation {
providerConfig.TargetPrincipal = model.serviceAccountToImpersonate
provider = tokenprovider.NewImpersonatedGceAccessTokenProvider(providerConfig)
} else {
provider = tokenprovider.NewGceAccessTokenProvider(providerConfig)
}
case jwtAuthentication:
providerConfig.JwtTokenConfig = &tokenprovider.JwtTokenConfig{
Email: model.clientEmail,
URI: model.tokenUri,
PrivateKey: []byte(model.privateKey),
}
if model.usingImpersonation {
providerConfig.TargetPrincipal = model.serviceAccountToImpersonate
provider = tokenprovider.NewImpersonatedJwtAccessTokenProvider(providerConfig)
} else {
provider = tokenprovider.NewJwtAccessTokenProvider(providerConfig)
}
}
return tokenprovider.AuthMiddleware(provider), nil
}
func buildURL(route string, universeDomain string) string {
if universeDomain == "" {
universeDomain = "googleapis.com"
}
return routes[route].url + universeDomain
}
func newHTTPClient(model *datasourceInfo, opts httpclient.Options, clientProvider *httpclient.Provider, route string) (*http.Client, error) {
m, err := getMiddleware(model, route)
if err != nil {
return nil, err
}
opts.Middlewares = append(opts.Middlewares, m)
return clientProvider.New(opts)
}