mirror of
https://github.com/grafana/grafana.git
synced 2026-08-18 00:54:58 -05:00
stackdriver: ux for config page, docs updated
This commit is contained in:
@@ -12,7 +12,7 @@ weight = 11
|
|||||||
|
|
||||||
# Using Google Stackdriver in Grafana
|
# Using Google Stackdriver in Grafana
|
||||||
|
|
||||||
Grafana ships with built in support for Google Stackdriver. You just have to add it as a datasource and you will be ready to build dashboards for your Stackdriver metrics.
|
Grafana ships with built-in support for Google Stackdriver. You just have to add it as a datasource and you will be ready to build dashboards for your Stackdriver metrics.
|
||||||
|
|
||||||
## Adding the data source to Grafana
|
## Adding the data source to Grafana
|
||||||
|
|
||||||
@@ -56,11 +56,14 @@ Click on the links above and click the `Enable` button:
|
|||||||
3. On the `Create service account key` page, choose key type `JSON`. Then in the `Service Account` dropdown, choose the `New service account` option:
|
3. On the `Create service account key` page, choose key type `JSON`. Then in the `Service Account` dropdown, choose the `New service account` option:
|
||||||
|
|
||||||

|

|
||||||
4. Some new fields will appear. Fill in a name for the service account in the `Service account name` field and then choose the Monitoring Viewer role from the `Role` dropdown:
|
4. Some new fields will appear. Fill in a name for the service account in the `Service account name` field and then choose the `Monitoring Viewer` role from the `Role` dropdown:
|
||||||
|
|
||||||

|

|
||||||
5. Click the Create button. A Json Web Token (JWT) file will be created and downloaded to your computer. Store this file in a secure place as it allows access to your Stackdriver data.
|
5. Click the Create button. A Json Web Token (JWT) file will be created and downloaded to your computer. Store this file in a secure place as it allows access to your Stackdriver data.
|
||||||
6. Upload it to Grafana on the datasource Configuration page.
|
6. Upload it to Grafana on the datasource Configuration page. You can either upload the file or paste in the contents of the file.
|
||||||
|

|
||||||
|
7. The file contents will be encrypted and saved in the Grafana database. Don't forget to save after uploading the file!
|
||||||
|

