Browse Source

stackdriver: only load default project from backend if it's not available on the target. this might happen when using gce authentication and provisioning

Erik Sundell 7 years ago
parent
commit
09fb1760a1

+ 33 - 45
public/app/plugins/datasource/stackdriver/datasource.ts

@@ -6,6 +6,7 @@ export default class StackdriverDatasource {
   url: string;
   baseUrl: string;
   projectName: string;
+  queryPromise: Promise<any>;
 
   /** @ngInject */
   constructor(instanceSettings, private backendSrv, private templateSrv, private timeSrv) {
@@ -99,31 +100,34 @@ export default class StackdriverDatasource {
   }
 
   async query(options) {
-    const result = [];
-    const data = await this.getTimeSeries(options);
-    if (data.results) {
-      Object['values'](data.results).forEach(queryRes => {
-        if (!queryRes.series) {
-          return;
-        }
-
-        const unit = this.resolvePanelUnitFromTargets(options.targets);
-        queryRes.series.forEach(series => {
-          let timeSerie: any = {
-            target: series.name,
-            datapoints: series.points,
-            refId: queryRes.refId,
-            meta: queryRes.meta,
-          };
-          if (unit) {
-            timeSerie = { ...timeSerie, unit };
+    this.queryPromise = new Promise(async resolve => {
+      const result = [];
+      const data = await this.getTimeSeries(options);
+      if (data.results) {
+        Object['values'](data.results).forEach(queryRes => {
+          if (!queryRes.series) {
+            return;
           }
-          result.push(timeSerie);
+          this.projectName = queryRes.meta.defaultProject;
+          const unit = this.resolvePanelUnitFromTargets(options.targets);
+          queryRes.series.forEach(series => {
+            let timeSerie: any = {
+              target: series.name,
+              datapoints: series.points,
+              refId: queryRes.refId,
+              meta: queryRes.meta,
+            };
+            if (unit) {
+              timeSerie = { ...timeSerie, unit };
+            }
+            result.push(timeSerie);
+          });
         });
-      });
-    }
+      }
 
-    return { data: result };
+      resolve({ data: result });
+    });
+    return this.queryPromise;
   }
 
   async annotationQuery(options) {
@@ -181,9 +185,9 @@ export default class StackdriverDatasource {
         data: {
           queries: [
             {
-              refId: 'metricDescriptors',
+              refId: 'testDatasource',
               datasourceId: this.id,
-              type: 'metricDescriptors',
+              type: 'testDatasource',
             },
           ],
         },
@@ -215,27 +219,10 @@ export default class StackdriverDatasource {
     }
   }
 
-  async getProjects() {
-    const response = await this.doRequest(`/cloudresourcemanager/v1/projects`);
-    return response.data.projects.map(p => ({ id: p.projectId, name: p.name }));
-  }
-
   async getDefaultProject() {
     try {
-      if (this.projectName) {
-        return {
-          id: this.projectName,
-          name: this.projectName,
-        };
-      } else {
-        const projects = await this.getProjects();
-        if (projects && projects.length > 0) {
-          const test = projects.filter(p => p.id === this.projectName)[0];
-          return test;
-        } else {
-          throw new Error('No projects found');
-        }
-      }
+      await this.queryPromise;
+      return this.projectName;
     } catch (error) {
       let message = 'Projects cannot be fetched: ';
       message += error.statusText ? error.statusText + ': ' : '';
@@ -252,12 +239,13 @@ export default class StackdriverDatasource {
         message += 'Cannot connect to Stackdriver API';
       }
       appEvents.emit('ds-request-error', message);
+      return '';
     }
   }
 
-  async getMetricTypes(projectId: string) {
+  async getMetricTypes(projectName: string) {
     try {
-      const metricsApiPath = `v3/projects/${projectId}/metricDescriptors`;
+      const metricsApiPath = `v3/projects/${projectName}/metricDescriptors`;
       const { data } = await this.doRequest(`${this.baseUrl}${metricsApiPath}`);
 
       const metrics = data.metricDescriptors.map(m => {

+ 3 - 4
public/app/plugins/datasource/stackdriver/partials/query.editor.html

@@ -15,8 +15,7 @@
   <div class="gf-form-inline">
     <div class="gf-form">
       <span class="gf-form-label width-9">Project</span>
-      <input class="gf-form-input" disabled type="text" ng-model='ctrl.target.project.name' get-options="ctrl.getProjects()"
-        css-class="min-width-12" />
+      <input class="gf-form-input" disabled type="text" ng-model='ctrl.target.defaultProject' css-class="min-width-12" />
     </div>
     <div class="gf-form">
       <label class="gf-form-label query-keyword" ng-click="ctrl.showHelp = !ctrl.showHelp">
@@ -40,8 +39,8 @@
   <div class="gf-form" ng-show="ctrl.showLastQuery">
     <pre class="gf-form-pre">{{ctrl.lastQueryMeta.rawQueryString}}</pre>
   </div>
-  <div class="grafana-info-box m-t-2 markdown-html" ng-show="ctrl.showHelp">
-    <h5>Alias Patterns</h5>
+  <div class="gf-form grafana-info-box" style="padding: 0" ng-show="ctrl.showHelp">
+    <pre class="gf-form-pre alert alert-info" style="margin-right: 0"><h5>Alias Patterns</h5>Format the legend keys any way you want by using alias patterns.
 
     Format the legend keys any way you want by using alias patterns.<br /> <br />
 

+ 2 - 8
public/app/plugins/datasource/stackdriver/query_ctrl.ts

@@ -14,10 +14,7 @@ export interface QueryMeta {
 export class StackdriverQueryCtrl extends QueryCtrl {
   static templateUrl = 'partials/query.editor.html';
   target: {
-    project: {
-      id: string;
-      name: string;
-    };
+    defaultProject: string;
     unit: string;
     metricType: string;
     service: string;
@@ -38,10 +35,7 @@ export class StackdriverQueryCtrl extends QueryCtrl {
   defaultServiceValue = 'All Services';
 
   defaults = {
-    project: {
-      id: 'default',
-      name: 'loading project...',
-    },
+    defaultProject: 'loading project...',
     metricType: this.defaultDropdownValue,
     service: this.defaultServiceValue,
     metric: '',

+ 8 - 3
public/app/plugins/datasource/stackdriver/query_filter_ctrl.ts

@@ -79,12 +79,17 @@ export class StackdriverFilterCtrl {
   }
 
   async getCurrentProject() {
-    this.target.project = await this.datasource.getDefaultProject();
+    return new Promise(async resolve => {
+      if (!this.target.defaultProject || this.target.defaultProject === 'loading project...') {
+        this.target.defaultProject = await this.datasource.getDefaultProject();
+      }
+      resolve(this.target.defaultProject);
+    });
   }
 
   async loadMetricDescriptors() {
-    if (this.target.project.id !== 'default') {
-      this.metricDescriptors = await this.datasource.getMetricTypes(this.target.project.id);
+    if (this.target.defaultProject !== 'loading project...') {
+      this.metricDescriptors = await this.datasource.getMetricTypes(this.target.defaultProject);
       this.services = this.getServicesList();
       this.metrics = this.getMetricsList();
       return this.metricDescriptors;