From 934a8f08ae20f26794b3a28ecea0447ff56c7087 Mon Sep 17 00:00:00 2001 From: Erik Sundell Date: Mon, 2 Mar 2020 09:31:09 -0500 Subject: [PATCH] Stackdriver: Project selector (#22447) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * clean PR #17366 * udpate vendor * [WIP] Implement projects management for stackdriver * [WIP] Implement projects management for stackdriver * [WIP] Implement projects management for stackdriver * Implement projects management for stackdriver * [WIP][Tests] Fix errors * clean anonymous struct * remove await * don't store project list * Add default project on query editor * gofmt * Fix tests * Move test data source to backend * Use segment instead of dropdown. remove ensure default project since it's not being used anymore. * Fix broken annotation editor * Load gceDefaultAccount only once when in the config page * Reset error message on auth type change * Add metric find query for projects * Remove debug code * Fix broken tests * Fix typings * Fix lint error * Slightly different approach - now having a distiction between config page default project, and project that is selectable from the dropdown in the query editor. * Fix broken tests * Attempt to fix strict ts errors * Prevent state from being set multiple times * Remove noOptionsMessage since it seems to be obosolete in react select * One more attempt to solve ts strict error * Interpolate project template variable. Make sure its loaded correctly when opening variable query editor first time * Implicit any fix * fix: typescript strict null check fixes * Return empty array in case project endpoint fails * Rename project to projectName to prevent clashing with legacy query prop * Fix broken test * fix: Stackdriver - template replace on filter label should have a regex format as that escapes the dots in the label name which is not valid. Co-authored-by: Labesse Kévin Co-authored-by: Elias Cédric Laouiti Co-authored-by: Daniel Lee --- go.mod | 3 +- go.sum | 48 + .../src/components/Segment/SegmentSelect.tsx | 1 - .../stackdriver/ensure_default_project.go | 24 - pkg/tsdb/stackdriver/stackdriver.go | 171 +- pkg/tsdb/stackdriver/types.go | 151 +- .../core/components/Select/MetricSelect.tsx | 1 - .../stackdriver/StackdriverMetricFindQuery.ts | 56 +- .../stackdriver/annotations_query_ctrl.ts | 3 +- .../stackdriver/components/Aggregations.tsx | 3 +- .../stackdriver/components/AliasBy.tsx | 2 +- .../components/AlignmentPeriods.tsx | 2 +- .../stackdriver/components/Alignments.tsx | 2 +- .../components/AnnotationQueryEditor.tsx | 36 +- .../components/AnnotationsHelp.tsx | 6 +- .../stackdriver/components/Help.tsx | 6 +- .../stackdriver/components/Metrics.tsx | 198 +- .../stackdriver/components/Project.tsx | 49 +- .../components/QueryEditor.test.tsx | 5 +- .../stackdriver/components/QueryEditor.tsx | 61 +- .../stackdriver/components/SimpleSelect.tsx | 2 +- .../components/VariableQueryEditor.test.tsx | 4 +- .../components/VariableQueryEditor.tsx | 100 +- .../__snapshots__/QueryEditor.test.tsx.snap | 49 +- .../VariableQueryEditor.test.tsx.snap | 7 +- .../datasource/stackdriver/config_ctrl.ts | 43 +- .../datasource/stackdriver/datasource.ts | 180 +- .../datasource/stackdriver/functions.ts | 39 +- .../stackdriver/partials/config.html | 118 +- .../stackdriver/specs/datasource.test.ts | 30 +- .../plugins/datasource/stackdriver/types.ts | 21 +- vendor/cloud.google.com/go/AUTHORS | 15 - vendor/cloud.google.com/go/CONTRIBUTORS | 40 - .../go/compute/metadata/metadata.go | 24 +- .../github.com/googleapis/gax-go/v2/LICENSE | 27 + .../googleapis/gax-go/v2/call_option.go | 161 + vendor/github.com/googleapis/gax-go/v2/gax.go | 39 + vendor/github.com/googleapis/gax-go/v2/go.mod | 3 + vendor/github.com/googleapis/gax-go/v2/go.sum | 25 + .../github.com/googleapis/gax-go/v2/header.go | 53 + .../github.com/googleapis/gax-go/v2/invoke.go | 99 + .../github.com/hashicorp/golang-lru/LICENSE | 362 + .../hashicorp/golang-lru/simplelru/lru.go | 161 + .../golang-lru/simplelru/lru_interface.go | 36 + vendor/go.opencensus.io/.gitignore | 9 + vendor/go.opencensus.io/AUTHORS | 1 + vendor/go.opencensus.io/CONTRIBUTING.md | 63 + vendor/go.opencensus.io/Gopkg.lock | 231 + vendor/go.opencensus.io/Gopkg.toml | 36 + vendor/go.opencensus.io/LICENSE | 202 + vendor/go.opencensus.io/Makefile | 96 + vendor/go.opencensus.io/README.md | 263 + vendor/go.opencensus.io/go.mod | 10 + vendor/go.opencensus.io/go.sum | 50 + vendor/go.opencensus.io/internal/internal.go | 37 + vendor/go.opencensus.io/internal/sanitize.go | 50 + .../internal/tagencoding/tagencoding.go | 75 + .../internal/traceinternals.go | 53 + .../go.opencensus.io/metric/metricdata/doc.go | 19 + .../metric/metricdata/exemplar.go | 38 + .../metric/metricdata/label.go | 35 + .../metric/metricdata/metric.go | 46 + .../metric/metricdata/point.go | 193 + .../metric/metricdata/type_string.go | 16 + .../metric/metricdata/unit.go | 27 + .../metric/metricproducer/manager.go | 78 + .../metric/metricproducer/producer.go | 28 + vendor/go.opencensus.io/opencensus.go | 21 + .../go.opencensus.io/plugin/ochttp/client.go | 117 + .../plugin/ochttp/client_stats.go | 143 + vendor/go.opencensus.io/plugin/ochttp/doc.go | 19 + .../plugin/ochttp/propagation/b3/b3.go | 123 + .../go.opencensus.io/plugin/ochttp/route.go | 61 + .../go.opencensus.io/plugin/ochttp/server.go | 449 + .../ochttp/span_annotating_client_trace.go | 169 + .../go.opencensus.io/plugin/ochttp/stats.go | 292 + .../go.opencensus.io/plugin/ochttp/trace.go | 239 + .../plugin/ochttp/wrapped_body.go | 44 + vendor/go.opencensus.io/resource/resource.go | 164 + vendor/go.opencensus.io/stats/doc.go | 69 + .../go.opencensus.io/stats/internal/record.go | 25 + vendor/go.opencensus.io/stats/measure.go | 109 + .../go.opencensus.io/stats/measure_float64.go | 55 + .../go.opencensus.io/stats/measure_int64.go | 55 + vendor/go.opencensus.io/stats/record.go | 117 + vendor/go.opencensus.io/stats/units.go | 25 + .../stats/view/aggregation.go | 120 + .../stats/view/aggregation_data.go | 293 + .../go.opencensus.io/stats/view/collector.go | 86 + vendor/go.opencensus.io/stats/view/doc.go | 47 + vendor/go.opencensus.io/stats/view/export.go | 58 + vendor/go.opencensus.io/stats/view/view.go | 221 + .../stats/view/view_to_metric.go | 140 + vendor/go.opencensus.io/stats/view/worker.go | 281 + .../stats/view/worker_commands.go | 186 + vendor/go.opencensus.io/tag/context.go | 43 + vendor/go.opencensus.io/tag/doc.go | 26 + vendor/go.opencensus.io/tag/key.go | 35 + vendor/go.opencensus.io/tag/map.go | 229 + vendor/go.opencensus.io/tag/map_codec.go | 239 + vendor/go.opencensus.io/tag/metadata.go | 52 + vendor/go.opencensus.io/tag/profile_19.go | 31 + vendor/go.opencensus.io/tag/profile_not19.go | 23 + vendor/go.opencensus.io/tag/validate.go | 56 + vendor/go.opencensus.io/trace/basetypes.go | 119 + vendor/go.opencensus.io/trace/config.go | 86 + vendor/go.opencensus.io/trace/doc.go | 53 + vendor/go.opencensus.io/trace/evictedqueue.go | 38 + vendor/go.opencensus.io/trace/export.go | 97 + .../trace/internal/internal.go | 22 + vendor/go.opencensus.io/trace/lrumap.go | 37 + .../trace/propagation/propagation.go | 108 + vendor/go.opencensus.io/trace/sampling.go | 75 + vendor/go.opencensus.io/trace/spanbucket.go | 130 + vendor/go.opencensus.io/trace/spanstore.go | 306 + vendor/go.opencensus.io/trace/status_codes.go | 37 + vendor/go.opencensus.io/trace/trace.go | 598 ++ vendor/go.opencensus.io/trace/trace_go11.go | 32 + .../go.opencensus.io/trace/trace_nongo11.go | 25 + .../trace/tracestate/tracestate.go | 147 + vendor/golang.org/x/oauth2/google/default.go | 3 +- vendor/golang.org/x/oauth2/google/google.go | 26 +- vendor/golang.org/x/oauth2/jwt/jwt.go | 21 +- vendor/golang.org/x/oauth2/oauth2.go | 2 +- vendor/google.golang.org/api/AUTHORS | 11 + vendor/google.golang.org/api/CONTRIBUTORS | 56 + vendor/google.golang.org/api/LICENSE | 27 + .../v1/cloudresourcemanager-api.json | 2071 ++++ .../v1/cloudresourcemanager-gen.go | 8450 +++++++++++++++++ .../api/googleapi/googleapi.go | 408 + .../api/googleapi/transport/apikey.go | 38 + .../google.golang.org/api/googleapi/types.go | 202 + .../google.golang.org/api/internal/creds.go | 92 + .../api/internal/gensupport/buffer.go | 79 + .../api/internal/gensupport/doc.go | 10 + .../api/internal/gensupport/json.go | 211 + .../api/internal/gensupport/jsonfloat.go | 47 + .../api/internal/gensupport/media.go | 363 + .../api/internal/gensupport/params.go | 51 + .../api/internal/gensupport/resumable.go | 241 + .../api/internal/gensupport/send.go | 87 + vendor/google.golang.org/api/internal/pool.go | 51 + .../api/internal/service-account.json | 12 + .../api/internal/settings.go | 87 + .../internal/third_party/uritemplates/LICENSE | 27 + .../third_party/uritemplates/METADATA | 14 + .../third_party/uritemplates/uritemplates.go | 248 + .../third_party/uritemplates/utils.go | 17 + .../api/option/credentials_go19.go | 23 + .../api/option/credentials_notgo19.go | 22 + vendor/google.golang.org/api/option/option.go | 238 + .../api/transport/http/dial.go | 153 + .../api/transport/http/dial_appengine.go | 20 + .../http/internal/propagation/http.go | 86 + .../googleapis/rpc/status/status.pb.go | 37 +- vendor/modules.txt | 39 +- 156 files changed, 23461 insertions(+), 603 deletions(-) delete mode 100644 pkg/tsdb/stackdriver/ensure_default_project.go delete mode 100644 vendor/cloud.google.com/go/AUTHORS delete mode 100644 vendor/cloud.google.com/go/CONTRIBUTORS create mode 100644 vendor/github.com/googleapis/gax-go/v2/LICENSE create mode 100644 vendor/github.com/googleapis/gax-go/v2/call_option.go create mode 100644 vendor/github.com/googleapis/gax-go/v2/gax.go create mode 100644 vendor/github.com/googleapis/gax-go/v2/go.mod create mode 100644 vendor/github.com/googleapis/gax-go/v2/go.sum create mode 100644 vendor/github.com/googleapis/gax-go/v2/header.go create mode 100644 vendor/github.com/googleapis/gax-go/v2/invoke.go create mode 100644 vendor/github.com/hashicorp/golang-lru/LICENSE create mode 100644 vendor/github.com/hashicorp/golang-lru/simplelru/lru.go create mode 100644 vendor/github.com/hashicorp/golang-lru/simplelru/lru_interface.go create mode 100644 vendor/go.opencensus.io/.gitignore create mode 100644 vendor/go.opencensus.io/AUTHORS create mode 100644 vendor/go.opencensus.io/CONTRIBUTING.md create mode 100644 vendor/go.opencensus.io/Gopkg.lock create mode 100644 vendor/go.opencensus.io/Gopkg.toml create mode 100644 vendor/go.opencensus.io/LICENSE create mode 100644 vendor/go.opencensus.io/Makefile create mode 100644 vendor/go.opencensus.io/README.md create mode 100644 vendor/go.opencensus.io/go.mod create mode 100644 vendor/go.opencensus.io/go.sum create mode 100644 vendor/go.opencensus.io/internal/internal.go create mode 100644 vendor/go.opencensus.io/internal/sanitize.go create mode 100644 vendor/go.opencensus.io/internal/tagencoding/tagencoding.go create mode 100644 vendor/go.opencensus.io/internal/traceinternals.go create mode 100644 vendor/go.opencensus.io/metric/metricdata/doc.go create mode 100644 vendor/go.opencensus.io/metric/metricdata/exemplar.go create mode 100644 vendor/go.opencensus.io/metric/metricdata/label.go create mode 100644 vendor/go.opencensus.io/metric/metricdata/metric.go create mode 100644 vendor/go.opencensus.io/metric/metricdata/point.go create mode 100644 vendor/go.opencensus.io/metric/metricdata/type_string.go create mode 100644 vendor/go.opencensus.io/metric/metricdata/unit.go create mode 100644 vendor/go.opencensus.io/metric/metricproducer/manager.go create mode 100644 vendor/go.opencensus.io/metric/metricproducer/producer.go create mode 100644 vendor/go.opencensus.io/opencensus.go create mode 100644 vendor/go.opencensus.io/plugin/ochttp/client.go create mode 100644 vendor/go.opencensus.io/plugin/ochttp/client_stats.go create mode 100644 vendor/go.opencensus.io/plugin/ochttp/doc.go create mode 100644 vendor/go.opencensus.io/plugin/ochttp/propagation/b3/b3.go create mode 100644 vendor/go.opencensus.io/plugin/ochttp/route.go create mode 100644 vendor/go.opencensus.io/plugin/ochttp/server.go create mode 100644 vendor/go.opencensus.io/plugin/ochttp/span_annotating_client_trace.go create mode 100644 vendor/go.opencensus.io/plugin/ochttp/stats.go create mode 100644 vendor/go.opencensus.io/plugin/ochttp/trace.go create mode 100644 vendor/go.opencensus.io/plugin/ochttp/wrapped_body.go create mode 100644 vendor/go.opencensus.io/resource/resource.go create mode 100644 vendor/go.opencensus.io/stats/doc.go create mode 100644 vendor/go.opencensus.io/stats/internal/record.go create mode 100644 vendor/go.opencensus.io/stats/measure.go create mode 100644 vendor/go.opencensus.io/stats/measure_float64.go create mode 100644 vendor/go.opencensus.io/stats/measure_int64.go create mode 100644 vendor/go.opencensus.io/stats/record.go create mode 100644 vendor/go.opencensus.io/stats/units.go create mode 100644 vendor/go.opencensus.io/stats/view/aggregation.go create mode 100644 vendor/go.opencensus.io/stats/view/aggregation_data.go create mode 100644 vendor/go.opencensus.io/stats/view/collector.go create mode 100644 vendor/go.opencensus.io/stats/view/doc.go create mode 100644 vendor/go.opencensus.io/stats/view/export.go create mode 100644 vendor/go.opencensus.io/stats/view/view.go create mode 100644 vendor/go.opencensus.io/stats/view/view_to_metric.go create mode 100644 vendor/go.opencensus.io/stats/view/worker.go create mode 100644 vendor/go.opencensus.io/stats/view/worker_commands.go create mode 100644 vendor/go.opencensus.io/tag/context.go create mode 100644 vendor/go.opencensus.io/tag/doc.go create mode 100644 vendor/go.opencensus.io/tag/key.go create mode 100644 vendor/go.opencensus.io/tag/map.go create mode 100644 vendor/go.opencensus.io/tag/map_codec.go create mode 100644 vendor/go.opencensus.io/tag/metadata.go create mode 100644 vendor/go.opencensus.io/tag/profile_19.go create mode 100644 vendor/go.opencensus.io/tag/profile_not19.go create mode 100644 vendor/go.opencensus.io/tag/validate.go create mode 100644 vendor/go.opencensus.io/trace/basetypes.go create mode 100644 vendor/go.opencensus.io/trace/config.go create mode 100644 vendor/go.opencensus.io/trace/doc.go create mode 100644 vendor/go.opencensus.io/trace/evictedqueue.go create mode 100644 vendor/go.opencensus.io/trace/export.go create mode 100644 vendor/go.opencensus.io/trace/internal/internal.go create mode 100644 vendor/go.opencensus.io/trace/lrumap.go create mode 100644 vendor/go.opencensus.io/trace/propagation/propagation.go create mode 100644 vendor/go.opencensus.io/trace/sampling.go create mode 100644 vendor/go.opencensus.io/trace/spanbucket.go create mode 100644 vendor/go.opencensus.io/trace/spanstore.go create mode 100644 vendor/go.opencensus.io/trace/status_codes.go create mode 100644 vendor/go.opencensus.io/trace/trace.go create mode 100644 vendor/go.opencensus.io/trace/trace_go11.go create mode 100644 vendor/go.opencensus.io/trace/trace_nongo11.go create mode 100644 vendor/go.opencensus.io/trace/tracestate/tracestate.go create mode 100644 vendor/google.golang.org/api/AUTHORS create mode 100644 vendor/google.golang.org/api/CONTRIBUTORS create mode 100644 vendor/google.golang.org/api/LICENSE create mode 100644 vendor/google.golang.org/api/cloudresourcemanager/v1/cloudresourcemanager-api.json create mode 100644 vendor/google.golang.org/api/cloudresourcemanager/v1/cloudresourcemanager-gen.go create mode 100644 vendor/google.golang.org/api/googleapi/googleapi.go create mode 100644 vendor/google.golang.org/api/googleapi/transport/apikey.go create mode 100644 vendor/google.golang.org/api/googleapi/types.go create mode 100644 vendor/google.golang.org/api/internal/creds.go create mode 100644 vendor/google.golang.org/api/internal/gensupport/buffer.go create mode 100644 vendor/google.golang.org/api/internal/gensupport/doc.go create mode 100644 vendor/google.golang.org/api/internal/gensupport/json.go create mode 100644 vendor/google.golang.org/api/internal/gensupport/jsonfloat.go create mode 100644 vendor/google.golang.org/api/internal/gensupport/media.go create mode 100644 vendor/google.golang.org/api/internal/gensupport/params.go create mode 100644 vendor/google.golang.org/api/internal/gensupport/resumable.go create mode 100644 vendor/google.golang.org/api/internal/gensupport/send.go create mode 100644 vendor/google.golang.org/api/internal/pool.go create mode 100644 vendor/google.golang.org/api/internal/service-account.json create mode 100644 vendor/google.golang.org/api/internal/settings.go create mode 100644 vendor/google.golang.org/api/internal/third_party/uritemplates/LICENSE create mode 100644 vendor/google.golang.org/api/internal/third_party/uritemplates/METADATA create mode 100644 vendor/google.golang.org/api/internal/third_party/uritemplates/uritemplates.go create mode 100644 vendor/google.golang.org/api/internal/third_party/uritemplates/utils.go create mode 100644 vendor/google.golang.org/api/option/credentials_go19.go create mode 100644 vendor/google.golang.org/api/option/credentials_notgo19.go create mode 100644 vendor/google.golang.org/api/option/option.go create mode 100644 vendor/google.golang.org/api/transport/http/dial.go create mode 100644 vendor/google.golang.org/api/transport/http/dial_appengine.go create mode 100644 vendor/google.golang.org/api/transport/http/internal/propagation/http.go diff --git a/go.mod b/go.mod index adb28c4ae70..e2dd5de2231 100644 --- a/go.mod +++ b/go.mod @@ -71,10 +71,11 @@ require ( golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f // indirect golang.org/x/net v0.0.0-20190923162816-aa69164e4478 - golang.org/x/oauth2 v0.0.0-20190319182350-c85d3e98c914 + golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e golang.org/x/tools v0.0.0-20191213221258-04c2e8eff935 // indirect golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 + google.golang.org/api v0.14.0 google.golang.org/grpc v1.23.1 gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect diff --git a/go.sum b/go.sum index 5f7a6e32ba3..84a4cb63a18 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,8 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0 h1:ROfEUZz+Gh5pa62DJWXSaonyu3StP6EA6lPEXPI6mCo= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f h1:HR5nRmUQgXrwqZOwZ2DAc/aCi3Bu3xENpspW935vxu0= @@ -102,6 +104,7 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -110,13 +113,20 @@ github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/flatbuffers v1.11.0 h1:O7CEyB8Cb3/DmtxODGtLHcEvpr81Jm5qLg/hsHnxA2A= github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -139,6 +149,9 @@ github.com/hashicorp/go-plugin v1.0.1 h1:4OtAfUGbnKC6yS48p0CtMX2oFYtzFZVv6rok3cR github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0= github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ= @@ -158,6 +171,7 @@ github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= @@ -313,6 +327,8 @@ github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZ github.com/zenazn/goji v0.9.1-0.20160507202103-64eb34159fe5/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= +go.opencensus.io v0.21.0 h1:mU6zScU4U1YAFPHEHYk+3JC4SY7JxgkqS10ZOSyksNg= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.uber.org/atomic v1.5.1 h1:rsqfU5vBkVknbhUGbAUwQKR2H4ItV8tjJ+6kJX4cxHM= go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -325,8 +341,13 @@ golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392 h1:ACG4HJsFiNMf47Y4PeRoeb golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/image v0.0.0-20190507092727-e4e5bf290fec/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE= @@ -337,8 +358,10 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -347,15 +370,20 @@ golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190923162816-aa69164e4478 h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190319182350-c85d3e98c914 h1:jIOcLT9BZzyJ9ce+IwwZ+aF9yeCqzrR+NrD68a/SHKw= golang.org/x/oauth2 v0.0.0-20190319182350-c85d3e98c914/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -365,6 +393,7 @@ golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpbl golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa h1:KIDDMLT1O0Nr7TSxp8xM5tJcdn8tgyAONntO829og1M= golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -376,11 +405,17 @@ golang.org/x/sys v0.0.0-20191220142924-d4481acd189f h1:68K/z8GLUxV76xGSqwTWw2gyk golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190802220118-1d1727260058/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= @@ -393,15 +428,25 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+y golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.14.0 h1:uMf5uLi4eQMRrMKhCplNik4U4H8Z6C1br3zOtAa/aDE= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873 h1:nfPFGzJkUDX6uBmpN/pSw7MbOAWegH5QDQuoXFHedLg= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/grpc v1.14.0 h1:ArxJuB1NWfPY6r9Gp9gqwplT0Ge7nqv9msgu03lHLmo= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.23.1 h1:q4XQuHFC6I28BKZpo6IYyb3mNO+l7lSOxRuYTCiDfXk= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= @@ -440,4 +485,7 @@ gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/packages/grafana-ui/src/components/Segment/SegmentSelect.tsx b/packages/grafana-ui/src/components/Segment/SegmentSelect.tsx index fb25f9be893..e7421b583ec 100644 --- a/packages/grafana-ui/src/components/Segment/SegmentSelect.tsx +++ b/packages/grafana-ui/src/components/Segment/SegmentSelect.tsx @@ -37,7 +37,6 @@ export function SegmentSelect({ width: ${width > 120 ? width : 120}px; ` )} - noOptionsMessage={() => noOptionsMessage} placeholder="" autoFocus={true} isOpen={true} diff --git a/pkg/tsdb/stackdriver/ensure_default_project.go b/pkg/tsdb/stackdriver/ensure_default_project.go deleted file mode 100644 index 265fdda5151..00000000000 --- a/pkg/tsdb/stackdriver/ensure_default_project.go +++ /dev/null @@ -1,24 +0,0 @@ -package stackdriver - -import ( - "context" - - "github.com/grafana/grafana/pkg/components/simplejson" - "github.com/grafana/grafana/pkg/tsdb" -) - -func (e *StackdriverExecutor) ensureDefaultProject(ctx context.Context, tsdbQuery *tsdb.TsdbQuery) (*tsdb.Response, error) { - queryResult := &tsdb.QueryResult{Meta: simplejson.New(), RefId: tsdbQuery.Queries[0].RefId} - result := &tsdb.Response{ - Results: make(map[string]*tsdb.QueryResult), - } - defaultProject, err := e.getDefaultProject(ctx) - if err != nil { - return nil, err - } - - e.dsInfo.JsonData.Set("defaultProject", defaultProject) - queryResult.Meta.Set("defaultProject", defaultProject) - result.Results[tsdbQuery.Queries[0].RefId] = queryResult - return result, nil -} diff --git a/pkg/tsdb/stackdriver/stackdriver.go b/pkg/tsdb/stackdriver/stackdriver.go index 788627598d2..b90420e9f03 100644 --- a/pkg/tsdb/stackdriver/stackdriver.go +++ b/pkg/tsdb/stackdriver/stackdriver.go @@ -15,9 +15,6 @@ import ( "strings" "time" - "golang.org/x/net/context/ctxhttp" - "golang.org/x/oauth2/google" - "github.com/grafana/grafana/pkg/api/pluginproxy" "github.com/grafana/grafana/pkg/components/null" "github.com/grafana/grafana/pkg/components/simplejson" @@ -27,6 +24,8 @@ import ( "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/tsdb" "github.com/opentracing/opentracing-go" + "golang.org/x/net/context/ctxhttp" + "golang.org/x/oauth2/google" ) var ( @@ -81,8 +80,10 @@ func (e *StackdriverExecutor) Query(ctx context.Context, dsInfo *models.DataSour switch queryType { case "annotationQuery": result, err = e.executeAnnotationQuery(ctx, tsdbQuery) - case "ensureDefaultProjectQuery": - result, err = e.ensureDefaultProject(ctx, tsdbQuery) + case "getProjectsListQuery": + result, err = e.getProjectList(ctx, tsdbQuery) + case "getGCEDefaultProject": + result, err = e.getGCEDefaultProject(ctx, tsdbQuery) case "timeSeriesQuery": fallthrough default: @@ -92,19 +93,29 @@ func (e *StackdriverExecutor) Query(ctx context.Context, dsInfo *models.DataSour return result, err } -func (e *StackdriverExecutor) executeTimeSeriesQuery(ctx context.Context, tsdbQuery *tsdb.TsdbQuery) (*tsdb.Response, error) { +func (e *StackdriverExecutor) getGCEDefaultProject(ctx context.Context, tsdbQuery *tsdb.TsdbQuery) (*tsdb.Response, error) { result := &tsdb.Response{ Results: make(map[string]*tsdb.QueryResult), } + refId := tsdbQuery.Queries[0].RefId + queryResult := &tsdb.QueryResult{Meta: simplejson.New(), RefId: refId} - authenticationType := e.dsInfo.JsonData.Get("authenticationType").MustString(jwtAuthentication) - if authenticationType == gceAuthentication { - defaultProject, err := e.getDefaultProject(ctx) - if err != nil { - return nil, fmt.Errorf("Failed to retrieve default project from GCE metadata server. error: %v", err) - } + gceDefaultProject, err := e.getDefaultProject(ctx) + if err != nil { + slog.Debug("Stackdriver", "Auth", "Failed to use GCE auth: ", err) + return nil, fmt.Errorf("Failed to retrieve default project from GCE metadata server. error: %v", err) + } + slog.Debug("Stackdriver", "Auth", "Successfully use GCE auth: ", gceDefaultProject) - e.dsInfo.JsonData.Set("defaultProject", defaultProject) + queryResult.Meta.Set("defaultProject", gceDefaultProject) + result.Results[refId] = queryResult + + return result, nil +} + +func (e *StackdriverExecutor) executeTimeSeriesQuery(ctx context.Context, tsdbQuery *tsdb.TsdbQuery) (*tsdb.Response, error) { + result := &tsdb.Response{ + Results: make(map[string]*tsdb.QueryResult), } queries, err := e.buildQueries(tsdbQuery) @@ -170,11 +181,12 @@ func (e *StackdriverExecutor) buildQueries(tsdbQuery *tsdb.TsdbQuery) ([]*Stackd aliasBy := query.Model.Get("aliasBy").MustString() stackdriverQueries = append(stackdriverQueries, &StackdriverQuery{ - Target: target, - Params: params, - RefID: query.RefId, - GroupBys: groupBysAsStrings, - AliasBy: aliasBy, + Target: target, + Params: params, + RefID: query.RefId, + GroupBys: groupBysAsStrings, + AliasBy: aliasBy, + ProjectName: query.Model.Get("projectName").MustString(""), }) } @@ -278,8 +290,7 @@ func setAggParams(params *url.Values, query *tsdb.Query, durationSeconds int) { func (e *StackdriverExecutor) executeQuery(ctx context.Context, query *StackdriverQuery, tsdbQuery *tsdb.TsdbQuery) (*tsdb.QueryResult, StackdriverResponse, error) { queryResult := &tsdb.QueryResult{Meta: simplejson.New(), RefId: query.RefID} - - req, err := e.createRequest(ctx, e.dsInfo) + req, err := e.createRequest(ctx, e.dsInfo, query, fmt.Sprintf("stackdriver%s", "v3/projects/"+query.ProjectName+"/timeSeries")) if err != nil { queryResult.Error = err return queryResult, StackdriverResponse{}, nil @@ -350,6 +361,28 @@ func (e *StackdriverExecutor) unmarshalResponse(res *http.Response) (Stackdriver return data, nil } +func (e *StackdriverExecutor) unmarshalResourceResponse(res *http.Response) (ResourceManagerProjectList, error) { + body, err := ioutil.ReadAll(res.Body) + defer res.Body.Close() + if err != nil { + return ResourceManagerProjectList{}, err + } + + if res.StatusCode/100 != 2 { + slog.Error("Request failed", "status", res.Status, "body", string(body)) + return ResourceManagerProjectList{}, fmt.Errorf(string(body)) + } + + var data ResourceManagerProjectList + err = json.Unmarshal(body, &data) + if err != nil { + slog.Error("Failed to unmarshal Resource manager response", "error", err, "status", res.Status, "body", string(body)) + return ResourceManagerProjectList{}, err + } + + return data, nil +} + func (e *StackdriverExecutor) parseResponse(queryRes *tsdb.QueryResult, data StackdriverResponse, query *StackdriverQuery) error { labels := make(map[string]map[string]bool) @@ -584,7 +617,7 @@ func calcBucketBound(bucketOptions StackdriverBucketOptions, n int) string { return bucketBound } -func (e *StackdriverExecutor) createRequest(ctx context.Context, dsInfo *models.DataSource) (*http.Request, error) { +func (e *StackdriverExecutor) createRequest(ctx context.Context, dsInfo *models.DataSource, query *StackdriverQuery, proxyPass string) (*http.Request, error) { u, _ := url.Parse(dsInfo.Url) u.Path = path.Join(u.Path, "render") @@ -611,14 +644,44 @@ func (e *StackdriverExecutor) createRequest(ctx context.Context, dsInfo *models. } } - projectName := dsInfo.JsonData.Get("defaultProject").MustString() - proxyPass := fmt.Sprintf("stackdriver%s", "v3/projects/"+projectName+"/timeSeries") - pluginproxy.ApplyRoute(ctx, req, proxyPass, stackdriverRoute, dsInfo) return req, nil } +func (e *StackdriverExecutor) createRequestResourceManager(ctx context.Context, dsInfo *models.DataSource) (*http.Request, error) { + u, _ := url.Parse(dsInfo.Url) + u.Path = path.Join(u.Path, "render") + + req, err := http.NewRequest(http.MethodGet, "https://cloudresourcemanager.googleapis.com/", nil) + if err != nil { + slog.Error("Failed to create request", "error", err) + return nil, fmt.Errorf("Failed to create request. error: %v", err) + } + + req.Header.Set("Content-Type", "application/json") + req.Header.Set("User-Agent", fmt.Sprintf("Grafana/%s", setting.BuildVersion)) + + // find plugin + plugin, ok := plugins.DataSources[dsInfo.Type] + if !ok { + return nil, errors.New("Unable to find datasource plugin Stackdriver") + } + + var resourceManagerRoute *plugins.AppPluginRoute + for _, route := range plugin.Routes { + if route.Path == "cloudresourcemanager" { + resourceManagerRoute = route + break + } + } + proxyPass := "v1/projects" + + pluginproxy.ApplyRoute(ctx, req, proxyPass, resourceManagerRoute, dsInfo) + + return req, nil +} + func (e *StackdriverExecutor) getDefaultProject(ctx context.Context) (string, error) { authenticationType := e.dsInfo.JsonData.Get("authenticationType").MustString(jwtAuthentication) if authenticationType == gceAuthentication { @@ -626,7 +689,67 @@ func (e *StackdriverExecutor) getDefaultProject(ctx context.Context) (string, er if err != nil { return "", fmt.Errorf("Failed to retrieve default project from GCE metadata server. error: %v", err) } + token, err := defaultCredentials.TokenSource.Token() + if err != nil { + return "", fmt.Errorf("Failed to retrieve GCP credential token. error: %v", err) + } + if !token.Valid() { + return "", errors.New("Failed to validate GCP credentials") + } + return defaultCredentials.ProjectID, nil } return e.dsInfo.JsonData.Get("defaultProject").MustString(), nil } + +func (e *StackdriverExecutor) getProjectList(ctx context.Context, tsdbQuery *tsdb.TsdbQuery) (*tsdb.Response, error) { + queryResult := &tsdb.QueryResult{Meta: simplejson.New(), RefId: tsdbQuery.Queries[0].RefId} + result := &tsdb.Response{ + Results: make(map[string]*tsdb.QueryResult), + } + projectsList, err := e.getProjects(ctx) + if err != nil { + return nil, err + } + + queryResult.Meta.Set("projectsList", projectsList) + result.Results[tsdbQuery.Queries[0].RefId] = queryResult + return result, nil +} + +func (e *StackdriverExecutor) getProjects(ctx context.Context) ([]ResourceManagerProjectSelect, error) { + var projects []ResourceManagerProjectSelect + + req, err := e.createRequestResourceManager(ctx, e.dsInfo) + if err != nil { + return nil, err + } + + span, ctx := opentracing.StartSpanFromContext(ctx, "resource manager query") + span.SetTag("datasource_id", e.dsInfo.Id) + span.SetTag("org_id", e.dsInfo.OrgId) + + defer span.Finish() + + if err := opentracing.GlobalTracer().Inject( + span.Context(), + opentracing.HTTPHeaders, + opentracing.HTTPHeadersCarrier(req.Header)); err != nil { + return nil, err + } + + res, err := ctxhttp.Do(ctx, e.httpClient, req) + if err != nil { + return nil, err + } + + data, err := e.unmarshalResourceResponse(res) + if err != nil { + return nil, err + } + + for _, project := range data.Projects { + projects = append(projects, ResourceManagerProjectSelect{Label: project.ProjectID, Value: project.ProjectID}) + } + return projects, nil +} diff --git a/pkg/tsdb/stackdriver/types.go b/pkg/tsdb/stackdriver/types.go index a8a4661b597..bb177a0628f 100644 --- a/pkg/tsdb/stackdriver/types.go +++ b/pkg/tsdb/stackdriver/types.go @@ -5,72 +5,89 @@ import ( "time" ) -// StackdriverQuery is the query that Grafana sends from the frontend -type StackdriverQuery struct { - Target string - Params url.Values - RefID string - GroupBys []string - AliasBy string -} +type ( + // StackdriverQuery is the query that Grafana sends from the frontend + StackdriverQuery struct { + Target string + Params url.Values + RefID string + GroupBys []string + AliasBy string + ProjectName string + } -type StackdriverBucketOptions struct { - LinearBuckets *struct { - NumFiniteBuckets int64 `json:"numFiniteBuckets"` - Width int64 `json:"width"` - Offset int64 `json:"offset"` - } `json:"linearBuckets"` - ExponentialBuckets *struct { - NumFiniteBuckets int64 `json:"numFiniteBuckets"` - GrowthFactor float64 `json:"growthFactor"` - Scale float64 `json:"scale"` - } `json:"exponentialBuckets"` - ExplicitBuckets *struct { - Bounds []float64 `json:"bounds"` - } `json:"explicitBuckets"` -} + StackdriverBucketOptions struct { + LinearBuckets *struct { + NumFiniteBuckets int64 `json:"numFiniteBuckets"` + Width int64 `json:"width"` + Offset int64 `json:"offset"` + } `json:"linearBuckets"` + ExponentialBuckets *struct { + NumFiniteBuckets int64 `json:"numFiniteBuckets"` + GrowthFactor float64 `json:"growthFactor"` + Scale float64 `json:"scale"` + } `json:"exponentialBuckets"` + ExplicitBuckets *struct { + Bounds []float64 `json:"bounds"` + } `json:"explicitBuckets"` + } -// StackdriverResponse is the data returned from the external Google Stackdriver API -type StackdriverResponse struct { - TimeSeries []struct { - Metric struct { - Labels map[string]string `json:"labels"` - Type string `json:"type"` - } `json:"metric"` - Resource struct { - Type string `json:"type"` - Labels map[string]string `json:"labels"` - } `json:"resource"` - MetaData map[string]map[string]interface{} `json:"metadata"` - MetricKind string `json:"metricKind"` - ValueType string `json:"valueType"` - Points []struct { - Interval struct { - StartTime time.Time `json:"startTime"` - EndTime time.Time `json:"endTime"` - } `json:"interval"` - Value struct { - DoubleValue float64 `json:"doubleValue"` - StringValue string `json:"stringValue"` - BoolValue bool `json:"boolValue"` - IntValue string `json:"int64Value"` - DistributionValue struct { - Count string `json:"count"` - Mean float64 `json:"mean"` - SumOfSquaredDeviation float64 `json:"sumOfSquaredDeviation"` - Range struct { - Min int `json:"min"` - Max int `json:"max"` - } `json:"range"` - BucketOptions StackdriverBucketOptions `json:"bucketOptions"` - BucketCounts []string `json:"bucketCounts"` - Examplars []struct { - Value float64 `json:"value"` - Timestamp string `json:"timestamp"` - // attachments - } `json:"examplars"` - } `json:"distributionValue"` - } `json:"value"` - } `json:"points"` - } `json:"timeSeries"` -} + // StackdriverResponse is the data returned from the external Google Stackdriver API + StackdriverResponse struct { + TimeSeries []struct { + Metric struct { + Labels map[string]string `json:"labels"` + Type string `json:"type"` + } `json:"metric"` + Resource struct { + Type string `json:"type"` + Labels map[string]string `json:"labels"` + } `json:"resource"` + MetaData map[string]map[string]interface{} `json:"metadata"` + MetricKind string `json:"metricKind"` + ValueType string `json:"valueType"` + Points []struct { + Interval struct { + StartTime time.Time `json:"startTime"` + EndTime time.Time `json:"endTime"` + } `json:"interval"` + Value struct { + DoubleValue float64 `json:"doubleValue"` + StringValue string `json:"stringValue"` + BoolValue bool `json:"boolValue"` + IntValue string `json:"int64Value"` + DistributionValue struct { + Count string `json:"count"` + Mean float64 `json:"mean"` + SumOfSquaredDeviation float64 `json:"sumOfSquaredDeviation"` + Range struct { + Min int `json:"min"` + Max int `json:"max"` + } `json:"range"` + BucketOptions StackdriverBucketOptions `json:"bucketOptions"` + BucketCounts []string `json:"bucketCounts"` + Examplars []struct { + Value float64 `json:"value"` + Timestamp string `json:"timestamp"` + // attachments + } `json:"examplars"` + } `json:"distributionValue"` + } `json:"value"` + } `json:"points"` + } `json:"timeSeries"` + } + + // ResourceManagerProjectList is the data returned from the external Google Resource Manager API + ResourceManagerProjectList struct { + Projects []ResourceManagerProject `json:"projects"` + } + + ResourceManagerProject struct { + ProjectID string `json:"projectId"` + } + + ResourceManagerProjectSelect struct { + Label string `json:"label"` + Value string `json:"value"` + } +) diff --git a/public/app/core/components/Select/MetricSelect.tsx b/public/app/core/components/Select/MetricSelect.tsx index 77247907c01..7522a7c5818 100644 --- a/public/app/core/components/Select/MetricSelect.tsx +++ b/public/app/core/components/Select/MetricSelect.tsx @@ -70,7 +70,6 @@ export class MetricSelect extends React.Component { const { placeholder, className, isSearchable, onChange } = this.props; const { options } = this.state; const selectedOption = this.getSelectedOption(); - return ( +export function Project({ projectName, datasource, onChange, templateVariableOptions }: Props) { + return ( +
+ Project + onChange(value!)} + loadOptions={() => + datasource.getProjects().then(projects => [ + { + label: 'Template Variables', + options: templateVariableOptions, + }, + ...projects, + ]) + } + value={projectName} + placeholder="Select Project" + /> +
+
- ); - } +
+ ); } diff --git a/public/app/plugins/datasource/stackdriver/components/QueryEditor.test.tsx b/public/app/plugins/datasource/stackdriver/components/QueryEditor.test.tsx index 1b5ed6f1096..c7a75dadbac 100644 --- a/public/app/plugins/datasource/stackdriver/components/QueryEditor.test.tsx +++ b/public/app/plugins/datasource/stackdriver/components/QueryEditor.test.tsx @@ -1,6 +1,6 @@ import React from 'react'; import renderer from 'react-test-renderer'; -import { QueryEditor, Props, DefaultTarget } from './QueryEditor'; +import { DefaultTarget, Props, QueryEditor } from './QueryEditor'; import { TemplateSrv } from 'app/features/templating/template_srv'; const props: Props = { @@ -9,7 +9,8 @@ const props: Props = { target: DefaultTarget, events: { on: () => {} }, datasource: { - getDefaultProject: () => Promise.resolve('project'), + getProjects: () => Promise.resolve([]), + getDefaultProject: () => Promise.resolve('projectName'), getMetricTypes: () => Promise.resolve([]), getLabels: () => Promise.resolve([]), variables: [], diff --git a/public/app/plugins/datasource/stackdriver/components/QueryEditor.tsx b/public/app/plugins/datasource/stackdriver/components/QueryEditor.tsx index a9fc6f63b68..0ce4ad77fd2 100644 --- a/public/app/plugins/datasource/stackdriver/components/QueryEditor.tsx +++ b/public/app/plugins/datasource/stackdriver/components/QueryEditor.tsx @@ -1,14 +1,12 @@ import React from 'react'; -import _ from 'lodash'; import { TemplateSrv } from 'app/features/templating/template_srv'; -import { Aggregations, Metrics, Filters, GroupBys, Alignments, AlignmentPeriods, AliasBy, Help } from './'; +import { Project, Aggregations, Metrics, Filters, GroupBys, Alignments, AlignmentPeriods, AliasBy, Help } from './'; import { StackdriverQuery, MetricDescriptor } from '../types'; import { getAlignmentPickerData, toOption } from '../functions'; import StackdriverDatasource from '../datasource'; -import { TimeSeries, SelectableValue } from '@grafana/data'; -import { PanelEvents } from '@grafana/data'; +import { PanelEvents, SelectableValue, TimeSeries } from '@grafana/data'; export interface Props { onQueryChange: (target: StackdriverQuery) => void; @@ -30,7 +28,7 @@ interface State extends StackdriverQuery { } export const DefaultTarget: State = { - defaultProject: 'loading project...', + projectName: '', metricType: '', metricKind: '', valueType: '', @@ -58,23 +56,34 @@ export class QueryEditor extends React.Component { async componentDidMount() { const { events, target, templateSrv, datasource } = this.props; + if (!target.projectName) { + target.projectName = datasource.getDefaultProject(); + } + events.on(PanelEvents.dataReceived, this.onDataReceived.bind(this)); events.on(PanelEvents.dataError, this.onDataError.bind(this)); + const { perSeriesAligner, alignOptions } = getAlignmentPickerData(target, templateSrv); const variableOptionGroup = { label: 'Template Variables', expanded: false, options: datasource.variables.map(toOption), }; - this.setState({ + + const state: Partial = { ...this.props.target, + projectName: target.projectName, alignOptions, perSeriesAligner, variableOptionGroup, variableOptions: variableOptionGroup.options, - }); + }; - datasource.getLabels(target.metricType, target.refId, target.groupBys).then(labels => this.setState({ labels })); + this.setState(state); + + datasource + .getLabels(target.metricType, target.refId, target.projectName, target.groupBys) + .then(labels => this.setState({ labels })); } componentWillUnmount() { @@ -118,7 +127,7 @@ export class QueryEditor extends React.Component { { valueType, metricKind, perSeriesAligner: this.state.perSeriesAligner }, templateSrv ); - const labels = await this.props.datasource.getLabels(type, target.refId, target.groupBys); + const labels = await this.props.datasource.getLabels(type, target.refId, this.state.projectName, target.groupBys); this.setState( { alignOptions, @@ -131,7 +140,9 @@ export class QueryEditor extends React.Component { }, () => { onQueryChange(this.state); - onExecuteQuery(); + if (this.state.projectName !== null) { + onExecuteQuery(); + } } ); }; @@ -142,24 +153,28 @@ export class QueryEditor extends React.Component { this.props.onQueryChange(this.state); this.props.onExecuteQuery(); }); - datasource.getLabels(target.metricType, target.refId, value).then(labels => this.setState({ labels })); + datasource + .getLabels(target.metricType, target.refId, this.state.projectName, value) + .then(labels => this.setState({ labels })); } - onPropertyChange(prop: string, value: string[]) { + onPropertyChange(prop: string, value: any) { this.setState({ [prop]: value }, () => { this.props.onQueryChange(this.state); - this.props.onExecuteQuery(); + if (this.state.projectName !== null) { + this.props.onExecuteQuery(); + } }); } render() { const { + groupBys = [], + filters = [], usedAlignmentPeriod, - defaultProject, + projectName, metricType, crossSeriesReducer, - groupBys, - filters, perSeriesAligner, alignOptions, alignmentPeriod, @@ -169,14 +184,24 @@ export class QueryEditor extends React.Component { labels, variableOptionGroup, variableOptions, + refId, } = this.state; const { datasource, templateSrv } = this.props; return ( <> + { + this.onPropertyChange('projectName', value); + datasource.getLabels(metricType, refId, value, groupBys).then(labels => this.setState({ labels })); + }} + /> { onChange={value => this.onPropertyChange('alignmentPeriod', value)} /> this.onPropertyChange('aliasBy', value)} /> - + )} diff --git a/public/app/plugins/datasource/stackdriver/components/SimpleSelect.tsx b/public/app/plugins/datasource/stackdriver/components/SimpleSelect.tsx index 6e2c4e2f3c8..7770aee0e7b 100644 --- a/public/app/plugins/datasource/stackdriver/components/SimpleSelect.tsx +++ b/public/app/plugins/datasource/stackdriver/components/SimpleSelect.tsx @@ -2,7 +2,7 @@ import React, { ChangeEvent, FC } from 'react'; interface Props { onValueChange: (e: ChangeEvent) => void; - options: any[]; + options: Array<{ value: string; name: string }>; value: string; label: string; } diff --git a/public/app/plugins/datasource/stackdriver/components/VariableQueryEditor.test.tsx b/public/app/plugins/datasource/stackdriver/components/VariableQueryEditor.test.tsx index 38614007651..da2f4a2d8e7 100644 --- a/public/app/plugins/datasource/stackdriver/components/VariableQueryEditor.test.tsx +++ b/public/app/plugins/datasource/stackdriver/components/VariableQueryEditor.test.tsx @@ -14,6 +14,8 @@ const props: VariableQueryProps = { onChange: (query, definition) => {}, query: {}, datasource: { + getDefaultProject: () => '', + getProjects: async (): Promise => [], getMetricTypes: async (p: any): Promise => [], }, templateSrv: { replace: (s: string) => s, variables: [] }, @@ -28,7 +30,7 @@ describe('VariableQueryEditor', () => { describe('and a new variable is created', () => { it('should trigger a query using the first query type in the array', done => { props.onChange = (query, definition) => { - expect(definition).toBe('Stackdriver - Services'); + expect(definition).toBe('Stackdriver - Projects'); done(); }; renderer.create().toJSON(); diff --git a/public/app/plugins/datasource/stackdriver/components/VariableQueryEditor.tsx b/public/app/plugins/datasource/stackdriver/components/VariableQueryEditor.tsx index 9d368395554..c05bfb5c617 100644 --- a/public/app/plugins/datasource/stackdriver/components/VariableQueryEditor.tsx +++ b/public/app/plugins/datasource/stackdriver/components/VariableQueryEditor.tsx @@ -1,4 +1,4 @@ -import React, { ChangeEvent, PureComponent } from 'react'; +import React, { PureComponent } from 'react'; import { VariableQueryProps } from 'app/types/plugins'; import { SimpleSelect } from './'; import { getMetricTypes, getLabelKeys, extractServicesFromMetricDescriptors } from '../functions'; @@ -6,6 +6,7 @@ import { MetricFindQueryTypes, VariableQueryData } from '../types'; export class StackdriverVariableQueryEditor extends PureComponent { queryTypes: Array<{ value: string; name: string }> = [ + { value: MetricFindQueryTypes.Projects, name: 'Projects' }, { value: MetricFindQueryTypes.Services, name: 'Services' }, { value: MetricFindQueryTypes.MetricTypes, name: 'Metric Types' }, { value: MetricFindQueryTypes.LabelKeys, name: 'Label Keys' }, @@ -25,15 +26,24 @@ export class StackdriverVariableQueryEditor extends PureComponent ({ value: m.service, name: m.serviceShortName, @@ -52,48 +62,66 @@ export class StackdriverVariableQueryEditor extends PureComponent ({ value, name: label })), + ...(await this.getLabels(selectedMetricType, this.state.projectName)), }; this.setState(state); } - async onQueryTypeChange(event: ChangeEvent) { + async onQueryTypeChange(queryType: string) { const state: any = { - selectedQueryType: event.target.value, - ...(await this.getLabels(this.state.selectedMetricType, event.target.value)), + selectedQueryType: queryType, + ...(await this.getLabels(this.state.selectedMetricType, this.state.projectName, queryType)), }; this.setState(state); } - async onServiceChange(event: ChangeEvent) { + async onProjectChange(projectName: string) { + const metricDescriptors = await this.props.datasource.getMetricTypes(projectName); + const labels = await this.getLabels(this.state.selectedMetricType, projectName); + const { metricTypes, selectedMetricType } = getMetricTypes( + metricDescriptors, + this.state.selectedMetricType, + this.props.templateSrv.replace(this.state.selectedMetricType), + this.props.templateSrv.replace(this.state.selectedService) + ); + + this.setState({ ...labels, metricTypes, selectedMetricType, metricDescriptors, projectName }); + } + + async onServiceChange(service: string) { const { metricTypes, selectedMetricType } = getMetricTypes( this.state.metricDescriptors, this.state.selectedMetricType, this.props.templateSrv.replace(this.state.selectedMetricType), - this.props.templateSrv.replace(event.target.value) + this.props.templateSrv.replace(service) ); const state: any = { - selectedService: event.target.value, + selectedService: service, metricTypes, selectedMetricType, - ...(await this.getLabels(selectedMetricType)), + ...(await this.getLabels(selectedMetricType, this.state.projectName)), }; this.setState(state); } - async onMetricTypeChange(event: ChangeEvent) { - const state: any = { selectedMetricType: event.target.value, ...(await this.getLabels(event.target.value)) }; + async onMetricTypeChange(metricType: string) { + const state: any = { + selectedMetricType: metricType, + ...(await this.getLabels(metricType, this.state.projectName)), + }; this.setState(state); } - onLabelKeyChange(event: ChangeEvent) { - this.setState({ labelKey: event.target.value }); + onLabelKeyChange(labelKey: string) { + this.setState({ labelKey }); } componentDidUpdate() { @@ -102,10 +130,10 @@ export class StackdriverVariableQueryEditor extends PureComponent l === this.props.templateSrv.replace(this.state.labelKey)) ? this.state.labelKey : labels[0]; @@ -126,35 +154,49 @@ export class StackdriverVariableQueryEditor extends PureComponent this.onServiceChange(e)} - label="Service" - /> + <> + this.onProjectChange(e.target.value)} + label="Project" + /> + this.onServiceChange(e.target.value)} + label="Service" + /> + ); case MetricFindQueryTypes.LabelKeys: case MetricFindQueryTypes.LabelValues: case MetricFindQueryTypes.ResourceTypes: return ( <> + this.onProjectChange(e.target.value)} + label="Project" + /> this.onServiceChange(e)} + onValueChange={e => this.onServiceChange(e.target.value)} label="Service" /> this.onMetricTypeChange(e)} + onValueChange={e => this.onMetricTypeChange(e.target.value)} label="Metric Type" /> {queryType === MetricFindQueryTypes.LabelValues && ( ({ value: l, name: l })))} - onValueChange={e => this.onLabelKeyChange(e)} + onValueChange={e => this.onLabelKeyChange(e.target.value)} label="Label Key" /> )} @@ -167,13 +209,13 @@ export class StackdriverVariableQueryEditor extends PureComponent this.onServiceChange(e)} + onValueChange={e => this.onServiceChange(e.target.value)} label="Service" /> this.onMetricTypeChange(e)} + onValueChange={e => this.onMetricTypeChange(e.target.value)} label="Metric Type" /> @@ -189,7 +231,7 @@ export class StackdriverVariableQueryEditor extends PureComponent this.onQueryTypeChange(e)} + onValueChange={e => this.onQueryTypeChange(e.target.value)} label="Query Type" /> {this.renderQueryTypeSwitch(this.state.selectedQueryType)} diff --git a/public/app/plugins/datasource/stackdriver/components/__snapshots__/QueryEditor.test.tsx.snap b/public/app/plugins/datasource/stackdriver/components/__snapshots__/QueryEditor.test.tsx.snap index 62e1476709c..e6eeee7acf2 100644 --- a/public/app/plugins/datasource/stackdriver/components/__snapshots__/QueryEditor.test.tsx.snap +++ b/public/app/plugins/datasource/stackdriver/components/__snapshots__/QueryEditor.test.tsx.snap @@ -2,6 +2,32 @@ exports[`QueryEditor renders correctly 1`] = ` Array [ +
+ + Project + + +
+
+
+
,
@@ -194,29 +220,6 @@ Array [
-
- - Project - -
- -
-
+