You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by nc...@apache.org on 2016/02/05 22:56:29 UTC
[14/40] ambari git commit: AMBARI-14893. Add Grafana-based Ambari
Metrics Dashboard Builder. (Prajwal Rao via yusaku)
AMBARI-14893. Add Grafana-based Ambari Metrics Dashboard Builder. (Prajwal Rao via yusaku)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/8ff0b5ed
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/8ff0b5ed
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/8ff0b5ed
Branch: refs/heads/branch-dev-patch-upgrade
Commit: 8ff0b5ed82784a202978017345348d0d130b64af
Parents: d0bec5c
Author: Yusaku Sako <yu...@hortonworks.com>
Authored: Thu Feb 4 11:05:37 2016 -0800
Committer: Yusaku Sako <yu...@hortonworks.com>
Committed: Thu Feb 4 11:05:37 2016 -0800
----------------------------------------------------------------------
ambari-metrics/ambari-metrics-grafana/README.md | 243 +++++++++++++++
.../ambari-metrics/datasource.js | 304 +++++++++++++++++++
.../ambari-metrics/directives.js | 36 +++
.../ambari-metrics/partials/config.html | 19 ++
.../ambari-metrics/partials/query.editor.html | 133 ++++++++
.../ambari-metrics/partials/query.options.html | 42 +++
.../ambari-metrics/plugin.json | 14 +
.../ambari-metrics/queryCtrl.js | 131 ++++++++
ambari-metrics/pom.xml | 1 +
9 files changed, 923 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/8ff0b5ed/ambari-metrics/ambari-metrics-grafana/README.md
----------------------------------------------------------------------
diff --git a/ambari-metrics/ambari-metrics-grafana/README.md b/ambari-metrics/ambari-metrics-grafana/README.md
new file mode 100644
index 0000000..0a138e8
--- /dev/null
+++ b/ambari-metrics/ambari-metrics-grafana/README.md
@@ -0,0 +1,243 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+# AMS (Ambari Metrics Service) Datasource Plugin for Grafana
+
+Use **ambari-metrics** to visualize metrics exposed via AMS in Grafana.
+
+### If you already have Ambari Metrics UI as a part of your AMS Install, [go here](#createdash) to get started
+
+
+**ToC**
+ - [Install Grafana](#installg)
+ - [Install Datasource Plugin](#installam)
+ - [Access Grafana](#accessgraf)
+ - [Add Datasource to Grafana](#addds)
+ - [Test Datasource](#testds)
+ - [Create Dashboard](#createdash)
+ - [Add a Graph](#addgraph)
+ - [Save Dashboard](#savedash)
+ - [Time Ranges](#timerange)
+ - [Edit Panel/Graph](#editpanel)
+
+
+----------
+![enter image description here](screenshots/full-dashboard.png)
+
+----------
+<a name="installg"></a>
+### Install Grafana
+
+
+You can install Grafana on any host. It does not need to be co-located with Ambari Metrics Collector. The only requirement is that it has network access to Ambari Metrics Collector.
+
+**Install on CentOS/Red Hat:**
+```
+sudo yum install https://grafanarel.s3.amazonaws.com/builds/grafana-2.6.0-1.x86_64.rpm
+```
+
+**Install on Ubuntu/Debian:**
+```
+wget https://grafanarel.s3.amazonaws.com/builds/grafana_2.6.0_amd64.deb
+sudo apt-get install -y adduser libfontconfig
+sudo dpkg -i grafana_2.6.0_amd64.deb
+```
+
+**Install on SUSE/SLES:**
+```
+sudo rpm -i --nodeps grafana-2.6.0-1.x86_64.rpm
+```
+<a name="installam"></a>
+### Deploy ambari-metrics
+
+**On your Grafana Server**
+
+```
+cp -R ambari/ambari-metrics/ambari-metrics-grafana/ambari-metrics /usr/share/grafana/public/app/plugins/datasource
+```
+
+### Start Grafana
+
+```
+sudo service grafana-server start
+```
+
+<a name="accessgraf"></a>
+### Access Grafana
+
+```
+http://GRAFANA_HOST:3000
+```
+
+---
+
+<a name="addds"></a>
+## Add Ambari Metrics Datasource in Grafana UI
+
+**Add a Datasource**
+> - Click on "Datasources"
+> - Click on "Add New" at the top
+
+![add-datasource](screenshots/1-add-datasource.png)
+
+**Add a Datasource (continued)**
+
+> 1. Name of your Datasource
+> 2. Type = AmbariMetrics
+> 3. Host+Port of your AMS installation. (usually host:6188)
+> - No trailing slashes
+> - Nothing else needs to be changed
+> - Click on Save.
+
+![datasource-details](screenshots/2-datasource-details.png)
+
+
+<a name="testds"></a>
+**Test your Datasource**
+
+> To make sure it's all working, click on **Test Connection** and you should see a message that says "Data source is working".
+
+
+![test-datasource](screenshots/3-test-datasource.png)
+
+---
+
+<a name="createdash"></a>
+## Creating a Dashboard
+
+**To create a dashboard**
+
+> - Click on Dashboards on the left
+> - Click on "Home"
+> - Click on New at the bottom of the dropdown
+
+![Dashboard Dropdown](screenshots/4-dashboard-dropdown.png)
+
+
+
+**To add a panel to your newly created dashboard**
+
+> - Click on the green button on the left(see image below)
+> - This will expand a flyout menu that will allow you to add a panel
+> - Choose Graph / Table / Single Stat
+
+![Add Panel](screenshots/5-dashboard-graph-menu.png)
+
+![Types of Panels](screenshots/6-graph-panels.png)
+
+
+---
+
+<a name="addgraph"></a>
+**To add a Graph**
+
+
+> - Choose the Datasource you created earlier
+> - Once you've chosen the datasource, you should see the query editor show you some options
+
+![Add a Graph](screenshots/7-choose-datasource.png)
+
+
+
+> - Choose the component you wish to see metrics for
+
+![Add a Graph](screenshots/8-choose-component.png)
+
+
+
+> - Based on the component chosen, you should now see a list of metrics for it
+
+![Add a Graph](screenshots/9-choose-metric.png)
+
+
+
+> - Choose hostname from the list of hosts if you wish to see metrics for a specific host.
+> - if hostname isn't chosen, metrics will be shown on a service component level.
+
+![Add a Graph](screenshots/10-choose-hostname.png)
+
+
+> - By default the aggregator is avg. You can change it via the dropdown
+> - You can choose to enable Rate by selecting the checkbox.
+> - You can specify precision by checking the box and then selecting "days, hours, minutes or seconds"
+
+![Select Options](screenshots/11-choose-agg-rate-precision.png)
+
+
+**To change the title of the Panel**
+
+> - Click on the "General" tab
+> - Enter the name to change the title of the panel
+
+![Change Panel Title](screenshots/12-change-panel-title.png)
+
+**To change the Units for your metric**
+
+> - You can edit the units of your graph by clicking on **Axes & Grid** tab and clicking on "unit" as shown.
+
+![Change Units](screenshots/15-change-units.png)
+
+**To customise your graphs**
+
+> - You can customise your graph by clicking on the **Display Styles** tab.
+> - For ex: you can change the color of a specific metric by choosing a series specific override at the bottom.
+
+![series specific override](screenshots/17-series-specific-override.png)
+
+
+<a name="savedash"></a>
+**To Save the Dashboard**
+
+> - Click on the save icon next to the dashboard list dropdown on the top to save your dashboard.
+
+![Save Dashboard](screenshots/13-save-dashboard.png)
+
+<a name="editpanel"></a>
+**To Edit a Graph**
+
+> - Click on the title of your graph/panel and click on edit.
+
+![Edit Graph](screenshots/19-edit-graph.png)
+
+
+---
+<a name="timerange"></a>
+### Time Ranges
+
+**To change the Time Range**
+
+> - To change the timerange click on the top right of your UI.
+> - This setting affects all your graphs inside the dashboard. If you wish to customise time for a specific graph [look here](#timeshift)
+> - You can use the quick ranges provided or choose a time range of your choice. You can also choose a refresh duration for your dashboard or leave it at "off" to manually refresh.
+
+![Timerange](screenshots/14-change-timerange.png)
+
+<a name="timeshift"></a>
+**To change the time range of one graph only**
+
+> - Use this in case you wish to change the time range for a specific graph without affecting the other graphs in your dashboard
+> - Click on the **Time Range** tab of your Graph
+> - You can then enter a value in the "Override Relative time" input box
+> - You will be able to confirm that this change has occured by looking at the top right of your graph which will show the override message.
+> - You can choose to hide this message if you wish to do so (by checking the "hide time override info")
+
+![Timerange Override](screenshots/18-override-time.png)
+
+
+---
+
+
http://git-wip-us.apache.org/repos/asf/ambari/blob/8ff0b5ed/ambari-metrics/ambari-metrics-grafana/ambari-metrics/datasource.js
----------------------------------------------------------------------
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/datasource.js b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/datasource.js
new file mode 100644
index 0000000..374501c
--- /dev/null
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/datasource.js
@@ -0,0 +1,304 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+define([
+ 'angular',
+ 'lodash',
+ 'jquery',
+ './directives',
+ './queryCtrl'
+ ],
+ function (angular, _) {
+ 'use strict';
+
+ var module = angular.module('grafana.services');
+
+ module.factory('AmbariMetricsDatasource', function ($q, backendSrv) {
+ /**
+ * AMS Datasource Constructor
+ */
+ function AmbariMetricsDatasource(datasource) {
+ this.name = datasource.name;
+ this.url = datasource.url;
+ this.initMetricAppidMapping();
+ }
+ var allMetrics = [];
+ var appIds = [];
+ AmbariMetricsDatasource.prototype.initMetricAppidMapping = function () {
+ backendSrv.get(this.url + '/ws/v1/timeline/metrics/metadata')
+ .then(function (items) {
+ allMetrics = [];
+ appIds = [];
+ var fake = "timeline_metric_store_watcher"; delete items[fake];
+ for (var key in items) {
+ if (items.hasOwnProperty(key)) {
+ items[key].forEach(function (_item) {
+ allMetrics.push({
+ metric: _item.metricname,
+ app: key
+ });
+ });
+ }
+ appIds = _.keys(items);
+ }
+ });
+ };
+
+ /**
+ * AMS Datasource Authentication
+ */
+ AmbariMetricsDatasource.prototype.doAmbariRequest = function (options) {
+ if (this.basicAuth || this.withCredentials) {
+ options.withCredentials = true;
+ }
+ if (this.basicAuth) {
+ options.headers = options.headers || {};
+ options.headers.Authorization = this.basicAuth;
+ }
+
+ options.url = this.url + options.url;
+ options.inspect = {type: 'discovery'};
+
+ return backendSrv.datasourceRequest(options);
+ };
+
+ /**
+ * AMS Datasource Query
+ */
+ AmbariMetricsDatasource.prototype.query = function (options) {
+ var emptyData = function (metric) {
+ return {
+ data: {
+ target: metric,
+ datapoints: []
+ }
+ };
+ };
+ var self = this;
+ var getMetricsData = function (target) {
+ return function (res) {
+ console.log('processing metric ' + target.metric);
+ if (!res.metrics[0] || target.hide) {
+ return $q.when(emptyData(target.metric));
+ }
+ var series = [];
+ var metricData = res.metrics[0].metrics;
+ var timeSeries = {};
+ if (target.hosts === undefined || target.hosts.trim() === "") {
+ timeSeries = {
+ target: target.metric,
+ datapoints: []
+ };
+ } else {
+ timeSeries = {
+ target: target.metric + ' on ' + target.hosts,
+ datapoints: []
+ };
+ }
+ for (var k in metricData){
+ if (metricData.hasOwnProperty(k)) {
+ timeSeries.datapoints.push([metricData[k], (k - k % 1000)]);
+ }
+ }
+ series.push(timeSeries);
+ return $q.when({data: series});
+ };
+
+ };
+ var precisionSetting = '';
+ var getHostAppIdData = function(target) {
+ if (target.shouldAddPrecision) {
+ precisionSetting = '&precision=' + target.precision;
+ } else {
+ precisionSetting = '';
+ }
+ if (target.shouldAddPrecision && target.shouldComputeRate) {
+ return backendSrv.get(self.url + '/ws/v1/timeline/metrics?metricNames=' + target.metric + "._rate._"
+ + target.aggregator + "&hostname=" + target.hosts + '&appId=' + target.app + '&startTime=' + from
+ + '&endTime=' + to + precisionSetting).then(
+ getMetricsData(target)
+ );
+ } else if (target.shouldComputeRate) {
+ return backendSrv.get(self.url + '/ws/v1/timeline/metrics?metricNames=' + target.metric + "._rate._"
+ + target.aggregator + "&hostname=" + target.hosts + '&appId=' + target.app + '&startTime=' + from
+ + '&endTime=' + to).then(
+ getMetricsData(target)
+ );
+ } else if (target.shouldAddPrecision){
+ return backendSrv.get(self.url + '/ws/v1/timeline/metrics?metricNames=' + target.metric + "._"
+ + target.aggregator + "&hostname=" + target.hosts + '&appId=' + target.app + '&startTime=' + from
+ + '&endTime=' + to + precisionSetting).then(
+ getMetricsData(target)
+ );
+ } else {
+ return backendSrv.get(self.url + '/ws/v1/timeline/metrics?metricNames=' + target.metric + "._"
+ + target.aggregator + "&hostname=" + target.hosts + '&appId=' + target.app + '&startTime=' + from
+ + '&endTime=' + to).then(
+ getMetricsData(target)
+ );
+ }
+ };
+
+ var getServiceAppIdData = function(target) {
+ if (target.shouldAddPrecision) { precisionSetting = '&precision=' + target.precision;
+ } else { precisionSetting = ''; }
+ if (target.shouldAddPrecision && target.shouldComputeRate) {
+ return backendSrv.get(self.url + '/ws/v1/timeline/metrics?metricNames=' + target.metric + "._rate._"
+ + target.aggregator + '&appId=' + target.app + '&startTime=' + from + '&endTime=' + to + precisionSetting)
+ .then(
+ getMetricsData(target)
+ );
+ } else if (target.shouldAddPrecision) {
+ return backendSrv.get(self.url + '/ws/v1/timeline/metrics?metricNames=' + target.metric + "._"
+ + target.aggregator + '&appId=' + target.app + '&startTime=' + from + '&endTime=' + to + precisionSetting)
+ .then(
+ getMetricsData(target)
+ );
+ } else if (target.shouldComputeRate) {
+ return backendSrv.get(self.url + '/ws/v1/timeline/metrics?metricNames=' + target.metric + "._rate._"
+ + target.aggregator + '&appId=' + target.app + '&startTime=' + from + '&endTime=' + to).then(
+ getMetricsData(target)
+ );
+ } else {
+ return backendSrv.get(self.url + '/ws/v1/timeline/metrics?metricNames=' + target.metric + "._"
+ + target.aggregator + '&appId=' + target.app + '&startTime=' + from + '&endTime=' + to).then(
+ getMetricsData(target)
+ );
+ }
+ };
+
+ // Time Ranges
+ var from = Math.floor(options.range.from.valueOf() / 1000);
+ var to = Math.floor(options.range.to.valueOf() / 1000);
+
+ var metricsPromises = _.map(options.targets, function(target) {
+ console.debug('target app=' + target.app + ',' +
+ 'target metric=' + target.metric + ' on host=' + target.hosts);
+ if (!!target.hosts) {
+ return getHostAppIdData(target);
+ } else {
+ return getServiceAppIdData(target);
+ }
+ });
+ return $q.all(metricsPromises).then(function(metricsDataArray) {
+ var data = _.map(metricsDataArray, function(metricsData) {
+ return metricsData.data;
+ });
+ var metricsDataResult = {data: _.flatten(data)};
+ return $q.when(metricsDataResult);
+ });
+ };
+
+ /**
+ * AMS Datasource List Series.
+ */
+ AmbariMetricsDatasource.prototype.listSeries = function (query) {
+ // wrap in regex
+ if (query && query.length > 0 && query[0] !== '/') {
+ query = '/' + query + '/';
+ }
+ return $q.when([]);
+ };
+
+ /**
+ * AMS Datasource - Test Data Source Connection.
+ *
+ * Added Check to see if Datasource is working. Throws up an error in the
+ * Datasources page if incorrect info is passed on.
+ */
+ AmbariMetricsDatasource.prototype.testDatasource = function () {
+ return backendSrv.datasourceRequest({
+ url: this.url + '/ws/v1/timeline/metrics/metadata',
+ method: 'GET'
+ }).then(function(response) {
+ console.log(response);
+ if (response.status === 200) {
+ return { status: "success", message: "Data source is working", title: "Success" };
+ }
+ });
+ };
+
+ /**
+ * AMS Datasource - Suggest AppId.
+ *
+ * Read AppIds from cache.
+ */
+ AmbariMetricsDatasource.prototype.suggestApps = function (query) {
+ console.log(query);
+
+ appIds = appIds.sort();
+ var appId = _.map(appIds, function (k) {
+ return {text: k};
+ });
+ return $q.when(appId);
+ };
+
+ /**
+ * AMS Datasource - Suggest Metrics.
+ *
+ * Read Metrics based on AppId chosen.
+ */
+ AmbariMetricsDatasource.prototype.suggestMetrics = function (query, app) {
+ if (!app) {
+ return $q.when([]);
+ }
+ var metrics = allMetrics.filter(function(item) {
+ return (item.app === app);
+ });
+ var keys = [];
+ _.forEach(metrics, function (k) { keys.push(k.metric); });
+ keys = _.map(keys,function(m) {
+ return {text: m};
+ });
+ keys = _.sortBy(keys, function (i) { return i.text.toLowerCase(); });
+ return $q.when(keys);
+ };
+
+ /**
+ * AMS Datasource - Suggest Hosts.
+ *
+ * Query Hosts on the cluster.
+ */
+ AmbariMetricsDatasource.prototype.suggestHosts = function (query) {
+ console.log(query);
+ return this.doAmbariRequest({method: 'GET', url: '/ws/v1/timeline/metrics/hosts'})
+ .then(function (results) {
+ var fake = "fakehostname"; delete results.data[fake];
+ return _.map(Object.keys(results.data), function (hostName) {
+ return {text: hostName};
+ });
+ });
+ };
+
+ /**
+ * AMS Datasource Aggregators.
+ */
+ var aggregatorsPromise = null;
+ AmbariMetricsDatasource.prototype.getAggregators = function () {
+ if (aggregatorsPromise) {
+ return aggregatorsPromise;
+ }
+ aggregatorsPromise = $q.when([
+ 'avg', 'sum', 'min', 'max'
+ ]);
+ return aggregatorsPromise;
+ };
+
+ return AmbariMetricsDatasource;
+ });
+ }
+);
http://git-wip-us.apache.org/repos/asf/ambari/blob/8ff0b5ed/ambari-metrics/ambari-metrics-grafana/ambari-metrics/directives.js
----------------------------------------------------------------------
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/directives.js b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/directives.js
new file mode 100644
index 0000000..aade7d7
--- /dev/null
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/directives.js
@@ -0,0 +1,36 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ define([
+ 'angular',
+],
+function (angular) {
+ 'use strict';
+ var module = angular.module('grafana.directives');
+
+ module.directive('metricQueryEditorAmbarimetrics', function() {
+ return {
+ controller: 'AmbariMetricsQueryCtrl',
+ templateUrl: 'app/plugins/datasource/ambari-metrics/partials/query.editor.html',
+ };
+ });
+
+ module.directive('metricQueryOptionsAmbarimetrics', function() {
+ return {templateUrl: 'app/plugins/datasource/ambari-metrics/partials/query.options.html'};
+ });
+
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/8ff0b5ed/ambari-metrics/ambari-metrics-grafana/ambari-metrics/partials/config.html
----------------------------------------------------------------------
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/partials/config.html b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/partials/config.html
new file mode 100644
index 0000000..360c15c
--- /dev/null
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/partials/config.html
@@ -0,0 +1,19 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<div ng-include="httpConfigPartialSrc"></div>
+<br>
http://git-wip-us.apache.org/repos/asf/ambari/blob/8ff0b5ed/ambari-metrics/ambari-metrics-grafana/ambari-metrics/partials/query.editor.html
----------------------------------------------------------------------
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/partials/query.editor.html b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/partials/query.editor.html
new file mode 100644
index 0000000..d4dffb4
--- /dev/null
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/partials/query.editor.html
@@ -0,0 +1,133 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<div class="tight-form">
+ <ul class="tight-form-list pull-right">
+ <li class="tight-form-item small" ng-show="target.datasource">
+ <em>{{target.datasource}}</em>
+ </li>
+ <li class="tight-form-item">
+ <div class="dropdown">
+ <a class="pointer dropdown-toggle" data-toggle="dropdown" tabindex="1">
+ <i class="fa fa-bars"></i>
+ </a>
+ <ul class="dropdown-menu pull-right" role="menu">
+ <li role="menuitem"><a tabindex="1" ng-click="toggleQueryMode()">Switch editor mode</a></li>
+ <li role="menuitem"><a tabindex="1" ng-click="duplicateDataQuery(target)">Duplicate</a></li>
+ <li role="menuitem"><a tabindex="1" ng-click="moveDataQuery($index, $index-1)">Move up</a></li>
+ <li role="menuitem"><a tabindex="1" ng-click="moveDataQuery($index, $index+1)">Move down</a></li>
+ </ul>
+ </div>
+ </li>
+ <li class="tight-form-item last">
+ <a class="pointer" tabindex="1" ng-click="removeDataQuery(target)">
+ <i class="fa fa-remove"></i>
+ </a>
+ </li>
+ </ul>
+
+ <ul class="tight-form-list">
+ <li class="tight-form-item" style="min-width: 15px; text-align: center">
+ {{target.refId}}
+ </li>
+ <li>
+ <a class="tight-form-item"
+ ng-click="target.hide = !target.hide; get_data();"
+ role="menuitem">
+ <i class="fa fa-eye"></i>
+ </a>
+ </li>
+ </ul>
+
+ <ul class="tight-form-list" role="menu">
+
+ <li class="tight-form-item" style="width: 86px">
+ Component
+ </li>
+ <li>
+ <input type="text" class="input-large tight-form-input" ng-model="target.app"
+ spellcheck='false' bs-typeahead="suggestApps" placeholder="Component Name" data-min-length=0 data-items=100
+ ng-blur="targetBlur()">
+ </input>
+ <a bs-tooltip="target.errors.metric" style="color: rgb(229, 189, 28)" ng-show="target.errors.metric">
+ <i class="fa fa-warning"></i>
+ </a>
+ </li>
+
+ <li class="tight-form-item" style="width: 86px">
+ Metric
+ </li>
+ <li>
+ <input type="text" class="input-large tight-form-input" ng-model="target.metric"
+ spellcheck='false' bs-typeahead="suggestMetrics" placeholder="metric name" data-min-length=0 data-items=100
+ ng-blur="targetBlur()">
+ </input>
+ <a bs-tooltip="target.errors.metric" style="color: rgb(229, 189, 28)" ng-show="target.errors.metric">
+ <i class="fa fa-warning"></i>
+ </a>
+ </li>
+
+
+ <li class="tight-form-item" style="width: 86px">
+ Hosts <a bs-tooltip="'if host is selected, aggregator is ignored.'" data-placement="bottom"><i class="fa fa-info-circle"></i></a>
+ </li>
+ <li>
+ <input type="text" class="input-large tight-form-input" ng-model="target.hosts"
+ spellcheck='false' bs-typeahead="suggestHosts" placeholder="host name" data-min-length=0 data-items=100
+ ng-blur="targetBlur()">
+ </input>
+ <a bs-tooltip="target.errors.metric" style="color: rgb(229, 189, 28)" ng-show="target.errors.metric">
+ <i class="fa fa-warning"></i>
+ </a>
+ </li>
+
+
+
+ <li class="tight-form-item">
+ Aggregator
+ </li>
+ <li>
+ <select ng-model="target.aggregator" class="tight-form-input input-small"
+ ng-options="agg for agg in aggregators"
+ ng-change="targetBlur()">
+ </select>
+ <a bs-tooltip="target.errors.aggregator" style="color: rgb(229, 189, 28)" ng-show="target.errors.aggregator">
+ <i class="fa fa-warning"></i>
+ </a>
+ </li>
+ </ul>
+
+ <div class="clearfix"></div>
+</div>
+
+<div class="tight-form">
+ <ul class="tight-form-list" role="menu">
+ <li class="tight-form-item tight-form-align" style="width: 86px">
+ <editor-checkbox text="Rate" model="target.shouldComputeRate" change="targetBlur()"></editor-checkbox>
+ </li>
+
+ <li class="tight-form-item tight-form-align">
+ <editor-checkbox text="Precision" model="target.shouldAddPrecision" change="targetBlur()"></editor-checkbox>
+ </li>
+ <li ng-show="target.shouldAddPrecision">
+ <select ng-model="target.precision" class="tight-form-input input-small"
+ ng-options="precision for precision in precisions"
+ ng-change="targetBlur()">
+ </select>
+ </li>
+ <div class="clearfix"></div>
+</div>
http://git-wip-us.apache.org/repos/asf/ambari/blob/8ff0b5ed/ambari-metrics/ambari-metrics-grafana/ambari-metrics/partials/query.options.html
----------------------------------------------------------------------
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/partials/query.options.html b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/partials/query.options.html
new file mode 100644
index 0000000..e58ca64
--- /dev/null
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/partials/query.options.html
@@ -0,0 +1,42 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<section class="grafana-metric-options">
+ <div class="tight-form last">
+ <ul class="tight-form-list">
+ <li class="tight-form-item tight-form-item-icon">
+ <i class="fa fa-info-circle"></i>
+ </li>
+ <li class="tight-form-item">
+ <a ng-click="toggleEditorHelp(1);" bs-tooltip="'click to show helpful info'" data-placement="bottom">
+ Single Stats
+ </a>
+ </li>
+ </ul>
+ <div class="clearfix"></div>
+ </div>
+</section>
+
+<div class="editor-row">
+ <div class="pull-left" style="margin-top: 30px;">
+ <div class="grafana-info-box span6" ng-if="editorHelpIndex === 1">
+ <h5>Single Stats</h5>
+ <blockquote>To get the current value of the metric selected, Click on the <strong>Options</strong> tab above
+ and set the <strong>Big Value's</strong> value to <strong>"current"</strong>.</blockquote>
+ </div>
+ </div>
+</div>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/8ff0b5ed/ambari-metrics/ambari-metrics-grafana/ambari-metrics/plugin.json
----------------------------------------------------------------------
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/plugin.json b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/plugin.json
new file mode 100644
index 0000000..5226ae7
--- /dev/null
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/plugin.json
@@ -0,0 +1,14 @@
+{
+ "pluginType": "datasource",
+ "name": "AmbariMetrics",
+
+ "type": "ambarimetrics",
+ "serviceName": "AmbariMetricsDatasource",
+
+ "module": "app/plugins/datasource/ambari-metrics/datasource",
+ "partials": {
+ "config": "app/plugins/datasource/ambari-metrics/partials/config.html"
+ },
+
+ "metrics": true
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/8ff0b5ed/ambari-metrics/ambari-metrics-grafana/ambari-metrics/queryCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/queryCtrl.js b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/queryCtrl.js
new file mode 100644
index 0000000..d6e93a8
--- /dev/null
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/queryCtrl.js
@@ -0,0 +1,131 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+define([
+ 'angular',
+ 'lodash'
+ ],
+ function (angular, _) {
+ 'use strict';
+
+ var module = angular.module('grafana.controllers');
+
+ module.controller('AmbariMetricsQueryCtrl', function($scope) {
+
+ $scope.init = function() {
+ $scope.target.errors = validateTarget($scope.target);
+ $scope.aggregators = ['avg', 'sum', 'min', 'max'];
+ $scope.precisions = ['seconds', 'minutes', 'hours', 'days'];
+
+ if (!$scope.target.aggregator) {
+ $scope.target.aggregator = 'avg';
+ }
+
+ if (!$scope.target.downsampleAggregator) {
+ $scope.target.downsampleAggregator = 'avg';
+ }
+
+ $scope.datasource.getAggregators().then(function(aggs) {
+ $scope.aggregators = aggs;
+ });
+ };
+
+ $scope.targetBlur = function() {
+ $scope.target.errors = validateTarget($scope.target);
+
+ // this does not work so good
+ if (!_.isEqual($scope.oldTarget, $scope.target) && _.isEmpty($scope.target.errors)) {
+ $scope.oldTarget = angular.copy($scope.target);
+ $scope.get_data();
+ }
+ };
+
+ $scope.getTextValues = function(metricFindResult) {
+ return _.map(metricFindResult, function(value) { return value.text; });
+ };
+
+ $scope.suggestApps = function(query, callback) {
+ $scope.datasource.suggestApps(query)
+ .then($scope.getTextValues)
+ .then(callback);
+ };
+
+ $scope.suggestHosts = function(query, callback) {
+ $scope.datasource.suggestHosts(query)
+ .then($scope.getTextValues)
+ .then(callback);
+ };
+
+ $scope.suggestMetrics = function(query, callback) {
+ $scope.datasource.suggestMetrics(query, $scope.target.app)
+ .then($scope.getTextValues)
+ .then(callback);
+ };
+
+ $scope.suggestTagKeys = function(query, callback) {
+ $scope.datasource.metricFindQuery('tag_names(' + $scope.target.metric + ')')
+ .then($scope.getTextValues)
+ .then(callback);
+ };
+
+ $scope.suggestTagValues = function(query, callback) {
+ $scope.datasource.metricFindQuery('tag_values(' + $scope.target.metric + ',' + $scope.target.currentTagKey + ')')
+ .then($scope.getTextValues)
+ .then(callback);
+ };
+
+ $scope.addTag = function() {
+ if (!$scope.addTagMode) {
+ $scope.addTagMode = true;
+ return;
+ }
+
+ if (!$scope.target.tags) {
+ $scope.target.tags = {};
+ }
+
+ $scope.target.errors = validateTarget($scope.target);
+
+ if (!$scope.target.errors.tags) {
+ $scope.target.tags[$scope.target.currentTagKey] = $scope.target.currentTagValue;
+ $scope.target.currentTagKey = '';
+ $scope.target.currentTagValue = '';
+ $scope.targetBlur();
+ }
+
+ $scope.addTagMode = false;
+ };
+
+ $scope.removeTag = function(key) {
+ delete $scope.target.tags[key];
+ $scope.targetBlur();
+ };
+
+ function validateTarget(target) {
+ var errs = {};
+
+ if (target.tags && _.has(target.tags, target.currentTagKey)) {
+ errs.tags = "Duplicate tag key '" + target.currentTagKey + "'.";
+ }
+
+ return errs;
+ }
+
+ $scope.init();
+ });
+
+ });
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/8ff0b5ed/ambari-metrics/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-metrics/pom.xml b/ambari-metrics/pom.xml
index 3ca8d54..9a39122 100644
--- a/ambari-metrics/pom.xml
+++ b/ambari-metrics/pom.xml
@@ -276,6 +276,7 @@
<exclude>pass.txt</exclude>
<exclude>derby.log</exclude>
<exclude>**/*.nuspec</exclude>
+ <exclude>**/*.json</exclude>
</excludes>
</configuration>
<executions>