|
||||||
|
|
||||||
## Metric Query Editor
|
## Metric Query Editor
|
||||||
|
|
||||||
|
|||||||
@@ -5,25 +5,20 @@ export class StackdriverConfigCtrl {
|
|||||||
jsonText: string;
|
jsonText: string;
|
||||||
validationErrors: string[] = [];
|
validationErrors: string[] = [];
|
||||||
inputDataValid: boolean;
|
inputDataValid: boolean;
|
||||||
defaultProject: string;
|
|
||||||
projectsError: string;
|
|
||||||
projects: any[];
|
|
||||||
loadingProjects: boolean;
|
|
||||||
|
|
||||||
/** @ngInject */
|
/** @ngInject */
|
||||||
constructor(private $scope, datasourceSrv) {
|
constructor(datasourceSrv) {
|
||||||
this.datasourceSrv = datasourceSrv;
|
this.datasourceSrv = datasourceSrv;
|
||||||
this.current.jsonData = this.current.jsonData || {};
|
this.current.jsonData = this.current.jsonData || {};
|
||||||
this.current.secureJsonData = this.current.secureJsonData || {};
|
this.current.secureJsonData = this.current.secureJsonData || {};
|
||||||
this.current.secureJsonFields = this.current.secureJsonFields || {};
|
this.current.secureJsonFields = this.current.secureJsonFields || {};
|
||||||
this.defaultProject = this.current.jsonData.defaultProject;
|
|
||||||
this.projects = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
save(jwt) {
|
save(jwt) {
|
||||||
this.current.secureJsonData.privateKey = jwt.private_key;
|
this.current.secureJsonData.privateKey = jwt.private_key;
|
||||||
this.current.jsonData.tokenUri = jwt.token_uri;
|
this.current.jsonData.tokenUri = jwt.token_uri;
|
||||||
this.current.jsonData.clientEmail = jwt.client_email;
|
this.current.jsonData.clientEmail = jwt.client_email;
|
||||||
|
this.current.jsonData.defaultProject = jwt.project_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
validateJwt(jwt) {
|
validateJwt(jwt) {
|
||||||
@@ -43,16 +38,15 @@ export class StackdriverConfigCtrl {
|
|||||||
if (this.validationErrors.length === 0) {
|
if (this.validationErrors.length === 0) {
|
||||||
this.inputDataValid = true;
|
this.inputDataValid = true;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
onUpload(json) {
|
onUpload(json) {
|
||||||
this.jsonText = '';
|
this.jsonText = '';
|
||||||
if (this.validateJwt(json)) {
|
if (this.validateJwt(json)) {
|
||||||
this.save(json);
|
this.save(json);
|
||||||
this.displayProjects();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +55,6 @@ export class StackdriverConfigCtrl {
|
|||||||
const json = JSON.parse(e.originalEvent.clipboardData.getData('text/plain') || this.jsonText);
|
const json = JSON.parse(e.originalEvent.clipboardData.getData('text/plain') || this.jsonText);
|
||||||
if (this.validateJwt(json)) {
|
if (this.validateJwt(json)) {
|
||||||
this.save(json);
|
this.save(json);
|
||||||
this.displayProjects();
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.resetValidationMessages();
|
this.resetValidationMessages();
|
||||||
@@ -73,44 +66,9 @@ export class StackdriverConfigCtrl {
|
|||||||
this.validationErrors = [];
|
this.validationErrors = [];
|
||||||
this.inputDataValid = false;
|
this.inputDataValid = false;
|
||||||
this.jsonText = '';
|
this.jsonText = '';
|
||||||
this.loadingProjects = false;
|
|
||||||
this.projectsError = '';
|
|
||||||
|
|
||||||
this.current.jsonData = {};
|
this.current.jsonData = {};
|
||||||
this.current.secureJsonData = {};
|
this.current.secureJsonData = {};
|
||||||
this.current.secureJsonFields = {};
|
this.current.secureJsonFields = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
async displayProjects() {
|
|
||||||
if (this.projects.length === 0) {
|
|
||||||
try {
|
|
||||||
this.loadingProjects = true;
|
|
||||||
const ds = await this.datasourceSrv.loadDatasource(this.current.name);
|
|
||||||
this.projects = await ds.getProjects();
|
|
||||||
this.$scope.$apply(() => {
|
|
||||||
if (this.projects.length > 0) {
|
|
||||||
this.current.jsonData.defaultProject = this.current.jsonData.defaultProject || this.projects[0].id;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
let message = 'Projects cannot be fetched: ';
|
|
||||||
message += error.statusText ? error.statusText + ': ' : '';
|
|
||||||
if (error && error.data && error.data.error && error.data.error.message) {
|
|
||||||
if (error.data.error.code === 403) {
|
|
||||||
message += `
|
|
||||||
A list of projects could not be fetched from the Google Cloud Resource Manager API.
|
|
||||||
You might need to enable it first:
|
|
||||||
https://console.developers.google.com/apis/library/cloudresourcemanager.googleapis.com`;
|
|
||||||
} else {
|
|
||||||
message += error.data.error.code + '. ' + error.data.error.message;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
message += 'Cannot connect to Stackdriver API';
|
|
||||||
}
|
|
||||||
this.$scope.$apply(() => (this.projectsError = message));
|
|
||||||
} finally {
|
|
||||||
this.$scope.$apply(() => (this.loadingProjects = false));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,59 +1,84 @@
|
|||||||
<div ng-if="!ctrl.current.jsonData.clientEmail && !ctrl.inputDataValid">
|
<div class="gf-form-group">
|
||||||
<div class="gf-form-group" ng-if="!ctrl.inputDataValid">
|
<div class="grafana-info-box">
|
||||||
<div class="gf-form">
|
<h5>GCP Service Account</h5>
|
||||||
<form>
|
<p>
|
||||||
<dash-upload on-upload="ctrl.onUpload(dash)"></dash-upload>
|
To authenticate with the Stackdriver API, you need to create a Google Cloud Platform (GCP) Service Account for
|
||||||
</form>
|
the Project you want to show data for. A Grafana datasource integrates with one GCP Project. If you want to
|
||||||
</div>
|
visualize data from multiple GCP Projects then you need to create one datasource per GCP Project.
|
||||||
</div>
|
</p>
|
||||||
<div class="gf-form-group">
|
<p>
|
||||||
<h5 class="section-heading" ng-if="!ctrl.inputDataValid">Or paste JSON</h5>
|
The <strong>Monitoring Viewer</strong> role provides all the permissions that Grafana needs.
|
||||||
<div class="gf-form" ng-if="!ctrl.inputDataValid">
|
</p>
|
||||||
<textarea rows="10" data-share-panel-url="" class="gf-form-input" ng-model="ctrl.jsonText" ng-paste="ctrl.onPasteJwt($event)"></textarea>
|
<p>
|
||||||
</div>
|
The following APIs need to be enabled on GCP for the datasource to work:
|
||||||
<div ng-repeat="valError in ctrl.validationErrors" class="text-error p-l-1">
|
<ul>
|
||||||
<i class="fa fa-warning"></i>
|
<li><a class="external-link" target="_blank" href="https://console.cloud.google.com/apis/library/monitoring.googleapis.com">Monitoring
|
||||||
{{valError}}
|
API</a></li>
|
||||||
</div>
|
<li><a class="external-link" target="_blank" href="https://console.cloud.google.com/apis/library/cloudresourcemanager.googleapis.com">Resource
|
||||||
</div>
|
Manager API</a></li>
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
<p>Detailed instructions on how to create a Service Account can be found <a class="external-link" target="_blank"
|
||||||
|
href="http://docs.grafana.org/datasources/stackdriver/">in
|
||||||
|
the documentation.</a></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="gf-form-group">
|
||||||
|
<div class="gf-form">
|
||||||
|
<h3>Service Account Authentication</h3>
|
||||||
|
<info-popover mode="header">Upload your Service Account key file or paste in the contents of the file. The file
|
||||||
|
contents will be encrypted and saved in the Grafana database.</info-popover>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div ng-if="!ctrl.current.jsonData.clientEmail && !ctrl.inputDataValid">
|
||||||
|
<div class="gf-form-group" ng-if="!ctrl.inputDataValid">
|
||||||
|
<div class="gf-form">
|
||||||
|
<form>
|
||||||
|
<dash-upload on-upload="ctrl.onUpload(dash)" btn-text="Upload Service Account key file"></dash-upload>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="gf-form-group">
|
||||||
|
<h5 class="section-heading" ng-if="!ctrl.inputDataValid">Or paste Service Account key JSON</h5>
|
||||||
|
<div class="gf-form" ng-if="!ctrl.inputDataValid">
|
||||||
|
<textarea rows="10" data-share-panel-url="" class="gf-form-input" ng-model="ctrl.jsonText" ng-paste="ctrl.onPasteJwt($event)"></textarea>
|
||||||
|
</div>
|
||||||
|
<div ng-repeat="valError in ctrl.validationErrors" class="text-error p-l-1">
|
||||||
|
<i class="fa fa-warning"></i>
|
||||||
|
{{valError}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="gf-form-group" ng-if="ctrl.inputDataValid || ctrl.current.jsonData.clientEmail">
|
<div class="gf-form-group" ng-if="ctrl.inputDataValid || ctrl.current.jsonData.clientEmail">
|
||||||
<div class="gf-form-inline">
|
<h6>Uploaded Key Details</h6>
|
||||||
<div class="gf-form">
|
|
||||||
<span class="gf-form-label width-9">Token URI</span>
|
|
||||||
<input class="gf-form-input width-30" disabled type="text" ng-model='ctrl.current.jsonData.tokenUri' />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="gf-form-inline">
|
|
||||||
<div class="gf-form">
|
|
||||||
<span class="gf-form-label width-9">Client Email</span>
|
|
||||||
<input class="gf-form-input width-30" disabled type="text" ng-model="ctrl.current.jsonData.clientEmail" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="gf-form" ng-if="ctrl.current.secureJsonFields.privateKey">
|
|
||||||
<span class="gf-form-label width-9">Private Key</span>
|
|
||||||
<input type="text" class="gf-form-input max-width-12" disabled="disabled" value="configured">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<div class="gf-form">
|
||||||
|
<span class="gf-form-label width-9">Project</span>
|
||||||
|
<input class="gf-form-input width-40" disabled type="text" ng-model="ctrl.current.jsonData.defaultProject" />
|
||||||
|
</div>
|
||||||
|
<div class="gf-form">
|
||||||
|
<span class="gf-form-label width-9">Client Email</span>
|
||||||
|
<input class="gf-form-input width-40" disabled type="text" ng-model="ctrl.current.jsonData.clientEmail" />
|
||||||
|
</div>
|
||||||
|
<div class="gf-form">
|
||||||
|
<span class="gf-form-label width-9">Token URI</span>
|
||||||
|
<input class="gf-form-input width-40" disabled type="text" ng-model='ctrl.current.jsonData.tokenUri' />
|
||||||
|
</div>
|
||||||
|
<div class="gf-form" ng-if="ctrl.current.secureJsonFields.privateKey">
|
||||||
|
<span class="gf-form-label width-9">Private Key</span>
|
||||||
|
<input type="text" class="gf-form-input max-width-12" disabled="disabled" value="configured">
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="gf-form">
|
<div class="gf-form width-18">
|
||||||
<a class="btn btn-secondary gf-form-btn" href="#" ng-click="ctrl.resetValidationMessages()">Reset form</a>
|
<a class="btn btn-secondary gf-form-btn" href="#" ng-click="ctrl.resetValidationMessages()">Reset Service
|
||||||
</div>
|
Account Key </a>
|
||||||
<br />
|
<info-popover mode="right-normal">
|
||||||
<div class="gf-form">
|
Reset to clear the uploaded key and upload a new file.
|
||||||
<span class="gf-form-label width-10">Default Project</span>
|
</info-popover>
|
||||||
<div class="gf-form-select-wrapper max-width-23">
|
</div>
|
||||||
<select class="gf-form-input" ng-model="ctrl.current.jsonData.defaultProject" ng-options="p.id as p.name for p in ctrl.projects"
|
|
||||||
ng-change="ctrl.userChangedDefaultProject()"></select>
|
|
||||||
</div>
|
|
||||||
<div ng-if="ctrl.loadingProjects">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
<em>Fetching projects...…</em>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div ng-if="ctrl.projectsError" class="text-error p-l-1">
|
|
||||||
<i class="fa fa-warning"></i>
|
|
||||||
{{ctrl.projectsError}}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<p class="gf-form-label" ng-hide="ctrl.current.secureJsonFields.privateKey"><i class="fa fa-save"></i> Do not forget to save your changes after uploading a file.</p>
|
||||||
|
|||||||
Reference in New Issue
Block a user