Stackdriver: Rename Stackdriver to Google Cloud Monitoring (#25807)
* Update backend * Update frontend * Keep old plugin id * Update docs * Place doc images to a new directory * Legacy support for stackdriver-auto alignment * Consistent plugin name * Apply suggestions from code review Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com> Co-authored-by: Tobias Skarhed <1438972+tskarhed@users.noreply.github.com> * Update docs * Update public/app/plugins/datasource/cloud-monitoring/README.md Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com> * Add reference to the data source formerly being named Stackdriver * Update pkg/models/datasource.go Co-authored-by: Carl Bergquist <carl@grafana.com> * Fix gofmt Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com> Co-authored-by: Tobias Skarhed <1438972+tskarhed@users.noreply.github.com> Co-authored-by: Carl Bergquist <carl@grafana.com>
This commit is contained in:
co-authored by
Marcus Efraimsson
Tobias Skarhed
Carl Bergquist
parent
05bfd17b00
commit
4bb3f66569
@@ -20,6 +20,7 @@ import (
|
||||
_ "github.com/grafana/grafana/pkg/services/alerting/notifiers"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
_ "github.com/grafana/grafana/pkg/tsdb/azuremonitor"
|
||||
_ "github.com/grafana/grafana/pkg/tsdb/cloudmonitoring"
|
||||
_ "github.com/grafana/grafana/pkg/tsdb/cloudwatch"
|
||||
_ "github.com/grafana/grafana/pkg/tsdb/elasticsearch"
|
||||
_ "github.com/grafana/grafana/pkg/tsdb/graphite"
|
||||
@@ -28,7 +29,6 @@ import (
|
||||
_ "github.com/grafana/grafana/pkg/tsdb/opentsdb"
|
||||
_ "github.com/grafana/grafana/pkg/tsdb/postgres"
|
||||
_ "github.com/grafana/grafana/pkg/tsdb/prometheus"
|
||||
_ "github.com/grafana/grafana/pkg/tsdb/stackdriver"
|
||||
_ "github.com/grafana/grafana/pkg/tsdb/testdatasource"
|
||||
)
|
||||
|
||||
|
||||
@@ -22,9 +22,11 @@ const (
|
||||
DS_MSSQL = "mssql"
|
||||
DS_ACCESS_DIRECT = "direct"
|
||||
DS_ACCESS_PROXY = "proxy"
|
||||
DS_STACKDRIVER = "stackdriver"
|
||||
DS_AZURE_MONITOR = "grafana-azure-monitor-datasource"
|
||||
DS_LOKI = "loki"
|
||||
// Stackdriver was renamed Google Cloud monitoring 2020-05 but we keep
|
||||
// "stackdriver" to avoid breaking changes in reporting.
|
||||
DS_CLOUD_MONITORING = "stackdriver"
|
||||
DS_AZURE_MONITOR = "grafana-azure-monitor-datasource"
|
||||
DS_LOKI = "loki"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -97,7 +99,7 @@ var knownDatasourcePlugins = map[string]bool{
|
||||
DS_POSTGRES: true,
|
||||
DS_MYSQL: true,
|
||||
DS_MSSQL: true,
|
||||
DS_STACKDRIVER: true,
|
||||
DS_CLOUD_MONITORING: true,
|
||||
DS_AZURE_MONITOR: true,
|
||||
DS_LOKI: true,
|
||||
"opennms": true,
|
||||
|
||||
@@ -60,8 +60,12 @@ func (fp *FrontendPluginBase) handleModuleDefaults() {
|
||||
}
|
||||
|
||||
fp.IsCorePlugin = true
|
||||
fp.Module = path.Join("app/plugins", fp.Type, fp.Id, "module")
|
||||
fp.BaseUrl = path.Join("public/app/plugins", fp.Type, fp.Id)
|
||||
// Previously there was an assumption that the plugin directory
|
||||
// should be public/app/plugins/<plugin type>/<plugin id>
|
||||
// However this can be an issue if the plugin directory should be renamed to something else
|
||||
currentDir := path.Base(fp.PluginDir)
|
||||
fp.Module = path.Join("app/plugins", fp.Type, currentDir, "module")
|
||||
fp.BaseUrl = path.Join("public/app/plugins", fp.Type, currentDir)
|
||||
}
|
||||
|
||||
func isExternalPlugin(pluginDir string) bool {
|
||||
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
package stackdriver
|
||||
package cloudmonitoring
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/tsdb"
|
||||
)
|
||||
|
||||
func (e *StackdriverExecutor) executeAnnotationQuery(ctx context.Context, tsdbQuery *tsdb.TsdbQuery) (*tsdb.Response, error) {
|
||||
func (e *CloudMonitoringExecutor) executeAnnotationQuery(ctx context.Context, tsdbQuery *tsdb.TsdbQuery) (*tsdb.Response, error) {
|
||||
result := &tsdb.Response{
|
||||
Results: make(map[string]*tsdb.QueryResult),
|
||||
}
|
||||
@@ -34,7 +34,7 @@ func (e *StackdriverExecutor) executeAnnotationQuery(ctx context.Context, tsdbQu
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (e *StackdriverExecutor) parseToAnnotations(queryRes *tsdb.QueryResult, data stackdriverResponse, query *stackdriverQuery, title string, text string, tags string) error {
|
||||
func (e *CloudMonitoringExecutor) parseToAnnotations(queryRes *tsdb.QueryResult, data cloudMonitoringResponse, query *cloudMonitoringQuery, title string, text string, tags string) error {
|
||||
annotations := make([]map[string]string, 0)
|
||||
|
||||
for _, series := range data.TimeSeries {
|
||||
+6
-6
@@ -1,4 +1,4 @@
|
||||
package stackdriver
|
||||
package cloudmonitoring
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@@ -9,16 +9,16 @@ import (
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func TestStackdriverAnnotationQuery(t *testing.T) {
|
||||
Convey("Stackdriver Annotation Query Executor", t, func() {
|
||||
executor := &StackdriverExecutor{}
|
||||
Convey("When parsing the stackdriver api response", func() {
|
||||
func TestCloudMonitoringAnnotationQuery(t *testing.T) {
|
||||
Convey("CloudMonitoring Annotation Query Executor", t, func() {
|
||||
executor := &CloudMonitoringExecutor{}
|
||||
Convey("When parsing the cloud monitoring api response", func() {
|
||||
data, err := loadTestFile("./test-data/2-series-response-no-agg.json")
|
||||
So(err, ShouldBeNil)
|
||||
So(len(data.TimeSeries), ShouldEqual, 3)
|
||||
|
||||
res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "annotationQuery"}
|
||||
query := &stackdriverQuery{}
|
||||
query := &cloudMonitoringQuery{}
|
||||
err = executor.parseToAnnotations(res, data, query, "atitle {{metric.label.instance_name}} {{metric.value}}", "atext {{resource.label.zone}}", "atag")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package stackdriver
|
||||
package cloudmonitoring
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -48,34 +48,34 @@ const (
|
||||
sloQueryType string = "slo"
|
||||
)
|
||||
|
||||
// StackdriverExecutor executes queries for the Stackdriver datasource
|
||||
type StackdriverExecutor struct {
|
||||
// CloudMonitoringExecutor executes queries for the CloudMonitoring datasource
|
||||
type CloudMonitoringExecutor struct {
|
||||
httpClient *http.Client
|
||||
dsInfo *models.DataSource
|
||||
}
|
||||
|
||||
// NewStackdriverExecutor initializes a http client
|
||||
func NewStackdriverExecutor(dsInfo *models.DataSource) (tsdb.TsdbQueryEndpoint, error) {
|
||||
// NewCloudMonitoringExecutor initializes a http client
|
||||
func NewCloudMonitoringExecutor(dsInfo *models.DataSource) (tsdb.TsdbQueryEndpoint, error) {
|
||||
httpClient, err := dsInfo.GetHttpClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &StackdriverExecutor{
|
||||
return &CloudMonitoringExecutor{
|
||||
httpClient: httpClient,
|
||||
dsInfo: dsInfo,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
slog = log.New("tsdb.stackdriver")
|
||||
tsdb.RegisterTsdbQueryEndpoint("stackdriver", NewStackdriverExecutor)
|
||||
slog = log.New("tsdb.cloudMonitoring")
|
||||
tsdb.RegisterTsdbQueryEndpoint("stackdriver", NewCloudMonitoringExecutor)
|
||||
}
|
||||
|
||||
// Query takes in the frontend queries, parses them into the Stackdriver query format
|
||||
// executes the queries against the Stackdriver API and parses the response into
|
||||
// Query takes in the frontend queries, parses them into the CloudMonitoring query format
|
||||
// executes the queries against the CloudMonitoring API and parses the response into
|
||||
// the time series or table format
|
||||
func (e *StackdriverExecutor) Query(ctx context.Context, dsInfo *models.DataSource, tsdbQuery *tsdb.TsdbQuery) (*tsdb.Response, error) {
|
||||
func (e *CloudMonitoringExecutor) Query(ctx context.Context, dsInfo *models.DataSource, tsdbQuery *tsdb.TsdbQuery) (*tsdb.Response, error) {
|
||||
var result *tsdb.Response
|
||||
var err error
|
||||
queryType := tsdbQuery.Queries[0].Model.Get("type").MustString("")
|
||||
@@ -94,7 +94,7 @@ func (e *StackdriverExecutor) Query(ctx context.Context, dsInfo *models.DataSour
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (e *StackdriverExecutor) getGCEDefaultProject(ctx context.Context, tsdbQuery *tsdb.TsdbQuery) (*tsdb.Response, error) {
|
||||
func (e *CloudMonitoringExecutor) getGCEDefaultProject(ctx context.Context, tsdbQuery *tsdb.TsdbQuery) (*tsdb.Response, error) {
|
||||
result := &tsdb.Response{
|
||||
Results: make(map[string]*tsdb.QueryResult),
|
||||
}
|
||||
@@ -112,7 +112,7 @@ func (e *StackdriverExecutor) getGCEDefaultProject(ctx context.Context, tsdbQuer
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (e *StackdriverExecutor) executeTimeSeriesQuery(ctx context.Context, tsdbQuery *tsdb.TsdbQuery) (*tsdb.Response, error) {
|
||||
func (e *CloudMonitoringExecutor) executeTimeSeriesQuery(ctx context.Context, tsdbQuery *tsdb.TsdbQuery) (*tsdb.Response, error) {
|
||||
result := &tsdb.Response{
|
||||
Results: make(map[string]*tsdb.QueryResult),
|
||||
}
|
||||
@@ -137,8 +137,8 @@ func (e *StackdriverExecutor) executeTimeSeriesQuery(ctx context.Context, tsdbQu
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (e *StackdriverExecutor) buildQueries(tsdbQuery *tsdb.TsdbQuery) ([]*stackdriverQuery, error) {
|
||||
stackdriverQueries := []*stackdriverQuery{}
|
||||
func (e *CloudMonitoringExecutor) buildQueries(tsdbQuery *tsdb.TsdbQuery) ([]*cloudMonitoringQuery, error) {
|
||||
cloudMonitoringQueries := []*cloudMonitoringQuery{}
|
||||
|
||||
startTime, err := tsdbQuery.TimeRange.ParseFrom()
|
||||
if err != nil {
|
||||
@@ -157,14 +157,14 @@ func (e *StackdriverExecutor) buildQueries(tsdbQuery *tsdb.TsdbQuery) ([]*stackd
|
||||
q := grafanaQuery{}
|
||||
model, _ := query.Model.MarshalJSON()
|
||||
if err := json.Unmarshal(model, &q); err != nil {
|
||||
return nil, fmt.Errorf("could not unmarshal StackdriverQuery json: %w", err)
|
||||
return nil, fmt.Errorf("could not unmarshal CloudMonitoringQuery json: %w", err)
|
||||
}
|
||||
var target string
|
||||
params := url.Values{}
|
||||
params.Add("interval.startTime", startTime.UTC().Format(time.RFC3339))
|
||||
params.Add("interval.endTime", endTime.UTC().Format(time.RFC3339))
|
||||
|
||||
sq := &stackdriverQuery{
|
||||
sq := &cloudMonitoringQuery{
|
||||
RefID: query.RefId,
|
||||
GroupBys: []string{},
|
||||
}
|
||||
@@ -194,13 +194,13 @@ func (e *StackdriverExecutor) buildQueries(tsdbQuery *tsdb.TsdbQuery) ([]*stackd
|
||||
sq.Params = params
|
||||
|
||||
if setting.Env == setting.DEV {
|
||||
slog.Debug("Stackdriver request", "params", params)
|
||||
slog.Debug("CloudMonitoring request", "params", params)
|
||||
}
|
||||
|
||||
stackdriverQueries = append(stackdriverQueries, sq)
|
||||
cloudMonitoringQueries = append(cloudMonitoringQueries, sq)
|
||||
}
|
||||
|
||||
return stackdriverQueries, nil
|
||||
return cloudMonitoringQueries, nil
|
||||
}
|
||||
|
||||
func migrateLegacyQueryModel(query *tsdb.Query) {
|
||||
@@ -306,7 +306,7 @@ func calculateAlignmentPeriod(alignmentPeriod string, intervalMs int64, duration
|
||||
alignmentPeriod = "+" + strconv.Itoa(alignmentPeriodValue) + "s"
|
||||
}
|
||||
|
||||
if alignmentPeriod == "stackdriver-auto" {
|
||||
if alignmentPeriod == "cloud-monitoring-auto" || alignmentPeriod == "stackdriver-auto" { // legacy
|
||||
alignmentPeriodValue := int(math.Max(float64(durationSeconds), 60.0))
|
||||
if alignmentPeriodValue < 60*60*23 {
|
||||
alignmentPeriod = "+60s"
|
||||
@@ -320,23 +320,23 @@ func calculateAlignmentPeriod(alignmentPeriod string, intervalMs int64, duration
|
||||
return alignmentPeriod
|
||||
}
|
||||
|
||||
func (e *StackdriverExecutor) executeQuery(ctx context.Context, query *stackdriverQuery, tsdbQuery *tsdb.TsdbQuery) (*tsdb.QueryResult, stackdriverResponse, error) {
|
||||
func (e *CloudMonitoringExecutor) executeQuery(ctx context.Context, query *cloudMonitoringQuery, tsdbQuery *tsdb.TsdbQuery) (*tsdb.QueryResult, cloudMonitoringResponse, error) {
|
||||
queryResult := &tsdb.QueryResult{Meta: simplejson.New(), RefId: query.RefID}
|
||||
projectName := query.ProjectName
|
||||
if projectName == "" {
|
||||
defaultProject, err := e.getDefaultProject(ctx)
|
||||
if err != nil {
|
||||
queryResult.Error = err
|
||||
return queryResult, stackdriverResponse{}, nil
|
||||
return queryResult, cloudMonitoringResponse{}, nil
|
||||
}
|
||||
projectName = defaultProject
|
||||
slog.Info("No project name set on query, using project name from datasource", "projectName", projectName)
|
||||
}
|
||||
|
||||
req, err := e.createRequest(ctx, e.dsInfo, query, fmt.Sprintf("stackdriver%s", "v3/projects/"+projectName+"/timeSeries"))
|
||||
req, err := e.createRequest(ctx, e.dsInfo, query, fmt.Sprintf("cloudmonitoring%s", "v3/projects/"+projectName+"/timeSeries"))
|
||||
if err != nil {
|
||||
queryResult.Error = err
|
||||
return queryResult, stackdriverResponse{}, nil
|
||||
return queryResult, cloudMonitoringResponse{}, nil
|
||||
}
|
||||
|
||||
req.URL.RawQuery = query.Params.Encode()
|
||||
@@ -350,7 +350,7 @@ func (e *StackdriverExecutor) executeQuery(ctx context.Context, query *stackdriv
|
||||
}
|
||||
}
|
||||
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "stackdriver query")
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "cloudMonitoring query")
|
||||
span.SetTag("target", query.Target)
|
||||
span.SetTag("from", tsdbQuery.TimeRange.From)
|
||||
span.SetTag("until", tsdbQuery.TimeRange.To)
|
||||
@@ -364,47 +364,47 @@ func (e *StackdriverExecutor) executeQuery(ctx context.Context, query *stackdriv
|
||||
opentracing.HTTPHeaders,
|
||||
opentracing.HTTPHeadersCarrier(req.Header)); err != nil {
|
||||
queryResult.Error = err
|
||||
return queryResult, stackdriverResponse{}, nil
|
||||
return queryResult, cloudMonitoringResponse{}, nil
|
||||
}
|
||||
|
||||
res, err := ctxhttp.Do(ctx, e.httpClient, req)
|
||||
if err != nil {
|
||||
queryResult.Error = err
|
||||
return queryResult, stackdriverResponse{}, nil
|
||||
return queryResult, cloudMonitoringResponse{}, nil
|
||||
}
|
||||
|
||||
data, err := e.unmarshalResponse(res)
|
||||
if err != nil {
|
||||
queryResult.Error = err
|
||||
return queryResult, stackdriverResponse{}, nil
|
||||
return queryResult, cloudMonitoringResponse{}, nil
|
||||
}
|
||||
|
||||
return queryResult, data, nil
|
||||
}
|
||||
|
||||
func (e *StackdriverExecutor) unmarshalResponse(res *http.Response) (stackdriverResponse, error) {
|
||||
func (e *CloudMonitoringExecutor) unmarshalResponse(res *http.Response) (cloudMonitoringResponse, error) {
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
defer res.Body.Close()
|
||||
if err != nil {
|
||||
return stackdriverResponse{}, err
|
||||
return cloudMonitoringResponse{}, err
|
||||
}
|
||||
|
||||
if res.StatusCode/100 != 2 {
|
||||
slog.Error("Request failed", "status", res.Status, "body", string(body))
|
||||
return stackdriverResponse{}, fmt.Errorf(string(body))
|
||||
return cloudMonitoringResponse{}, fmt.Errorf(string(body))
|
||||
}
|
||||
|
||||
var data stackdriverResponse
|
||||
var data cloudMonitoringResponse
|
||||
err = json.Unmarshal(body, &data)
|
||||
if err != nil {
|
||||
slog.Error("Failed to unmarshal Stackdriver response", "error", err, "status", res.Status, "body", string(body))
|
||||
return stackdriverResponse{}, err
|
||||
slog.Error("Failed to unmarshal CloudMonitoring response", "error", err, "status", res.Status, "body", string(body))
|
||||
return cloudMonitoringResponse{}, err
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (e *StackdriverExecutor) parseResponse(queryRes *tsdb.QueryResult, data stackdriverResponse, query *stackdriverQuery) error {
|
||||
func (e *CloudMonitoringExecutor) parseResponse(queryRes *tsdb.QueryResult, data cloudMonitoringResponse, query *cloudMonitoringQuery) error {
|
||||
labels := make(map[string]map[string]bool)
|
||||
|
||||
for _, series := range data.TimeSeries {
|
||||
@@ -570,7 +570,7 @@ func containsLabel(labels []string, newLabel string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func formatLegendKeys(metricType string, defaultMetricName string, labels map[string]string, additionalLabels map[string]string, query *stackdriverQuery) string {
|
||||
func formatLegendKeys(metricType string, defaultMetricName string, labels map[string]string, additionalLabels map[string]string, query *cloudMonitoringQuery) string {
|
||||
if query.AliasBy == "" {
|
||||
return defaultMetricName
|
||||
}
|
||||
@@ -639,7 +639,7 @@ func replaceWithMetricPart(metaPartName string, metricType string) []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
func calcBucketBound(bucketOptions stackdriverBucketOptions, n int) string {
|
||||
func calcBucketBound(bucketOptions cloudMonitoringBucketOptions, n int) string {
|
||||
bucketBound := "0"
|
||||
if n == 0 {
|
||||
return bucketBound
|
||||
@@ -655,7 +655,7 @@ func calcBucketBound(bucketOptions stackdriverBucketOptions, n int) string {
|
||||
return bucketBound
|
||||
}
|
||||
|
||||
func (e *StackdriverExecutor) createRequest(ctx context.Context, dsInfo *models.DataSource, query *stackdriverQuery, proxyPass string) (*http.Request, error) {
|
||||
func (e *CloudMonitoringExecutor) createRequest(ctx context.Context, dsInfo *models.DataSource, query *cloudMonitoringQuery, proxyPass string) (*http.Request, error) {
|
||||
u, err := url.Parse(dsInfo.Url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -674,23 +674,23 @@ func (e *StackdriverExecutor) createRequest(ctx context.Context, dsInfo *models.
|
||||
// find plugin
|
||||
plugin, ok := plugins.DataSources[dsInfo.Type]
|
||||
if !ok {
|
||||
return nil, errors.New("Unable to find datasource plugin Stackdriver")
|
||||
return nil, errors.New("Unable to find datasource plugin CloudMonitoring")
|
||||
}
|
||||
|
||||
var stackdriverRoute *plugins.AppPluginRoute
|
||||
var cloudMonitoringRoute *plugins.AppPluginRoute
|
||||
for _, route := range plugin.Routes {
|
||||
if route.Path == "stackdriver" {
|
||||
stackdriverRoute = route
|
||||
if route.Path == "cloudmonitoring" {
|
||||
cloudMonitoringRoute = route
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
pluginproxy.ApplyRoute(ctx, req, proxyPass, stackdriverRoute, dsInfo)
|
||||
pluginproxy.ApplyRoute(ctx, req, proxyPass, cloudMonitoringRoute, dsInfo)
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func (e *StackdriverExecutor) getDefaultProject(ctx context.Context) (string, error) {
|
||||
func (e *CloudMonitoringExecutor) getDefaultProject(ctx context.Context) (string, error) {
|
||||
authenticationType := e.dsInfo.JsonData.Get("authenticationType").MustString(jwtAuthentication)
|
||||
if authenticationType == gceAuthentication {
|
||||
defaultCredentials, err := google.FindDefaultCredentials(ctx, "https://www.googleapis.com/auth/monitoring.read")
|
||||
+76
-22
@@ -1,4 +1,4 @@
|
||||
package stackdriver
|
||||
package cloudmonitoring
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -15,11 +15,11 @@ import (
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func TestStackdriver(t *testing.T) {
|
||||
Convey("Stackdriver", t, func() {
|
||||
executor := &StackdriverExecutor{}
|
||||
func TestCloudMonitoring(t *testing.T) {
|
||||
Convey("Google Cloud Monitoring", t, func() {
|
||||
executor := &CloudMonitoringExecutor{}
|
||||
|
||||
Convey("Parse migrated queries from frontend and build Stackdriver API queries", func() {
|
||||
Convey("Parse migrated queries from frontend and build Google Cloud Monitoring API queries", func() {
|
||||
fromStart := time.Date(2018, 3, 15, 13, 0, 0, 0, time.UTC).In(time.Local)
|
||||
tsdbQuery := &tsdb.TsdbQuery{
|
||||
TimeRange: &tsdb.TimeRange{
|
||||
@@ -92,7 +92,61 @@ func TestStackdriver(t *testing.T) {
|
||||
})
|
||||
})
|
||||
|
||||
Convey("and alignmentPeriod is set to stackdriver-auto", func() {
|
||||
Convey("and alignmentPeriod is set to cloud-monitoring-auto", func() { // legacy
|
||||
Convey("and range is two hours", func() {
|
||||
tsdbQuery.TimeRange.From = "1538033322461"
|
||||
tsdbQuery.TimeRange.To = "1538040522461"
|
||||
tsdbQuery.Queries[0].Model = simplejson.NewFromAny(map[string]interface{}{
|
||||
"target": "target",
|
||||
"alignmentPeriod": "cloud-monitoring-auto",
|
||||
})
|
||||
|
||||
queries, err := executor.buildQueries(tsdbQuery)
|
||||
So(err, ShouldBeNil)
|
||||
So(queries[0].Params["aggregation.alignmentPeriod"][0], ShouldEqual, `+60s`)
|
||||
})
|
||||
|
||||
Convey("and range is 22 hours", func() {
|
||||
tsdbQuery.TimeRange.From = "1538034524922"
|
||||
tsdbQuery.TimeRange.To = "1538113724922"
|
||||
tsdbQuery.Queries[0].Model = simplejson.NewFromAny(map[string]interface{}{
|
||||
"target": "target",
|
||||
"alignmentPeriod": "cloud-monitoring-auto",
|
||||
})
|
||||
|
||||
queries, err := executor.buildQueries(tsdbQuery)
|
||||
So(err, ShouldBeNil)
|
||||
So(queries[0].Params["aggregation.alignmentPeriod"][0], ShouldEqual, `+60s`)
|
||||
})
|
||||
|
||||
Convey("and range is 23 hours", func() {
|
||||
tsdbQuery.TimeRange.From = "1538034567985"
|
||||
tsdbQuery.TimeRange.To = "1538117367985"
|
||||
tsdbQuery.Queries[0].Model = simplejson.NewFromAny(map[string]interface{}{
|
||||
"target": "target",
|
||||
"alignmentPeriod": "cloud-monitoring-auto",
|
||||
})
|
||||
|
||||
queries, err := executor.buildQueries(tsdbQuery)
|
||||
So(err, ShouldBeNil)
|
||||
So(queries[0].Params["aggregation.alignmentPeriod"][0], ShouldEqual, `+300s`)
|
||||
})
|
||||
|
||||
Convey("and range is 7 days", func() {
|
||||
tsdbQuery.TimeRange.From = "1538036324073"
|
||||
tsdbQuery.TimeRange.To = "1538641124073"
|
||||
tsdbQuery.Queries[0].Model = simplejson.NewFromAny(map[string]interface{}{
|
||||
"target": "target",
|
||||
"alignmentPeriod": "cloud-monitoring-auto",
|
||||
})
|
||||
|
||||
queries, err := executor.buildQueries(tsdbQuery)
|
||||
So(err, ShouldBeNil)
|
||||
So(queries[0].Params["aggregation.alignmentPeriod"][0], ShouldEqual, `+3600s`)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("and alignmentPeriod is set to stackdriver-auto", func() { // legacy
|
||||
Convey("and range is two hours", func() {
|
||||
tsdbQuery.TimeRange.From = "1538033322461"
|
||||
tsdbQuery.TimeRange.To = "1538040522461"
|
||||
@@ -208,7 +262,7 @@ func TestStackdriver(t *testing.T) {
|
||||
|
||||
})
|
||||
|
||||
Convey("Parse queries from frontend and build Stackdriver API queries", func() {
|
||||
Convey("Parse queries from frontend and build Google Cloud Monitoring API queries", func() {
|
||||
fromStart := time.Date(2018, 3, 15, 13, 0, 0, 0, time.UTC).In(time.Local)
|
||||
tsdbQuery := &tsdb.TsdbQuery{
|
||||
TimeRange: &tsdb.TimeRange{
|
||||
@@ -301,14 +355,14 @@ func TestStackdriver(t *testing.T) {
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Parse stackdriver response in the time series format", func() {
|
||||
Convey("Parse cloud monitoring response in the time series format", func() {
|
||||
Convey("when data from query aggregated to one time series", func() {
|
||||
data, err := loadTestFile("./test-data/1-series-response-agg-one-metric.json")
|
||||
So(err, ShouldBeNil)
|
||||
So(len(data.TimeSeries), ShouldEqual, 1)
|
||||
|
||||
res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "A"}
|
||||
query := &stackdriverQuery{}
|
||||
query := &cloudMonitoringQuery{}
|
||||
err = executor.parseResponse(res, data, query)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
@@ -334,7 +388,7 @@ func TestStackdriver(t *testing.T) {
|
||||
So(len(data.TimeSeries), ShouldEqual, 3)
|
||||
|
||||
res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "A"}
|
||||
query := &stackdriverQuery{}
|
||||
query := &cloudMonitoringQuery{}
|
||||
err = executor.parseResponse(res, data, query)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
@@ -376,7 +430,7 @@ func TestStackdriver(t *testing.T) {
|
||||
So(len(data.TimeSeries), ShouldEqual, 3)
|
||||
|
||||
res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "A"}
|
||||
query := &stackdriverQuery{GroupBys: []string{"metric.label.instance_name", "resource.label.zone"}}
|
||||
query := &cloudMonitoringQuery{GroupBys: []string{"metric.label.instance_name", "resource.label.zone"}}
|
||||
err = executor.parseResponse(res, data, query)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
@@ -397,7 +451,7 @@ func TestStackdriver(t *testing.T) {
|
||||
|
||||
Convey("and the alias pattern is for metric type, a metric label and a resource label", func() {
|
||||
|
||||
query := &stackdriverQuery{AliasBy: "{{metric.type}} - {{metric.label.instance_name}} - {{resource.label.zone}}", GroupBys: []string{"metric.label.instance_name", "resource.label.zone"}}
|
||||
query := &cloudMonitoringQuery{AliasBy: "{{metric.type}} - {{metric.label.instance_name}} - {{resource.label.zone}}", GroupBys: []string{"metric.label.instance_name", "resource.label.zone"}}
|
||||
err = executor.parseResponse(res, data, query)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
@@ -411,7 +465,7 @@ func TestStackdriver(t *testing.T) {
|
||||
|
||||
Convey("and the alias pattern is for metric name", func() {
|
||||
|
||||
query := &stackdriverQuery{AliasBy: "metric {{metric.name}} service {{metric.service}}", GroupBys: []string{"metric.label.instance_name", "resource.label.zone"}}
|
||||
query := &cloudMonitoringQuery{AliasBy: "metric {{metric.name}} service {{metric.service}}", GroupBys: []string{"metric.label.instance_name", "resource.label.zone"}}
|
||||
err = executor.parseResponse(res, data, query)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
@@ -430,7 +484,7 @@ func TestStackdriver(t *testing.T) {
|
||||
So(len(data.TimeSeries), ShouldEqual, 1)
|
||||
|
||||
res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "A"}
|
||||
query := &stackdriverQuery{AliasBy: "{{bucket}}"}
|
||||
query := &cloudMonitoringQuery{AliasBy: "{{bucket}}"}
|
||||
err = executor.parseResponse(res, data, query)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
@@ -477,7 +531,7 @@ func TestStackdriver(t *testing.T) {
|
||||
So(len(data.TimeSeries), ShouldEqual, 1)
|
||||
|
||||
res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "A"}
|
||||
query := &stackdriverQuery{AliasBy: "{{bucket}}"}
|
||||
query := &cloudMonitoringQuery{AliasBy: "{{bucket}}"}
|
||||
err = executor.parseResponse(res, data, query)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
@@ -517,7 +571,7 @@ func TestStackdriver(t *testing.T) {
|
||||
So(len(data.TimeSeries), ShouldEqual, 3)
|
||||
|
||||
res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "A"}
|
||||
query := &stackdriverQuery{AliasBy: "{{bucket}}"}
|
||||
query := &cloudMonitoringQuery{AliasBy: "{{bucket}}"}
|
||||
err = executor.parseResponse(res, data, query)
|
||||
labels := res.Meta.Get("labels").Interface().(map[string][]string)
|
||||
So(err, ShouldBeNil)
|
||||
@@ -556,7 +610,7 @@ func TestStackdriver(t *testing.T) {
|
||||
|
||||
Convey("and systemlabel contains key with array of string", func() {
|
||||
res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "A"}
|
||||
query := &stackdriverQuery{AliasBy: "{{metadata.system_labels.test}}"}
|
||||
query := &cloudMonitoringQuery{AliasBy: "{{metadata.system_labels.test}}"}
|
||||
err = executor.parseResponse(res, data, query)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(res.Series), ShouldEqual, 3)
|
||||
@@ -568,7 +622,7 @@ func TestStackdriver(t *testing.T) {
|
||||
|
||||
Convey("and systemlabel contains key with array of string2", func() {
|
||||
res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "A"}
|
||||
query := &stackdriverQuery{AliasBy: "{{metadata.system_labels.test2}}"}
|
||||
query := &cloudMonitoringQuery{AliasBy: "{{metadata.system_labels.test2}}"}
|
||||
err = executor.parseResponse(res, data, query)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(res.Series), ShouldEqual, 3)
|
||||
@@ -584,7 +638,7 @@ func TestStackdriver(t *testing.T) {
|
||||
|
||||
Convey("and alias by is expanded", func() {
|
||||
res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "A"}
|
||||
query := &stackdriverQuery{
|
||||
query := &cloudMonitoringQuery{
|
||||
ProjectName: "test-proj",
|
||||
Selector: "select_slo_compliance",
|
||||
Service: "test-service",
|
||||
@@ -604,7 +658,7 @@ func TestStackdriver(t *testing.T) {
|
||||
|
||||
Convey("and alias by is expanded", func() {
|
||||
res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "A"}
|
||||
query := &stackdriverQuery{
|
||||
query := &cloudMonitoringQuery{
|
||||
ProjectName: "test-proj",
|
||||
Selector: "select_slo_compliance",
|
||||
Service: "test-service",
|
||||
@@ -710,8 +764,8 @@ func TestStackdriver(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func loadTestFile(path string) (stackdriverResponse, error) {
|
||||
var data stackdriverResponse
|
||||
func loadTestFile(path string) (cloudMonitoringResponse, error) {
|
||||
var data cloudMonitoringResponse
|
||||
|
||||
jsonBody, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
@@ -1,4 +1,4 @@
|
||||
package stackdriver
|
||||
package cloudmonitoring
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
)
|
||||
|
||||
type (
|
||||
stackdriverQuery struct {
|
||||
cloudMonitoringQuery struct {
|
||||
Target string
|
||||
Params url.Values
|
||||
RefID string
|
||||
@@ -48,7 +48,7 @@ type (
|
||||
SloQuery sloQuery
|
||||
}
|
||||
|
||||
stackdriverBucketOptions struct {
|
||||
cloudMonitoringBucketOptions struct {
|
||||
LinearBuckets *struct {
|
||||
NumFiniteBuckets int64 `json:"numFiniteBuckets"`
|
||||
Width int64 `json:"width"`
|
||||
@@ -64,7 +64,7 @@ type (
|
||||
} `json:"explicitBuckets"`
|
||||
}
|
||||
|
||||
stackdriverResponse struct {
|
||||
cloudMonitoringResponse struct {
|
||||
TimeSeries []struct {
|
||||
Metric struct {
|
||||
Labels map[string]string `json:"labels"`
|
||||
@@ -95,8 +95,8 @@ type (
|
||||
Min int `json:"min"`
|
||||
Max int `json:"max"`
|
||||
} `json:"range"`
|
||||
BucketOptions stackdriverBucketOptions `json:"bucketOptions"`
|
||||
BucketCounts []string `json:"bucketCounts"`
|
||||
BucketOptions cloudMonitoringBucketOptions `json:"bucketOptions"`
|
||||
BucketCounts []string `json:"bucketCounts"`
|
||||
Examplars []struct {
|
||||
Value float64 `json:"value"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
Reference in New Issue
Block a user