diff --git a/.gitignore b/.gitignore index 188313e..5882751 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,6 @@ node_modules npm-debug.log -dist/ - .idea/ *.iml diff --git a/dist/README.adoc b/dist/README.adoc new file mode 100644 index 0000000..8b8e4d2 --- /dev/null +++ b/dist/README.adoc @@ -0,0 +1,78 @@ += Hawkular Datasource for Grafana +:source-language: javascript + +This project is the Hawkular Datasource plugin for Grafana 3. It works with: + +* Metrics standalone servers as well +* Hawkular servers, starting from version Alpha13 + +== Installing + +=== From source + +Download the source code and copy the content of `dist` to `hawkular` inside Grafana's plugin directory. + +[source,bash] +---- +# This is the default for Linux Grafana installs. Change it to match yours, if needed. +GRAFANA_PLUGINS=/var/lib/grafana/plugins +wget https://github.com/hawkular/hawkular-grafana-datasource/archive/master.zip -O hawkular-grafana-datasource-master.zip +unzip hawkular-grafana-datasource-master.zip +mkdir ${GRAFANA_PLUGINS}/hawkular +cp -R hawkular-grafana-datasource-master/dist/* ${GRAFANA_PLUGINS}/hawkular +---- + +=== From the Grafana plugin directory + +COMING SOON + +== Configuration + +The datasource URL must point to the Hawkular Metrics service, e.g. `http://myhost:8080/hawkular/metrics` + +`direct` access mode only works with standalone Metrics servers currently. If you active it, make sure to allow +the Grafana server origin in Metrics' configuration. + +Authentication must be set when working with a Hawkular server. Check the 'Basic Auth' box and fill the user and password fields. + +Select the tenant. On Hawkular servers, use `hawkular`. + +Openshift-Metrics users must provide an authentication token. + +== Using Grafana Templating (variables) + +Grafana allows you to create dashboard templates through the definition of variables. This is link:http://docs.grafana.org/reference/templating/[documented on Grafana's site]. +With the Hawkular Datasource Plugin, the variables of type _'Query'_ are mapped to the http://www.hawkular.org/docs/rest/rest-metrics.html#GET__metrics[_@get (url)/metrics_] +Hawkular Metrics endpoint and can be used to retrieve tenant's metric names. Use the _Query Options_ text field to pass query parameters. +[TIP] +For instance, if you have metrics tagged _"type:memory"_ and others tagged _"type:cpu"_, you can write _"?tags=type:memory"_ to get only the _"memory"_ ones, or _"?tags=type:cpu|memory"_ to get them both. The leading question mark is not mandatory. + +There is an exception to that rule: if the query string is prefixed with _'tags/'_, the variable will contain the matching tag names rather than the metric names. In this case, the Hawkular Metrics endpoint link:++http://www.hawkular.org/docs/rest/rest-metrics.html#GET__metrics_tags__tags_++[_@get (url)/metrics/tags/{tags}_] will be used. +[TIP] +For instance, type _"tags/type:*"_ to get all of the available tag values for _"type"_. + +Once you have set some variables, you can use them in graph queries: either for row or graph duplication, or to display multiple series in a single graph from a single query. This is especially useful when metric names contain some dynamic parts and thus cannot be known in advance. + +== Building + +You need `npm` and `grunt` to build the project. Clone this repository, then from that directory run: + +[source,bash] +---- +npm install +grunt +---- + +Files are generated under the `dist` directory. + +To test it, copy these files to `${GRAFANA_PLUGINS}/hawkular` and restart grafana-server. + +== Building and running a Docker image + +[source,bash] +---- +# This will build the image +docker build -t hawkular/hawkular-grafana-datasource . +# This will run the image on http://localhost:3000/ +docker run -i -p 3000:3000 --name hawkular-grafana-datasource --rm hawkular/hawkular-grafana-datasource +---- diff --git a/dist/capabilities.js b/dist/capabilities.js new file mode 100644 index 0000000..2520c7a --- /dev/null +++ b/dist/capabilities.js @@ -0,0 +1,40 @@ +'use strict'; + +System.register([], function (_export, _context) { + "use strict"; + + var Capabilities; + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + return { + setters: [], + execute: function () { + _export('Capabilities', Capabilities = function Capabilities(versionStr) { + _classCallCheck(this, Capabilities); + + this.QUERY_POST_ENDPOINTS = true; + this.QUERY_BY_TAGS = true; + var regExp = new RegExp('([0-9]+)\.([0-9]+)\.(.+)'); + if (versionStr.match(regExp)) { + var versionInfo = regExp.exec(versionStr); + var major = versionInfo[1]; + var minor = versionInfo[2]; + if (major == 0 && minor < 17) { + this.QUERY_POST_ENDPOINTS = false; + } + if (major == 0 && minor < 20) { + this.QUERY_BY_TAGS = false; + } + } + }); + + _export('Capabilities', Capabilities); + } + }; +}); +//# sourceMappingURL=capabilities.js.map diff --git a/dist/capabilities.js.map b/dist/capabilities.js.map new file mode 100644 index 0000000..8f72a52 --- /dev/null +++ b/dist/capabilities.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../src/capabilities.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;8BAAa,Y,GAEX,sBAAY,UAAZ,EAAwB;AAAA;;AACtB,aAAK,oBAAL,GAA4B,IAA5B;AACA,aAAK,aAAL,GAAqB,IAArB;AACA,YAAI,SAAS,IAAI,MAAJ,CAAW,0BAAX,CAAb;AACA,YAAI,WAAW,KAAX,CAAiB,MAAjB,CAAJ,EAA8B;AAC5B,cAAI,cAAc,OAAO,IAAP,CAAY,UAAZ,CAAlB;AACA,cAAI,QAAQ,YAAY,CAAZ,CAAZ;AACA,cAAI,QAAQ,YAAY,CAAZ,CAAZ;AACA,cAAI,SAAS,CAAT,IAAc,QAAQ,EAA1B,EAA8B;AAC5B,iBAAK,oBAAL,GAA4B,KAA5B;AACD;AACD,cAAI,SAAS,CAAT,IAAc,QAAQ,EAA1B,EAA8B;AAC5B,iBAAK,aAAL,GAAqB,KAArB;AACD;AACF;AACF,O","file":"capabilities.js","sourcesContent":["export class Capabilities {\n\n constructor(versionStr) {\n this.QUERY_POST_ENDPOINTS = true;\n this.QUERY_BY_TAGS = true;\n let regExp = new RegExp('([0-9]+)\\.([0-9]+)\\.(.+)');\n if (versionStr.match(regExp)) {\n let versionInfo = regExp.exec(versionStr);\n let major = versionInfo[1];\n let minor = versionInfo[2];\n if (major == 0 && minor < 17) {\n this.QUERY_POST_ENDPOINTS = false;\n }\n if (major == 0 && minor < 20) {\n this.QUERY_BY_TAGS = false;\n }\n }\n }\n}\n"]} \ No newline at end of file diff --git a/dist/css/query-editor.css b/dist/css/query-editor.css new file mode 100644 index 0000000..3b678b9 --- /dev/null +++ b/dist/css/query-editor.css @@ -0,0 +1,3 @@ +.generic-datasource-query-row .query-keyword { + width: 75px; +} \ No newline at end of file diff --git a/dist/datasource.js b/dist/datasource.js new file mode 100644 index 0000000..6dbf885 --- /dev/null +++ b/dist/datasource.js @@ -0,0 +1,226 @@ +'use strict'; + +System.register(['lodash', './variables', './capabilities', './queryProcessor'], function (_export, _context) { + "use strict"; + + var _, Variables, Capabilities, QueryProcessor, _createClass, HawkularDatasource; + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + return { + setters: [function (_lodash) { + _ = _lodash.default; + }, function (_variables) { + Variables = _variables.Variables; + }, function (_capabilities) { + Capabilities = _capabilities.Capabilities; + }, function (_queryProcessor) { + QueryProcessor = _queryProcessor.QueryProcessor; + }], + execute: function () { + _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + _export('HawkularDatasource', HawkularDatasource = function () { + function HawkularDatasource(instanceSettings, $q, backendSrv, templateSrv) { + _classCallCheck(this, HawkularDatasource); + + this.type = instanceSettings.type; + this.url = instanceSettings.url; + this.name = instanceSettings.name; + this.tenant = instanceSettings.jsonData.tenant; + this.token = instanceSettings.jsonData.token; + this.q = $q; + this.backendSrv = backendSrv; + var variables = new Variables(templateSrv); + this.capabilitiesPromise = this.queryVersion().then(function (version) { + return new Capabilities(version); + }); + this.queryProcessor = new QueryProcessor($q, backendSrv, variables, this.capabilitiesPromise, this.url, this.createHeaders()); + } + + _createClass(HawkularDatasource, [{ + key: 'query', + value: function query(options) { + var _this = this; + + var validTargets = options.targets.filter(function (target) { + return !target.hide; + }).filter(function (target) { + return target.target !== 'select metric'; + }); + + if (validTargets.length === 0) { + return this.q.when({ data: [] }); + } + + var promises = validTargets.map(function (target) { + return _this.queryProcessor.run(target, options); + }); + + return this.q.all(promises).then(function (responses) { + var flatten = [].concat.apply([], responses); + return { data: flatten }; + }); + } + }, { + key: 'createHeaders', + value: function createHeaders() { + var headers = { + 'Content-Type': 'application/json', + 'Hawkular-Tenant': this.tenant + }; + if (typeof this.token === 'string' && this.token.length > 0) { + headers.Authorization = 'Bearer ' + this.token; + } + return headers; + } + }, { + key: 'testDatasource', + value: function testDatasource() { + return this.backendSrv.datasourceRequest({ + url: this.url + '/status', + method: 'GET' + }).then(function (response) { + if (response.status === 200) { + return { status: "success", message: "Data source is working", title: "Success" }; + } + }); + } + }, { + key: 'annotationQuery', + value: function annotationQuery(options) { + return this.backendSrv.datasourceRequest({ + url: this.url + '/annotations', + method: 'POST', + data: options + }).then(function (result) { + return result.data; + }); + } + }, { + key: 'suggestQueries', + value: function suggestQueries(target) { + return this.backendSrv.datasourceRequest({ + url: this.url + '/metrics?type=' + target.type, + method: 'GET', + headers: this.createHeaders() + }).then(function (result) { + return _.map(result.data, function (metric) { + return { text: metric.id, value: metric.id }; + }); + }); + } + }, { + key: 'suggestTags', + value: function suggestTags(type, key) { + if (!key) { + // Need at least some characters typed in order to suggest something + return this.q.when([]); + } + return this.backendSrv.datasourceRequest({ + url: this.url + '/' + type + 's/tags/' + key + ':*', + method: 'GET', + headers: this.createHeaders() + }).then(function (result) { + if (result.data.hasOwnProperty(key)) { + return [' *'].concat(result.data[key]).map(function (value) { + return { text: value, value: value }; + }); + } + return []; + }); + } + }, { + key: 'metricFindQuery', + value: function metricFindQuery(query) { + var params = ""; + if (query !== undefined) { + if (query.startsWith("tags/")) { + return this.findTags(query.substr(5).trim()); + } + if (query.startsWith("?")) { + params = query; + } else { + params = "?" + query; + } + } + return this.backendSrv.datasourceRequest({ + url: this.url + '/metrics' + params, + method: 'GET', + headers: this.createHeaders() + }).then(function (result) { + return _.map(result.data, function (metric) { + return { text: metric.id, value: metric.id }; + }); + }); + } + }, { + key: 'findTags', + value: function findTags(pattern) { + return this.backendSrv.datasourceRequest({ + url: this.url + '/metrics/tags/' + pattern, + method: 'GET', + headers: this.createHeaders() + }).then(function (result) { + var flatTags = []; + if (result.data) { + var data = result.data; + for (var property in data) { + if (data.hasOwnProperty(property)) { + flatTags = flatTags.concat(data[property]); + } + } + } + return flatTags.map(function (tag) { + return { text: tag, value: tag }; + }); + }); + } + }, { + key: 'queryVersion', + value: function queryVersion() { + return this.backendSrv.datasourceRequest({ + url: this.url + '/status', + method: 'GET', + headers: { 'Content-Type': 'application/json' } + }).then(function (response) { + return response.data['Implementation-Version']; + }).catch(function (response) { + return "Unknown"; + }); + } + }, { + key: 'getCapabilities', + value: function getCapabilities() { + return this.capabilitiesPromise; + } + }]); + + return HawkularDatasource; + }()); + + _export('HawkularDatasource', HawkularDatasource); + } + }; +}); +//# sourceMappingURL=datasource.js.map diff --git a/dist/datasource.js.map b/dist/datasource.js.map new file mode 100644 index 0000000..2b4e6bc --- /dev/null +++ b/dist/datasource.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../src/datasource.js"],"names":[],"mappings":"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","file":"datasource.js","sourcesContent":["import _ from \"lodash\";\nimport {Variables} from './variables';\nimport {Capabilities} from './capabilities';\nimport {QueryProcessor} from './queryProcessor';\n\nexport class HawkularDatasource {\n\n constructor(instanceSettings, $q, backendSrv, templateSrv) {\n this.type = instanceSettings.type;\n this.url = instanceSettings.url;\n this.name = instanceSettings.name;\n this.tenant = instanceSettings.jsonData.tenant;\n this.token = instanceSettings.jsonData.token;\n this.q = $q;\n this.backendSrv = backendSrv;\n let variables = new Variables(templateSrv);\n this.capabilitiesPromise = this.queryVersion()\n .then(version => new Capabilities(version));\n this.queryProcessor = new QueryProcessor($q, backendSrv, variables, this.capabilitiesPromise, this.url, this.createHeaders());\n }\n\n query(options) {\n let validTargets = options.targets\n .filter(target => !target.hide)\n .filter(target => target.target !== 'select metric');\n\n if (validTargets.length === 0) {\n return this.q.when({data: []});\n }\n\n let promises = validTargets.map(target => {\n return this.queryProcessor.run(target, options);\n });\n\n return this.q.all(promises).then(responses => {\n let flatten = [].concat.apply([], responses);\n return {data: flatten};\n });\n }\n\n createHeaders() {\n var headers = {\n 'Content-Type': 'application/json',\n 'Hawkular-Tenant': this.tenant\n };\n if (typeof this.token === 'string' && this.token.length > 0) {\n headers.Authorization = 'Bearer ' + this.token;\n }\n return headers;\n }\n\n testDatasource() {\n return this.backendSrv.datasourceRequest({\n url: this.url + '/status',\n method: 'GET'\n }).then(response => {\n if (response.status === 200) {\n return { status: \"success\", message: \"Data source is working\", title: \"Success\" };\n }\n });\n }\n\n annotationQuery(options) {\n return this.backendSrv.datasourceRequest({\n url: this.url + '/annotations',\n method: 'POST',\n data: options\n }).then(result => {\n return result.data;\n });\n }\n\n suggestQueries(target) {\n return this.backendSrv.datasourceRequest({\n url: this.url + '/metrics?type=' + target.type,\n method: 'GET',\n headers: this.createHeaders()\n }).then(result => {\n return _.map(result.data, metric => {\n return {text: metric.id, value: metric.id};\n });\n });\n }\n\n suggestTags(type, key) {\n if (!key) {\n // Need at least some characters typed in order to suggest something\n return this.q.when([]);\n }\n return this.backendSrv.datasourceRequest({\n url: this.url + '/' + type + 's/tags/' + key + ':*',\n method: 'GET',\n headers: this.createHeaders()\n }).then(result => {\n if (result.data.hasOwnProperty(key)) {\n return [' *'].concat(result.data[key]).map(value => {\n return {text: value, value: value};\n });\n }\n return [];\n });\n }\n\n metricFindQuery(query) {\n var params = \"\";\n if (query !== undefined) {\n if (query.startsWith(\"tags/\")) {\n return this.findTags(query.substr(5).trim());\n }\n if (query.startsWith(\"?\")) {\n params = query;\n } else {\n params = \"?\" + query;\n }\n }\n return this.backendSrv.datasourceRequest({\n url: this.url + '/metrics' + params,\n method: 'GET',\n headers: this.createHeaders()\n }).then(result => {\n return _.map(result.data, metric => {\n return {text: metric.id, value: metric.id};\n });\n });\n }\n\n findTags(pattern) {\n return this.backendSrv.datasourceRequest({\n url: this.url + '/metrics/tags/' + pattern,\n method: 'GET',\n headers: this.createHeaders()\n }).then(result => {\n var flatTags = [];\n if (result.data) {\n var data = result.data;\n for (var property in data) {\n if (data.hasOwnProperty(property)) {\n flatTags = flatTags.concat(data[property]);\n }\n }\n }\n return flatTags.map(tag => {\n return {text: tag, value: tag};\n });\n });\n }\n\n queryVersion() {\n return this.backendSrv.datasourceRequest({\n url: this.url + '/status',\n method: 'GET',\n headers: {'Content-Type': 'application/json'}\n }).then(response => response.data['Implementation-Version'])\n .catch(response => \"Unknown\");\n }\n\n getCapabilities() {\n return this.capabilitiesPromise;\n }\n}\n"]} \ No newline at end of file diff --git a/dist/img/hawkular_logo.svg b/dist/img/hawkular_logo.svg new file mode 100644 index 0000000..b8a46a3 --- /dev/null +++ b/dist/img/hawkular_logo.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dist/module.js b/dist/module.js new file mode 100644 index 0000000..8dc62fe --- /dev/null +++ b/dist/module.js @@ -0,0 +1,51 @@ +'use strict'; + +System.register(['./datasource', './query_ctrl'], function (_export, _context) { + "use strict"; + + var HawkularDatasource, HawkularDatasourceQueryCtrl, HawkularConfigCtrl, HawkularQueryOptionsCtrl, HawkularAnnotationsQueryCtrl; + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + return { + setters: [function (_datasource) { + HawkularDatasource = _datasource.HawkularDatasource; + }, function (_query_ctrl) { + HawkularDatasourceQueryCtrl = _query_ctrl.HawkularDatasourceQueryCtrl; + }], + execute: function () { + _export('ConfigCtrl', HawkularConfigCtrl = function HawkularConfigCtrl() { + _classCallCheck(this, HawkularConfigCtrl); + }); + + HawkularConfigCtrl.templateUrl = 'partials/config.html'; + + _export('QueryOptionsCtrl', HawkularQueryOptionsCtrl = function HawkularQueryOptionsCtrl() { + _classCallCheck(this, HawkularQueryOptionsCtrl); + }); + + HawkularQueryOptionsCtrl.templateUrl = 'partials/query.options.html'; + + _export('AnnotationsQueryCtrl', HawkularAnnotationsQueryCtrl = function HawkularAnnotationsQueryCtrl() { + _classCallCheck(this, HawkularAnnotationsQueryCtrl); + }); + + HawkularAnnotationsQueryCtrl.templateUrl = 'partials/annotations.editor.html'; + + _export('Datasource', HawkularDatasource); + + _export('QueryCtrl', HawkularDatasourceQueryCtrl); + + _export('ConfigCtrl', HawkularConfigCtrl); + + _export('QueryOptionsCtrl', HawkularQueryOptionsCtrl); + + _export('AnnotationsQueryCtrl', HawkularAnnotationsQueryCtrl); + } + }; +}); +//# sourceMappingURL=module.js.map diff --git a/dist/module.js.map b/dist/module.js.map new file mode 100644 index 0000000..51a2f0d --- /dev/null +++ b/dist/module.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../src/module.js"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAQ,wB,eAAA,kB;;AACA,iC,eAAA,2B;;;4BAEF,kB;;;;AACN,yBAAmB,WAAnB,GAAiC,sBAAjC;;kCAEM,wB;;;;AACN,+BAAyB,WAAzB,GAAuC,6BAAvC;;sCAEM,4B;;;;AACN,mCAA6B,WAA7B,GAA2C,kCAA3C;;4BAGE,kB;;2BACA,2B;;4BACA,kB;;kCACA,wB;;sCACA,4B","file":"module.js","sourcesContent":["import {HawkularDatasource} from './datasource';\nimport {HawkularDatasourceQueryCtrl} from './query_ctrl';\n\nclass HawkularConfigCtrl {}\nHawkularConfigCtrl.templateUrl = 'partials/config.html';\n\nclass HawkularQueryOptionsCtrl {}\nHawkularQueryOptionsCtrl.templateUrl = 'partials/query.options.html';\n\nclass HawkularAnnotationsQueryCtrl {}\nHawkularAnnotationsQueryCtrl.templateUrl = 'partials/annotations.editor.html';\n\nexport {\n HawkularDatasource as Datasource,\n HawkularDatasourceQueryCtrl as QueryCtrl,\n HawkularConfigCtrl as ConfigCtrl,\n HawkularQueryOptionsCtrl as QueryOptionsCtrl,\n HawkularAnnotationsQueryCtrl as AnnotationsQueryCtrl\n};\n"]} \ No newline at end of file diff --git a/dist/partials/annotations.editor.html b/dist/partials/annotations.editor.html new file mode 100644 index 0000000..8e67e97 --- /dev/null +++ b/dist/partials/annotations.editor.html @@ -0,0 +1,9 @@ + +
Query
+
+
+ +
+
+ + diff --git a/dist/partials/config.html b/dist/partials/config.html new file mode 100644 index 0000000..f17bc93 --- /dev/null +++ b/dist/partials/config.html @@ -0,0 +1,19 @@ + + + +

Hawkular settings

+ +
+
+
+ Tenant + +
+
+
+
+ Token + +
+
+
diff --git a/dist/partials/query.editor.html b/dist/partials/query.editor.html new file mode 100644 index 0000000..cdeb273 --- /dev/null +++ b/dist/partials/query.editor.html @@ -0,0 +1,21 @@ + +
+
+ +
+
+ +
+
+ +
+
+ +
+ +
+
diff --git a/dist/partials/query.options.html b/dist/partials/query.options.html new file mode 100644 index 0000000..b460011 --- /dev/null +++ b/dist/partials/query.options.html @@ -0,0 +1,4 @@ +
+
+
+
diff --git a/dist/plugin.json b/dist/plugin.json new file mode 100644 index 0000000..6a75da7 --- /dev/null +++ b/dist/plugin.json @@ -0,0 +1,34 @@ +{ + "id": "hawkular", + "type": "datasource", + "name": "Hawkular", + "metrics": true, + "annotations": false, + "info": { + "description": "Hawkular Datasource", + "author": { + "name": "Hawkular Project", + "url": "http://hawkular.org" + }, + "logos": { + "small": "img/hawkular_logo.svg", + "large": "img/hawkular_logo.svg" + }, + "links": [ + { + "name": "Project", + "url": "http://hawkular.org" + }, + { + "name": "GitHub", + "url": "https://github.com/hawkular/hawkular-grafana-datasource" + } + ], + "version": "1.0.0", + "updated": "2016-05-30" + }, + "dependencies": { + "grafanaVersion": "3.x.x", + "plugins": [] + } +} diff --git a/dist/queryProcessor.js b/dist/queryProcessor.js new file mode 100644 index 0000000..a09ed53 --- /dev/null +++ b/dist/queryProcessor.js @@ -0,0 +1,210 @@ +'use strict'; + +System.register([], function (_export, _context) { + "use strict"; + + var _createClass, QueryProcessor; + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + return { + setters: [], + execute: function () { + _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + _export('QueryProcessor', QueryProcessor = function () { + function QueryProcessor(q, backendSrv, variables, capabilities, url, baseHeaders) { + _classCallCheck(this, QueryProcessor); + + this.q = q; + this.backendSrv = backendSrv; + this.variables = variables; + this.capabilities = capabilities; + this.url = url; + this.baseHeaders = baseHeaders; + } + + _createClass(QueryProcessor, [{ + key: 'run', + value: function run(target, options) { + var _this = this; + + return this.capabilities.then(function (caps) { + if (target.queryBy === 'ids') { + var metricIds = _this.variables.resolve(target.target, options); + if (caps.QUERY_POST_ENDPOINTS) { + return _this.rawQuery(target, options.range, metricIds); + } else { + return _this.rawQueryLegacy(target, options.range, metricIds); + } + } else { + if (target.tags.length === 0) { + return _this.q.when([]); + } + var strTags = _this.hawkularFormatTags(target.tags, options); + return _this.rawQueryByTags(target, options.range, strTags); + } + }); + } + }, { + key: 'hawkularFormatTags', + value: function hawkularFormatTags(tags, options) { + var _this2 = this; + + return tags.map(function (tag) { + var value; + if (tag.value === ' *') { + // '*' character get a special treatment in grafana so we had to use ' *' instead + value = '*'; + } else { + value = _this2.variables.resolve(tag.value, options).join('|'); + } + return tag.name + ':' + value; + }).join(','); + } + }, { + key: 'rawQuery', + value: function rawQuery(target, range, metricIds) { + var _this3 = this; + + var uri = [target.type + 's', // gauges or counters + target.rate ? 'rate' : 'raw', // raw or rate + 'query']; + var url = this.url + '/' + uri.join('/'); + + return this.backendSrv.datasourceRequest({ + url: url, + data: { + ids: metricIds, + start: range.from.valueOf(), + end: range.to.valueOf(), + order: 'ASC' + }, + method: 'POST', + headers: this.baseHeaders + }).then(function (response) { + return _this3.processRawResponse(target, response.status == 200 ? response.data : []); + }); + } + }, { + key: 'rawQueryLegacy', + value: function rawQueryLegacy(target, range, metricIds) { + var _this4 = this; + + return this.q.all(metricIds.map(function (metric) { + var uri = [target.type + 's', // gauges or counters + encodeURIComponent(metric).replace('+', '%20'), // metric name + 'data']; + var url = _this4.url + '/' + uri.join('/'); + + return _this4.backendSrv.datasourceRequest({ + url: url, + params: { + start: range.from.valueOf(), + end: range.to.valueOf() + }, + method: 'GET', + headers: _this4.baseHeaders + }).then(function (response) { + return _this4.processRawResponseLegacy(target, metric, response.status == 200 ? response.data : []); + }); + })); + } + }, { + key: 'rawQueryByTags', + value: function rawQueryByTags(target, range, tags) { + var _this5 = this; + + var uri = [target.type + 's', // gauges or counters + target.rate ? 'rate' : 'raw', // raw or rate + 'query']; + var url = this.url + '/' + uri.join('/'); + + return this.backendSrv.datasourceRequest({ + url: url, + data: { + tags: tags, + start: range.from.valueOf(), + end: range.to.valueOf(), + order: 'ASC' + }, + method: 'POST', + headers: this.baseHeaders + }).then(function (response) { + return _this5.processRawResponse(target, response.status == 200 ? response.data : []); + }); + } + }, { + key: 'processRawResponse', + value: function processRawResponse(target, data) { + return data.map(function (timeSerie) { + return { + refId: target.refId, + target: timeSerie.id, + datapoints: timeSerie.data.map(function (point) { + return [point.value, point.timestamp]; + }) + }; + }); + } + }, { + key: 'processRawResponseLegacy', + value: function processRawResponseLegacy(target, metric, data) { + var datapoints; + if (!target.rate) { + datapoints = _.map(data, function (point) { + return [point.value, point.timestamp]; + }); + } else { + var sortedData = data.sort(function (p1, p2) { + return p1.timestamp - p2.timestamp; + }); + datapoints = _.chain(sortedData).zip(sortedData.slice(1)).filter(function (pair) { + return pair[1] // Exclude the last pair + && (target.type == 'gauge' || pair[0].value <= pair[1].value); // Exclude counter resets + }).map(function (pair) { + var point1 = pair[0], + point2 = pair[1]; + var timestamp = point2.timestamp; + var value_diff = point2.value - point1.value; + var time_diff = point2.timestamp - point1.timestamp; + var rate = 60000 * value_diff / time_diff; + return [rate, timestamp]; + }).value(); + } + return { + refId: target.refId, + target: metric, + datapoints: datapoints + }; + } + }]); + + return QueryProcessor; + }()); + + _export('QueryProcessor', QueryProcessor); + } + }; +}); +//# sourceMappingURL=queryProcessor.js.map diff --git a/dist/queryProcessor.js.map b/dist/queryProcessor.js.map new file mode 100644 index 0000000..5b360dd --- /dev/null +++ b/dist/queryProcessor.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../src/queryProcessor.js"],"names":[],"mappings":"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","file":"queryProcessor.js","sourcesContent":["export class QueryProcessor {\n\n constructor(q, backendSrv, variables, capabilities, url, baseHeaders) {\n this.q = q;\n this.backendSrv = backendSrv;\n this.variables = variables;\n this.capabilities = capabilities;\n this.url = url;\n this.baseHeaders = baseHeaders;\n }\n\n run(target, options) {\n return this.capabilities.then(caps => {\n if (target.queryBy === 'ids') {\n let metricIds = this.variables.resolve(target.target, options);\n if (caps.QUERY_POST_ENDPOINTS) {\n return this.rawQuery(target, options.range, metricIds);\n } else {\n return this.rawQueryLegacy(target, options.range, metricIds);\n }\n } else {\n if (target.tags.length === 0) {\n return this.q.when([]);\n }\n let strTags = this.hawkularFormatTags(target.tags, options);\n return this.rawQueryByTags(target, options.range, strTags);\n }\n });\n }\n\n hawkularFormatTags(tags, options) {\n return tags.map(tag => {\n var value;\n if (tag.value === ' *') {\n // '*' character get a special treatment in grafana so we had to use ' *' instead\n value = '*';\n } else {\n value = this.variables.resolve(tag.value, options).join('|');\n }\n return tag.name + ':' + value;\n }).join(',');\n }\n\n rawQuery(target, range, metricIds) {\n let uri = [\n target.type + 's', // gauges or counters\n target.rate ? 'rate' : 'raw', // raw or rate\n 'query'\n ];\n let url = this.url + '/' + uri.join('/');\n\n return this.backendSrv.datasourceRequest({\n url: url,\n data: {\n ids: metricIds,\n start: range.from.valueOf(),\n end: range.to.valueOf(),\n order: 'ASC'\n },\n method: 'POST',\n headers: this.baseHeaders\n }).then(response => this.processRawResponse(target, response.status == 200 ? response.data : []));\n }\n\n rawQueryLegacy(target, range, metricIds) {\n return this.q.all(metricIds.map(metric => {\n let uri = [\n target.type + 's', // gauges or counters\n encodeURIComponent(metric).replace('+', '%20'), // metric name\n 'data'];\n let url = this.url + '/' + uri.join('/');\n\n return this.backendSrv.datasourceRequest({\n url: url,\n params: {\n start: range.from.valueOf(),\n end: range.to.valueOf()\n },\n method: 'GET',\n headers: this.baseHeaders\n }).then(response => this.processRawResponseLegacy(target, metric, response.status == 200 ? response.data : []));\n }));\n }\n\n rawQueryByTags(target, range, tags) {\n let uri = [\n target.type + 's', // gauges or counters\n target.rate ? 'rate' : 'raw', // raw or rate\n 'query'\n ];\n let url = this.url + '/' + uri.join('/');\n\n return this.backendSrv.datasourceRequest({\n url: url,\n data: {\n tags: tags,\n start: range.from.valueOf(),\n end: range.to.valueOf(),\n order: 'ASC'\n },\n method: 'POST',\n headers: this.baseHeaders\n }).then(response => this.processRawResponse(target, response.status == 200 ? response.data : []));\n }\n\n processRawResponse(target, data) {\n return data.map(timeSerie => {\n return {\n refId: target.refId,\n target: timeSerie.id,\n datapoints: timeSerie.data.map(point => [point.value, point.timestamp])\n };\n });\n }\n\n processRawResponseLegacy(target, metric, data) {\n var datapoints;\n if (!target.rate) {\n datapoints = _.map(data, point => [point.value, point.timestamp]);\n } else {\n var sortedData = data.sort((p1, p2)=> p1.timestamp - p2.timestamp);\n datapoints = _.chain(sortedData)\n .zip(sortedData.slice(1))\n .filter(pair => {\n return pair[1] // Exclude the last pair\n && (target.type == 'gauge' || pair[0].value <= pair[1].value); // Exclude counter resets\n })\n .map(pair => {\n var point1 = pair[0], point2 = pair[1];\n var timestamp = point2.timestamp;\n var value_diff = point2.value - point1.value;\n var time_diff = point2.timestamp - point1.timestamp;\n var rate = 60000 * value_diff / time_diff;\n return [rate, timestamp];\n })\n .value();\n }\n return {\n refId: target.refId,\n target: metric,\n datapoints: datapoints\n };\n }\n}\n"]} \ No newline at end of file diff --git a/dist/query_ctrl.js b/dist/query_ctrl.js new file mode 100644 index 0000000..d87fdff --- /dev/null +++ b/dist/query_ctrl.js @@ -0,0 +1,160 @@ +'use strict'; + +System.register(['app/plugins/sdk', './css/query-editor.css!'], function (_export, _context) { + "use strict"; + + var QueryCtrl, _createClass, HawkularDatasourceQueryCtrl; + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + function _possibleConstructorReturn(self, call) { + if (!self) { + throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); + } + + return call && (typeof call === "object" || typeof call === "function") ? call : self; + } + + function _inherits(subClass, superClass) { + if (typeof superClass !== "function" && superClass !== null) { + throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); + } + + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + enumerable: false, + writable: true, + configurable: true + } + }); + if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; + } + + return { + setters: [function (_appPluginsSdk) { + QueryCtrl = _appPluginsSdk.QueryCtrl; + }, function (_cssQueryEditorCss) {}], + execute: function () { + _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + _export('HawkularDatasourceQueryCtrl', HawkularDatasourceQueryCtrl = function (_QueryCtrl) { + _inherits(HawkularDatasourceQueryCtrl, _QueryCtrl); + + function HawkularDatasourceQueryCtrl($scope, $injector, uiSegmentSrv, $q) { + _classCallCheck(this, HawkularDatasourceQueryCtrl); + + var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(HawkularDatasourceQueryCtrl).call(this, $scope, $injector)); + + _this.scope = $scope; + _this.uiSegmentSrv = uiSegmentSrv; + _this.$q = $q; + + _this.queryByTagCapability = false; + _this.datasource.getCapabilities().then(function (caps) { + _this.queryByTagCapability = caps.QUERY_BY_TAGS; + }); + + _this.listQueryBy = [{ value: 'ids', text: 'Search by name' }, { value: 'tags', text: 'Search by tags' }]; + _this.metricTypes = [{ value: 'gauge', text: 'Gauge' }, { value: 'counter', text: 'Counter' }]; + + _this.target.queryBy = _this.target.queryBy || _this.listQueryBy[0].value; + _this.target.type = _this.target.type || _this.metricTypes[0].value; + _this.target.target = _this.target.target || 'select metric'; + _this.target.rate = _this.target.rate === true; + _this.target.tags = _this.target.tags || []; + + _this.tagsSegments = _.reduce(_this.target.tags, function (list, tag) { + list.push(uiSegmentSrv.newKey(tag.name)); + list.push(uiSegmentSrv.newOperator(':')); + list.push(uiSegmentSrv.newKeyValue(tag.value)); + list.push(uiSegmentSrv.newOperator(',')); + return list; + }, []); + _this.tagsSegments.push(uiSegmentSrv.newPlusButton()); + _this.removeTagsSegment = uiSegmentSrv.newSegment({ fake: true, value: '-- Remove tag --' }); + return _this; + } + + _createClass(HawkularDatasourceQueryCtrl, [{ + key: 'getTagsSegments', + value: function getTagsSegments(segment, $index) { + if (segment.type === 'plus-button') { + return this.$q.when([]); + } else if (segment.type === 'key') { + return this.$q.when([angular.copy(this.removeTagsSegment)]); + } else if (segment.type === 'value') { + var key = this.tagsSegments[$index - 2].value; + return this.datasource.suggestTags(this.target.type, key).then(this.uiSegmentSrv.transformToSegments(false)); + } + } + }, { + key: 'tagsSegmentChanged', + value: function tagsSegmentChanged(segment, index) { + if (segment.value === this.removeTagsSegment.value) { + this.tagsSegments.splice(index, 4); + } else if (segment.type === 'plus-button') { + this.tagsSegments.splice(index, 1, this.uiSegmentSrv.newOperator(',')); + this.tagsSegments.splice(index, 0, this.uiSegmentSrv.newKeyValue(' *')); + this.tagsSegments.splice(index, 0, this.uiSegmentSrv.newOperator(':')); + this.tagsSegments.splice(index, 0, this.uiSegmentSrv.newKey(segment.value)); + this.tagsSegments.push(this.uiSegmentSrv.newPlusButton()); + } else { + this.tagsSegments[index] = segment; + } + this.tagsToModel(); + this.onChangeInternal(); + } + }, { + key: 'tagsToModel', + value: function tagsToModel() { + this.target.tags = []; + for (var i = 0; i < this.tagsSegments.length - 2; i += 4) { + var key = this.tagsSegments[i].value; + var val = this.tagsSegments[i + 2].fake ? '*' : this.tagsSegments[i + 2].value || '*'; + this.target.tags.push({ name: key, value: val }); + } + } + }, { + key: 'getOptions', + value: function getOptions() { + return this.datasource.suggestQueries(this.target).then(this.uiSegmentSrv.transformToSegments(false)); + // Options have to be transformed by uiSegmentSrv to be usable by metric-segment-model directive + } + }, { + key: 'onChangeInternal', + value: function onChangeInternal() { + this.panelCtrl.refresh(); // Asks the panel to refresh data. + } + }]); + + return HawkularDatasourceQueryCtrl; + }(QueryCtrl)); + + _export('HawkularDatasourceQueryCtrl', HawkularDatasourceQueryCtrl); + + HawkularDatasourceQueryCtrl.templateUrl = 'partials/query.editor.html'; + } + }; +}); +//# sourceMappingURL=query_ctrl.js.map diff --git a/dist/query_ctrl.js.map b/dist/query_ctrl.js.map new file mode 100644 index 0000000..ade2181 --- /dev/null +++ b/dist/query_ctrl.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../src/query_ctrl.js"],"names":[],"mappings":"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","file":"query_ctrl.js","sourcesContent":["import {QueryCtrl} from 'app/plugins/sdk';\nimport './css/query-editor.css!'\n\nexport class HawkularDatasourceQueryCtrl extends QueryCtrl {\n\n constructor($scope, $injector, uiSegmentSrv, $q) {\n super($scope, $injector);\n\n this.scope = $scope;\n this.uiSegmentSrv = uiSegmentSrv;\n this.$q = $q;\n\n this.queryByTagCapability = false;\n this.datasource.getCapabilities().then(caps => {\n this.queryByTagCapability = caps.QUERY_BY_TAGS;\n });\n\n this.listQueryBy = [\n {value: 'ids', text: 'Search by name'},\n {value: 'tags', text: 'Search by tags'}\n ];\n this.metricTypes = [\n {value: 'gauge', text: 'Gauge'},\n {value: 'counter', text: 'Counter'}\n ];\n\n this.target.queryBy = this.target.queryBy || this.listQueryBy[0].value;\n this.target.type = this.target.type || this.metricTypes[0].value;\n this.target.target = this.target.target || 'select metric';\n this.target.rate = this.target.rate === true;\n this.target.tags = this.target.tags || [];\n\n this.tagsSegments = _.reduce(this.target.tags, function(list, tag) {\n list.push(uiSegmentSrv.newKey(tag.name));\n list.push(uiSegmentSrv.newOperator(':'));\n list.push(uiSegmentSrv.newKeyValue(tag.value));\n list.push(uiSegmentSrv.newOperator(','));\n return list;\n }, []);\n this.tagsSegments.push(uiSegmentSrv.newPlusButton());\n this.removeTagsSegment = uiSegmentSrv.newSegment({fake: true, value: '-- Remove tag --'});\n }\n\n getTagsSegments(segment, $index) {\n if (segment.type === 'plus-button') {\n return this.$q.when([]);\n } else if (segment.type === 'key') {\n return this.$q.when([angular.copy(this.removeTagsSegment)]);\n } else if (segment.type === 'value') {\n var key = this.tagsSegments[$index-2].value;\n return this.datasource.suggestTags(this.target.type, key)\n .then(this.uiSegmentSrv.transformToSegments(false));\n }\n }\n\n tagsSegmentChanged(segment, index) {\n if (segment.value === this.removeTagsSegment.value) {\n this.tagsSegments.splice(index, 4);\n } else if (segment.type === 'plus-button') {\n this.tagsSegments.splice(index, 1, this.uiSegmentSrv.newOperator(','));\n this.tagsSegments.splice(index, 0, this.uiSegmentSrv.newKeyValue(' *'));\n this.tagsSegments.splice(index, 0, this.uiSegmentSrv.newOperator(':'));\n this.tagsSegments.splice(index, 0, this.uiSegmentSrv.newKey(segment.value));\n this.tagsSegments.push(this.uiSegmentSrv.newPlusButton());\n } else {\n this.tagsSegments[index] = segment;\n }\n this.tagsToModel();\n this.onChangeInternal();\n }\n\n tagsToModel() {\n this.target.tags = [];\n for (var i = 0; i < this.tagsSegments.length - 2; i += 4) {\n let key = this.tagsSegments[i].value;\n let val = this.tagsSegments[i+2].fake ? '*' : (this.tagsSegments[i+2].value || '*');\n this.target.tags.push({name: key, value: val});\n }\n }\n\n getOptions() {\n return this.datasource.suggestQueries(this.target)\n .then(this.uiSegmentSrv.transformToSegments(false));\n // Options have to be transformed by uiSegmentSrv to be usable by metric-segment-model directive\n }\n\n onChangeInternal() {\n this.panelCtrl.refresh(); // Asks the panel to refresh data.\n }\n}\n\nHawkularDatasourceQueryCtrl.templateUrl = 'partials/query.editor.html';\n"]} \ No newline at end of file diff --git a/dist/test/capabilities.js b/dist/test/capabilities.js new file mode 100644 index 0000000..39e0641 --- /dev/null +++ b/dist/test/capabilities.js @@ -0,0 +1,27 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var Capabilities = exports.Capabilities = function Capabilities(versionStr) { + _classCallCheck(this, Capabilities); + + this.QUERY_POST_ENDPOINTS = true; + this.QUERY_BY_TAGS = true; + var regExp = new RegExp('([0-9]+)\.([0-9]+)\.(.+)'); + if (versionStr.match(regExp)) { + var versionInfo = regExp.exec(versionStr); + var major = versionInfo[1]; + var minor = versionInfo[2]; + if (major == 0 && minor < 17) { + this.QUERY_POST_ENDPOINTS = false; + } + if (major == 0 && minor < 20) { + this.QUERY_BY_TAGS = false; + } + } +}; +//# sourceMappingURL=capabilities.js.map diff --git a/dist/test/capabilities.js.map b/dist/test/capabilities.js.map new file mode 100644 index 0000000..2246731 --- /dev/null +++ b/dist/test/capabilities.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/capabilities.js"],"names":[],"mappings":";;;;;;;;IAAa,Y,WAAA,Y,GAEX,sBAAY,UAAZ,EAAwB;AAAA;;AACtB,OAAK,oBAAL,GAA4B,IAA5B;AACA,OAAK,aAAL,GAAqB,IAArB;AACA,MAAI,SAAS,IAAI,MAAJ,CAAW,0BAAX,CAAb;AACA,MAAI,WAAW,KAAX,CAAiB,MAAjB,CAAJ,EAA8B;AAC5B,QAAI,cAAc,OAAO,IAAP,CAAY,UAAZ,CAAlB;AACA,QAAI,QAAQ,YAAY,CAAZ,CAAZ;AACA,QAAI,QAAQ,YAAY,CAAZ,CAAZ;AACA,QAAI,SAAS,CAAT,IAAc,QAAQ,EAA1B,EAA8B;AAC5B,WAAK,oBAAL,GAA4B,KAA5B;AACD;AACD,QAAI,SAAS,CAAT,IAAc,QAAQ,EAA1B,EAA8B;AAC5B,WAAK,aAAL,GAAqB,KAArB;AACD;AACF;AACF,C","file":"capabilities.js","sourcesContent":["export class Capabilities {\n\n constructor(versionStr) {\n this.QUERY_POST_ENDPOINTS = true;\n this.QUERY_BY_TAGS = true;\n let regExp = new RegExp('([0-9]+)\\.([0-9]+)\\.(.+)');\n if (versionStr.match(regExp)) {\n let versionInfo = regExp.exec(versionStr);\n let major = versionInfo[1];\n let minor = versionInfo[2];\n if (major == 0 && minor < 17) {\n this.QUERY_POST_ENDPOINTS = false;\n }\n if (major == 0 && minor < 20) {\n this.QUERY_BY_TAGS = false;\n }\n }\n }\n}\n"]} \ No newline at end of file diff --git a/dist/test/datasource.js b/dist/test/datasource.js new file mode 100644 index 0000000..6ebe767 --- /dev/null +++ b/dist/test/datasource.js @@ -0,0 +1,202 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.HawkularDatasource = undefined; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _lodash = require('lodash'); + +var _lodash2 = _interopRequireDefault(_lodash); + +var _variables = require('./variables'); + +var _capabilities = require('./capabilities'); + +var _queryProcessor = require('./queryProcessor'); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var HawkularDatasource = exports.HawkularDatasource = function () { + function HawkularDatasource(instanceSettings, $q, backendSrv, templateSrv) { + _classCallCheck(this, HawkularDatasource); + + this.type = instanceSettings.type; + this.url = instanceSettings.url; + this.name = instanceSettings.name; + this.tenant = instanceSettings.jsonData.tenant; + this.token = instanceSettings.jsonData.token; + this.q = $q; + this.backendSrv = backendSrv; + var variables = new _variables.Variables(templateSrv); + this.capabilitiesPromise = this.queryVersion().then(function (version) { + return new _capabilities.Capabilities(version); + }); + this.queryProcessor = new _queryProcessor.QueryProcessor($q, backendSrv, variables, this.capabilitiesPromise, this.url, this.createHeaders()); + } + + _createClass(HawkularDatasource, [{ + key: 'query', + value: function query(options) { + var _this = this; + + var validTargets = options.targets.filter(function (target) { + return !target.hide; + }).filter(function (target) { + return target.target !== 'select metric'; + }); + + if (validTargets.length === 0) { + return this.q.when({ data: [] }); + } + + var promises = validTargets.map(function (target) { + return _this.queryProcessor.run(target, options); + }); + + return this.q.all(promises).then(function (responses) { + var flatten = [].concat.apply([], responses); + return { data: flatten }; + }); + } + }, { + key: 'createHeaders', + value: function createHeaders() { + var headers = { + 'Content-Type': 'application/json', + 'Hawkular-Tenant': this.tenant + }; + if (typeof this.token === 'string' && this.token.length > 0) { + headers.Authorization = 'Bearer ' + this.token; + } + return headers; + } + }, { + key: 'testDatasource', + value: function testDatasource() { + return this.backendSrv.datasourceRequest({ + url: this.url + '/status', + method: 'GET' + }).then(function (response) { + if (response.status === 200) { + return { status: "success", message: "Data source is working", title: "Success" }; + } + }); + } + }, { + key: 'annotationQuery', + value: function annotationQuery(options) { + return this.backendSrv.datasourceRequest({ + url: this.url + '/annotations', + method: 'POST', + data: options + }).then(function (result) { + return result.data; + }); + } + }, { + key: 'suggestQueries', + value: function suggestQueries(target) { + return this.backendSrv.datasourceRequest({ + url: this.url + '/metrics?type=' + target.type, + method: 'GET', + headers: this.createHeaders() + }).then(function (result) { + return _lodash2.default.map(result.data, function (metric) { + return { text: metric.id, value: metric.id }; + }); + }); + } + }, { + key: 'suggestTags', + value: function suggestTags(type, key) { + if (!key) { + // Need at least some characters typed in order to suggest something + return this.q.when([]); + } + return this.backendSrv.datasourceRequest({ + url: this.url + '/' + type + 's/tags/' + key + ':*', + method: 'GET', + headers: this.createHeaders() + }).then(function (result) { + if (result.data.hasOwnProperty(key)) { + return [' *'].concat(result.data[key]).map(function (value) { + return { text: value, value: value }; + }); + } + return []; + }); + } + }, { + key: 'metricFindQuery', + value: function metricFindQuery(query) { + var params = ""; + if (query !== undefined) { + if (query.startsWith("tags/")) { + return this.findTags(query.substr(5).trim()); + } + if (query.startsWith("?")) { + params = query; + } else { + params = "?" + query; + } + } + return this.backendSrv.datasourceRequest({ + url: this.url + '/metrics' + params, + method: 'GET', + headers: this.createHeaders() + }).then(function (result) { + return _lodash2.default.map(result.data, function (metric) { + return { text: metric.id, value: metric.id }; + }); + }); + } + }, { + key: 'findTags', + value: function findTags(pattern) { + return this.backendSrv.datasourceRequest({ + url: this.url + '/metrics/tags/' + pattern, + method: 'GET', + headers: this.createHeaders() + }).then(function (result) { + var flatTags = []; + if (result.data) { + var data = result.data; + for (var property in data) { + if (data.hasOwnProperty(property)) { + flatTags = flatTags.concat(data[property]); + } + } + } + return flatTags.map(function (tag) { + return { text: tag, value: tag }; + }); + }); + } + }, { + key: 'queryVersion', + value: function queryVersion() { + return this.backendSrv.datasourceRequest({ + url: this.url + '/status', + method: 'GET', + headers: { 'Content-Type': 'application/json' } + }).then(function (response) { + return response.data['Implementation-Version']; + }).catch(function (response) { + return "Unknown"; + }); + } + }, { + key: 'getCapabilities', + value: function getCapabilities() { + return this.capabilitiesPromise; + } + }]); + + return HawkularDatasource; +}(); +//# sourceMappingURL=datasource.js.map diff --git a/dist/test/datasource.js.map b/dist/test/datasource.js.map new file mode 100644 index 0000000..c0f4811 --- /dev/null +++ b/dist/test/datasource.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/datasource.js"],"names":[],"mappings":"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","file":"datasource.js","sourcesContent":["import _ from \"lodash\";\nimport {Variables} from './variables';\nimport {Capabilities} from './capabilities';\nimport {QueryProcessor} from './queryProcessor';\n\nexport class HawkularDatasource {\n\n constructor(instanceSettings, $q, backendSrv, templateSrv) {\n this.type = instanceSettings.type;\n this.url = instanceSettings.url;\n this.name = instanceSettings.name;\n this.tenant = instanceSettings.jsonData.tenant;\n this.token = instanceSettings.jsonData.token;\n this.q = $q;\n this.backendSrv = backendSrv;\n let variables = new Variables(templateSrv);\n this.capabilitiesPromise = this.queryVersion()\n .then(version => new Capabilities(version));\n this.queryProcessor = new QueryProcessor($q, backendSrv, variables, this.capabilitiesPromise, this.url, this.createHeaders());\n }\n\n query(options) {\n let validTargets = options.targets\n .filter(target => !target.hide)\n .filter(target => target.target !== 'select metric');\n\n if (validTargets.length === 0) {\n return this.q.when({data: []});\n }\n\n let promises = validTargets.map(target => {\n return this.queryProcessor.run(target, options);\n });\n\n return this.q.all(promises).then(responses => {\n let flatten = [].concat.apply([], responses);\n return {data: flatten};\n });\n }\n\n createHeaders() {\n var headers = {\n 'Content-Type': 'application/json',\n 'Hawkular-Tenant': this.tenant\n };\n if (typeof this.token === 'string' && this.token.length > 0) {\n headers.Authorization = 'Bearer ' + this.token;\n }\n return headers;\n }\n\n testDatasource() {\n return this.backendSrv.datasourceRequest({\n url: this.url + '/status',\n method: 'GET'\n }).then(response => {\n if (response.status === 200) {\n return { status: \"success\", message: \"Data source is working\", title: \"Success\" };\n }\n });\n }\n\n annotationQuery(options) {\n return this.backendSrv.datasourceRequest({\n url: this.url + '/annotations',\n method: 'POST',\n data: options\n }).then(result => {\n return result.data;\n });\n }\n\n suggestQueries(target) {\n return this.backendSrv.datasourceRequest({\n url: this.url + '/metrics?type=' + target.type,\n method: 'GET',\n headers: this.createHeaders()\n }).then(result => {\n return _.map(result.data, metric => {\n return {text: metric.id, value: metric.id};\n });\n });\n }\n\n suggestTags(type, key) {\n if (!key) {\n // Need at least some characters typed in order to suggest something\n return this.q.when([]);\n }\n return this.backendSrv.datasourceRequest({\n url: this.url + '/' + type + 's/tags/' + key + ':*',\n method: 'GET',\n headers: this.createHeaders()\n }).then(result => {\n if (result.data.hasOwnProperty(key)) {\n return [' *'].concat(result.data[key]).map(value => {\n return {text: value, value: value};\n });\n }\n return [];\n });\n }\n\n metricFindQuery(query) {\n var params = \"\";\n if (query !== undefined) {\n if (query.startsWith(\"tags/\")) {\n return this.findTags(query.substr(5).trim());\n }\n if (query.startsWith(\"?\")) {\n params = query;\n } else {\n params = \"?\" + query;\n }\n }\n return this.backendSrv.datasourceRequest({\n url: this.url + '/metrics' + params,\n method: 'GET',\n headers: this.createHeaders()\n }).then(result => {\n return _.map(result.data, metric => {\n return {text: metric.id, value: metric.id};\n });\n });\n }\n\n findTags(pattern) {\n return this.backendSrv.datasourceRequest({\n url: this.url + '/metrics/tags/' + pattern,\n method: 'GET',\n headers: this.createHeaders()\n }).then(result => {\n var flatTags = [];\n if (result.data) {\n var data = result.data;\n for (var property in data) {\n if (data.hasOwnProperty(property)) {\n flatTags = flatTags.concat(data[property]);\n }\n }\n }\n return flatTags.map(tag => {\n return {text: tag, value: tag};\n });\n });\n }\n\n queryVersion() {\n return this.backendSrv.datasourceRequest({\n url: this.url + '/status',\n method: 'GET',\n headers: {'Content-Type': 'application/json'}\n }).then(response => response.data['Implementation-Version'])\n .catch(response => \"Unknown\");\n }\n\n getCapabilities() {\n return this.capabilitiesPromise;\n }\n}\n"]} \ No newline at end of file diff --git a/dist/test/module.js b/dist/test/module.js new file mode 100644 index 0000000..e91c7cb --- /dev/null +++ b/dist/test/module.js @@ -0,0 +1,37 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.AnnotationsQueryCtrl = exports.QueryOptionsCtrl = exports.ConfigCtrl = exports.QueryCtrl = exports.Datasource = undefined; + +var _datasource = require('./datasource'); + +var _query_ctrl = require('./query_ctrl'); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var HawkularConfigCtrl = function HawkularConfigCtrl() { + _classCallCheck(this, HawkularConfigCtrl); +}; + +HawkularConfigCtrl.templateUrl = 'partials/config.html'; + +var HawkularQueryOptionsCtrl = function HawkularQueryOptionsCtrl() { + _classCallCheck(this, HawkularQueryOptionsCtrl); +}; + +HawkularQueryOptionsCtrl.templateUrl = 'partials/query.options.html'; + +var HawkularAnnotationsQueryCtrl = function HawkularAnnotationsQueryCtrl() { + _classCallCheck(this, HawkularAnnotationsQueryCtrl); +}; + +HawkularAnnotationsQueryCtrl.templateUrl = 'partials/annotations.editor.html'; + +exports.Datasource = _datasource.HawkularDatasource; +exports.QueryCtrl = _query_ctrl.HawkularDatasourceQueryCtrl; +exports.ConfigCtrl = HawkularConfigCtrl; +exports.QueryOptionsCtrl = HawkularQueryOptionsCtrl; +exports.AnnotationsQueryCtrl = HawkularAnnotationsQueryCtrl; +//# sourceMappingURL=module.js.map diff --git a/dist/test/module.js.map b/dist/test/module.js.map new file mode 100644 index 0000000..b2ee928 --- /dev/null +++ b/dist/test/module.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/module.js"],"names":[],"mappings":";;;;;;;AAAA;;AACA;;;;IAEM,kB;;;;AACN,mBAAmB,WAAnB,GAAiC,sBAAjC;;IAEM,wB;;;;AACN,yBAAyB,WAAzB,GAAuC,6BAAvC;;IAEM,4B;;;;AACN,6BAA6B,WAA7B,GAA2C,kCAA3C;;QAGwB,U;QACS,S;QACT,U,GAAtB,kB;QAC4B,gB,GAA5B,wB;QACgC,oB,GAAhC,4B","file":"module.js","sourcesContent":["import {HawkularDatasource} from './datasource';\nimport {HawkularDatasourceQueryCtrl} from './query_ctrl';\n\nclass HawkularConfigCtrl {}\nHawkularConfigCtrl.templateUrl = 'partials/config.html';\n\nclass HawkularQueryOptionsCtrl {}\nHawkularQueryOptionsCtrl.templateUrl = 'partials/query.options.html';\n\nclass HawkularAnnotationsQueryCtrl {}\nHawkularAnnotationsQueryCtrl.templateUrl = 'partials/annotations.editor.html';\n\nexport {\n HawkularDatasource as Datasource,\n HawkularDatasourceQueryCtrl as QueryCtrl,\n HawkularConfigCtrl as ConfigCtrl,\n HawkularQueryOptionsCtrl as QueryOptionsCtrl,\n HawkularAnnotationsQueryCtrl as AnnotationsQueryCtrl\n};\n"]} \ No newline at end of file diff --git a/dist/test/queryProcessor.js b/dist/test/queryProcessor.js new file mode 100644 index 0000000..f0e8221 --- /dev/null +++ b/dist/test/queryProcessor.js @@ -0,0 +1,181 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var QueryProcessor = exports.QueryProcessor = function () { + function QueryProcessor(q, backendSrv, variables, capabilities, url, baseHeaders) { + _classCallCheck(this, QueryProcessor); + + this.q = q; + this.backendSrv = backendSrv; + this.variables = variables; + this.capabilities = capabilities; + this.url = url; + this.baseHeaders = baseHeaders; + } + + _createClass(QueryProcessor, [{ + key: 'run', + value: function run(target, options) { + var _this = this; + + return this.capabilities.then(function (caps) { + if (target.queryBy === 'ids') { + var metricIds = _this.variables.resolve(target.target, options); + if (caps.QUERY_POST_ENDPOINTS) { + return _this.rawQuery(target, options.range, metricIds); + } else { + return _this.rawQueryLegacy(target, options.range, metricIds); + } + } else { + if (target.tags.length === 0) { + return _this.q.when([]); + } + var strTags = _this.hawkularFormatTags(target.tags, options); + return _this.rawQueryByTags(target, options.range, strTags); + } + }); + } + }, { + key: 'hawkularFormatTags', + value: function hawkularFormatTags(tags, options) { + var _this2 = this; + + return tags.map(function (tag) { + var value; + if (tag.value === ' *') { + // '*' character get a special treatment in grafana so we had to use ' *' instead + value = '*'; + } else { + value = _this2.variables.resolve(tag.value, options).join('|'); + } + return tag.name + ':' + value; + }).join(','); + } + }, { + key: 'rawQuery', + value: function rawQuery(target, range, metricIds) { + var _this3 = this; + + var uri = [target.type + 's', // gauges or counters + target.rate ? 'rate' : 'raw', // raw or rate + 'query']; + var url = this.url + '/' + uri.join('/'); + + return this.backendSrv.datasourceRequest({ + url: url, + data: { + ids: metricIds, + start: range.from.valueOf(), + end: range.to.valueOf(), + order: 'ASC' + }, + method: 'POST', + headers: this.baseHeaders + }).then(function (response) { + return _this3.processRawResponse(target, response.status == 200 ? response.data : []); + }); + } + }, { + key: 'rawQueryLegacy', + value: function rawQueryLegacy(target, range, metricIds) { + var _this4 = this; + + return this.q.all(metricIds.map(function (metric) { + var uri = [target.type + 's', // gauges or counters + encodeURIComponent(metric).replace('+', '%20'), // metric name + 'data']; + var url = _this4.url + '/' + uri.join('/'); + + return _this4.backendSrv.datasourceRequest({ + url: url, + params: { + start: range.from.valueOf(), + end: range.to.valueOf() + }, + method: 'GET', + headers: _this4.baseHeaders + }).then(function (response) { + return _this4.processRawResponseLegacy(target, metric, response.status == 200 ? response.data : []); + }); + })); + } + }, { + key: 'rawQueryByTags', + value: function rawQueryByTags(target, range, tags) { + var _this5 = this; + + var uri = [target.type + 's', // gauges or counters + target.rate ? 'rate' : 'raw', // raw or rate + 'query']; + var url = this.url + '/' + uri.join('/'); + + return this.backendSrv.datasourceRequest({ + url: url, + data: { + tags: tags, + start: range.from.valueOf(), + end: range.to.valueOf(), + order: 'ASC' + }, + method: 'POST', + headers: this.baseHeaders + }).then(function (response) { + return _this5.processRawResponse(target, response.status == 200 ? response.data : []); + }); + } + }, { + key: 'processRawResponse', + value: function processRawResponse(target, data) { + return data.map(function (timeSerie) { + return { + refId: target.refId, + target: timeSerie.id, + datapoints: timeSerie.data.map(function (point) { + return [point.value, point.timestamp]; + }) + }; + }); + } + }, { + key: 'processRawResponseLegacy', + value: function processRawResponseLegacy(target, metric, data) { + var datapoints; + if (!target.rate) { + datapoints = _.map(data, function (point) { + return [point.value, point.timestamp]; + }); + } else { + var sortedData = data.sort(function (p1, p2) { + return p1.timestamp - p2.timestamp; + }); + datapoints = _.chain(sortedData).zip(sortedData.slice(1)).filter(function (pair) { + return pair[1] // Exclude the last pair + && (target.type == 'gauge' || pair[0].value <= pair[1].value); // Exclude counter resets + }).map(function (pair) { + var point1 = pair[0], + point2 = pair[1]; + var timestamp = point2.timestamp; + var value_diff = point2.value - point1.value; + var time_diff = point2.timestamp - point1.timestamp; + var rate = 60000 * value_diff / time_diff; + return [rate, timestamp]; + }).value(); + } + return { + refId: target.refId, + target: metric, + datapoints: datapoints + }; + } + }]); + + return QueryProcessor; +}(); +//# sourceMappingURL=queryProcessor.js.map diff --git a/dist/test/queryProcessor.js.map b/dist/test/queryProcessor.js.map new file mode 100644 index 0000000..ad6e97f --- /dev/null +++ b/dist/test/queryProcessor.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/queryProcessor.js"],"names":[],"mappings":"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","file":"queryProcessor.js","sourcesContent":["export class QueryProcessor {\n\n constructor(q, backendSrv, variables, capabilities, url, baseHeaders) {\n this.q = q;\n this.backendSrv = backendSrv;\n this.variables = variables;\n this.capabilities = capabilities;\n this.url = url;\n this.baseHeaders = baseHeaders;\n }\n\n run(target, options) {\n return this.capabilities.then(caps => {\n if (target.queryBy === 'ids') {\n let metricIds = this.variables.resolve(target.target, options);\n if (caps.QUERY_POST_ENDPOINTS) {\n return this.rawQuery(target, options.range, metricIds);\n } else {\n return this.rawQueryLegacy(target, options.range, metricIds);\n }\n } else {\n if (target.tags.length === 0) {\n return this.q.when([]);\n }\n let strTags = this.hawkularFormatTags(target.tags, options);\n return this.rawQueryByTags(target, options.range, strTags);\n }\n });\n }\n\n hawkularFormatTags(tags, options) {\n return tags.map(tag => {\n var value;\n if (tag.value === ' *') {\n // '*' character get a special treatment in grafana so we had to use ' *' instead\n value = '*';\n } else {\n value = this.variables.resolve(tag.value, options).join('|');\n }\n return tag.name + ':' + value;\n }).join(',');\n }\n\n rawQuery(target, range, metricIds) {\n let uri = [\n target.type + 's', // gauges or counters\n target.rate ? 'rate' : 'raw', // raw or rate\n 'query'\n ];\n let url = this.url + '/' + uri.join('/');\n\n return this.backendSrv.datasourceRequest({\n url: url,\n data: {\n ids: metricIds,\n start: range.from.valueOf(),\n end: range.to.valueOf(),\n order: 'ASC'\n },\n method: 'POST',\n headers: this.baseHeaders\n }).then(response => this.processRawResponse(target, response.status == 200 ? response.data : []));\n }\n\n rawQueryLegacy(target, range, metricIds) {\n return this.q.all(metricIds.map(metric => {\n let uri = [\n target.type + 's', // gauges or counters\n encodeURIComponent(metric).replace('+', '%20'), // metric name\n 'data'];\n let url = this.url + '/' + uri.join('/');\n\n return this.backendSrv.datasourceRequest({\n url: url,\n params: {\n start: range.from.valueOf(),\n end: range.to.valueOf()\n },\n method: 'GET',\n headers: this.baseHeaders\n }).then(response => this.processRawResponseLegacy(target, metric, response.status == 200 ? response.data : []));\n }));\n }\n\n rawQueryByTags(target, range, tags) {\n let uri = [\n target.type + 's', // gauges or counters\n target.rate ? 'rate' : 'raw', // raw or rate\n 'query'\n ];\n let url = this.url + '/' + uri.join('/');\n\n return this.backendSrv.datasourceRequest({\n url: url,\n data: {\n tags: tags,\n start: range.from.valueOf(),\n end: range.to.valueOf(),\n order: 'ASC'\n },\n method: 'POST',\n headers: this.baseHeaders\n }).then(response => this.processRawResponse(target, response.status == 200 ? response.data : []));\n }\n\n processRawResponse(target, data) {\n return data.map(timeSerie => {\n return {\n refId: target.refId,\n target: timeSerie.id,\n datapoints: timeSerie.data.map(point => [point.value, point.timestamp])\n };\n });\n }\n\n processRawResponseLegacy(target, metric, data) {\n var datapoints;\n if (!target.rate) {\n datapoints = _.map(data, point => [point.value, point.timestamp]);\n } else {\n var sortedData = data.sort((p1, p2)=> p1.timestamp - p2.timestamp);\n datapoints = _.chain(sortedData)\n .zip(sortedData.slice(1))\n .filter(pair => {\n return pair[1] // Exclude the last pair\n && (target.type == 'gauge' || pair[0].value <= pair[1].value); // Exclude counter resets\n })\n .map(pair => {\n var point1 = pair[0], point2 = pair[1];\n var timestamp = point2.timestamp;\n var value_diff = point2.value - point1.value;\n var time_diff = point2.timestamp - point1.timestamp;\n var rate = 60000 * value_diff / time_diff;\n return [rate, timestamp];\n })\n .value();\n }\n return {\n refId: target.refId,\n target: metric,\n datapoints: datapoints\n };\n }\n}\n"]} \ No newline at end of file diff --git a/dist/test/query_ctrl.js b/dist/test/query_ctrl.js new file mode 100644 index 0000000..ca27a30 --- /dev/null +++ b/dist/test/query_ctrl.js @@ -0,0 +1,114 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.HawkularDatasourceQueryCtrl = undefined; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _sdk = require('app/plugins/sdk'); + +require('./css/query-editor.css!'); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var HawkularDatasourceQueryCtrl = exports.HawkularDatasourceQueryCtrl = function (_QueryCtrl) { + _inherits(HawkularDatasourceQueryCtrl, _QueryCtrl); + + function HawkularDatasourceQueryCtrl($scope, $injector, uiSegmentSrv, $q) { + _classCallCheck(this, HawkularDatasourceQueryCtrl); + + var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(HawkularDatasourceQueryCtrl).call(this, $scope, $injector)); + + _this.scope = $scope; + _this.uiSegmentSrv = uiSegmentSrv; + _this.$q = $q; + + _this.queryByTagCapability = false; + _this.datasource.getCapabilities().then(function (caps) { + _this.queryByTagCapability = caps.QUERY_BY_TAGS; + }); + + _this.listQueryBy = [{ value: 'ids', text: 'Search by name' }, { value: 'tags', text: 'Search by tags' }]; + _this.metricTypes = [{ value: 'gauge', text: 'Gauge' }, { value: 'counter', text: 'Counter' }]; + + _this.target.queryBy = _this.target.queryBy || _this.listQueryBy[0].value; + _this.target.type = _this.target.type || _this.metricTypes[0].value; + _this.target.target = _this.target.target || 'select metric'; + _this.target.rate = _this.target.rate === true; + _this.target.tags = _this.target.tags || []; + + _this.tagsSegments = _.reduce(_this.target.tags, function (list, tag) { + list.push(uiSegmentSrv.newKey(tag.name)); + list.push(uiSegmentSrv.newOperator(':')); + list.push(uiSegmentSrv.newKeyValue(tag.value)); + list.push(uiSegmentSrv.newOperator(',')); + return list; + }, []); + _this.tagsSegments.push(uiSegmentSrv.newPlusButton()); + _this.removeTagsSegment = uiSegmentSrv.newSegment({ fake: true, value: '-- Remove tag --' }); + return _this; + } + + _createClass(HawkularDatasourceQueryCtrl, [{ + key: 'getTagsSegments', + value: function getTagsSegments(segment, $index) { + if (segment.type === 'plus-button') { + return this.$q.when([]); + } else if (segment.type === 'key') { + return this.$q.when([angular.copy(this.removeTagsSegment)]); + } else if (segment.type === 'value') { + var key = this.tagsSegments[$index - 2].value; + return this.datasource.suggestTags(this.target.type, key).then(this.uiSegmentSrv.transformToSegments(false)); + } + } + }, { + key: 'tagsSegmentChanged', + value: function tagsSegmentChanged(segment, index) { + if (segment.value === this.removeTagsSegment.value) { + this.tagsSegments.splice(index, 4); + } else if (segment.type === 'plus-button') { + this.tagsSegments.splice(index, 1, this.uiSegmentSrv.newOperator(',')); + this.tagsSegments.splice(index, 0, this.uiSegmentSrv.newKeyValue(' *')); + this.tagsSegments.splice(index, 0, this.uiSegmentSrv.newOperator(':')); + this.tagsSegments.splice(index, 0, this.uiSegmentSrv.newKey(segment.value)); + this.tagsSegments.push(this.uiSegmentSrv.newPlusButton()); + } else { + this.tagsSegments[index] = segment; + } + this.tagsToModel(); + this.onChangeInternal(); + } + }, { + key: 'tagsToModel', + value: function tagsToModel() { + this.target.tags = []; + for (var i = 0; i < this.tagsSegments.length - 2; i += 4) { + var key = this.tagsSegments[i].value; + var val = this.tagsSegments[i + 2].fake ? '*' : this.tagsSegments[i + 2].value || '*'; + this.target.tags.push({ name: key, value: val }); + } + } + }, { + key: 'getOptions', + value: function getOptions() { + return this.datasource.suggestQueries(this.target).then(this.uiSegmentSrv.transformToSegments(false)); + // Options have to be transformed by uiSegmentSrv to be usable by metric-segment-model directive + } + }, { + key: 'onChangeInternal', + value: function onChangeInternal() { + this.panelCtrl.refresh(); // Asks the panel to refresh data. + } + }]); + + return HawkularDatasourceQueryCtrl; +}(_sdk.QueryCtrl); + +HawkularDatasourceQueryCtrl.templateUrl = 'partials/query.editor.html'; +//# sourceMappingURL=query_ctrl.js.map diff --git a/dist/test/query_ctrl.js.map b/dist/test/query_ctrl.js.map new file mode 100644 index 0000000..d4e04fc --- /dev/null +++ b/dist/test/query_ctrl.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/query_ctrl.js"],"names":[],"mappings":"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","file":"query_ctrl.js","sourcesContent":["import {QueryCtrl} from 'app/plugins/sdk';\nimport './css/query-editor.css!'\n\nexport class HawkularDatasourceQueryCtrl extends QueryCtrl {\n\n constructor($scope, $injector, uiSegmentSrv, $q) {\n super($scope, $injector);\n\n this.scope = $scope;\n this.uiSegmentSrv = uiSegmentSrv;\n this.$q = $q;\n\n this.queryByTagCapability = false;\n this.datasource.getCapabilities().then(caps => {\n this.queryByTagCapability = caps.QUERY_BY_TAGS;\n });\n\n this.listQueryBy = [\n {value: 'ids', text: 'Search by name'},\n {value: 'tags', text: 'Search by tags'}\n ];\n this.metricTypes = [\n {value: 'gauge', text: 'Gauge'},\n {value: 'counter', text: 'Counter'}\n ];\n\n this.target.queryBy = this.target.queryBy || this.listQueryBy[0].value;\n this.target.type = this.target.type || this.metricTypes[0].value;\n this.target.target = this.target.target || 'select metric';\n this.target.rate = this.target.rate === true;\n this.target.tags = this.target.tags || [];\n\n this.tagsSegments = _.reduce(this.target.tags, function(list, tag) {\n list.push(uiSegmentSrv.newKey(tag.name));\n list.push(uiSegmentSrv.newOperator(':'));\n list.push(uiSegmentSrv.newKeyValue(tag.value));\n list.push(uiSegmentSrv.newOperator(','));\n return list;\n }, []);\n this.tagsSegments.push(uiSegmentSrv.newPlusButton());\n this.removeTagsSegment = uiSegmentSrv.newSegment({fake: true, value: '-- Remove tag --'});\n }\n\n getTagsSegments(segment, $index) {\n if (segment.type === 'plus-button') {\n return this.$q.when([]);\n } else if (segment.type === 'key') {\n return this.$q.when([angular.copy(this.removeTagsSegment)]);\n } else if (segment.type === 'value') {\n var key = this.tagsSegments[$index-2].value;\n return this.datasource.suggestTags(this.target.type, key)\n .then(this.uiSegmentSrv.transformToSegments(false));\n }\n }\n\n tagsSegmentChanged(segment, index) {\n if (segment.value === this.removeTagsSegment.value) {\n this.tagsSegments.splice(index, 4);\n } else if (segment.type === 'plus-button') {\n this.tagsSegments.splice(index, 1, this.uiSegmentSrv.newOperator(','));\n this.tagsSegments.splice(index, 0, this.uiSegmentSrv.newKeyValue(' *'));\n this.tagsSegments.splice(index, 0, this.uiSegmentSrv.newOperator(':'));\n this.tagsSegments.splice(index, 0, this.uiSegmentSrv.newKey(segment.value));\n this.tagsSegments.push(this.uiSegmentSrv.newPlusButton());\n } else {\n this.tagsSegments[index] = segment;\n }\n this.tagsToModel();\n this.onChangeInternal();\n }\n\n tagsToModel() {\n this.target.tags = [];\n for (var i = 0; i < this.tagsSegments.length - 2; i += 4) {\n let key = this.tagsSegments[i].value;\n let val = this.tagsSegments[i+2].fake ? '*' : (this.tagsSegments[i+2].value || '*');\n this.target.tags.push({name: key, value: val});\n }\n }\n\n getOptions() {\n return this.datasource.suggestQueries(this.target)\n .then(this.uiSegmentSrv.transformToSegments(false));\n // Options have to be transformed by uiSegmentSrv to be usable by metric-segment-model directive\n }\n\n onChangeInternal() {\n this.panelCtrl.refresh(); // Asks the panel to refresh data.\n }\n}\n\nHawkularDatasourceQueryCtrl.templateUrl = 'partials/query.editor.html';\n"]} \ No newline at end of file diff --git a/dist/test/spec/datasource_spec.js b/dist/test/spec/datasource_spec.js new file mode 100644 index 0000000..7bf71fc --- /dev/null +++ b/dist/test/spec/datasource_spec.js @@ -0,0 +1,200 @@ +"use strict"; + +var _module = require("../module"); + +var _q = require("q"); + +var _q2 = _interopRequireDefault(_q); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +describe('HawkularDatasource', function () { + var ctx = {}; + var hProtocol = 'https'; + var hHostname = 'test.com'; + var hPort = '876'; + var hPath = 'hawkular/metrics'; + var instanceSettings = { + url: hProtocol + '://' + hHostname + ':' + hPort + '/' + hPath, + jsonData: { + tenant: 'test-tenant' + } + }; + + var parsePathElements = function parsePathElements(request) { + expect(request.method).to.equal('POST'); + expect(request.headers).to.have.property('Hawkular-Tenant', instanceSettings.jsonData.tenant); + + var parser = document.createElement('a'); + parser.href = request.url; + + expect(parser).to.have.property('protocol', hProtocol + ':'); + expect(parser).to.have.property('hostname', hHostname); + expect(parser).to.have.property('port', hPort); + expect(parser).to.have.property('pathname'); + + return parser.pathname.split('/').filter(function (e) { + return e.length != 0; + }); + }; + + beforeEach(function () { + ctx.$q = _q2.default; + ctx.backendSrv = {}; + ctx.backendSrv.datasourceRequest = function (request) { + return ctx.$q.when({ data: { 'Implementation-Version': '1.0.0' } }); + }; + ctx.templateSrv = { + replace: function replace(target, vars) { + return target; + } + }; + ctx.ds = new _module.Datasource(instanceSettings, ctx.$q, ctx.backendSrv, ctx.templateSrv); + }); + + it('should return an empty array when no targets are set', function (done) { + ctx.ds.query({ targets: [] }).then(function (result) { + expect(result).to.have.property('data').with.length(0); + }).then(function (v) { + return done(); + }, function (err) { + return done(err); + }); + }); + + it('should return the server results when a target is set', function (done) { + + var options = { + range: { + from: 15, + to: 30 + }, + targets: [{ + target: 'memory', + type: 'gauge', + rate: false, + queryBy: 'ids' + }, { + target: 'packets', + type: 'counter', + rate: true, + queryBy: 'ids' + }] + }; + + ctx.backendSrv.datasourceRequest = function (request) { + var pathElements = parsePathElements(request); + var id = pathElements[2] == 'gauges' ? 'memory' : 'packets'; + + expect(pathElements).to.have.length(5); + expect(pathElements.slice(0, 2)).to.deep.equal(hPath.split('/')); + expect(pathElements[2]).to.be.oneOf(['gauges', 'counters']); + if (pathElements[2] == 'gauges') { + expect(pathElements.slice(3)).to.deep.equal(['raw', 'query']); + expect(request.data).to.deep.equal({ + start: options.range.from, + end: options.range.to, + ids: [id], + order: 'ASC' + }); + } else { + expect(pathElements.slice(3)).to.deep.equal(['rate', 'query']); + expect(request.data).to.deep.equal({ + start: options.range.from, + end: options.range.to, + ids: [id], + order: 'ASC' + }); + } + + return ctx.$q.when({ + status: 200, + data: [{ + id: id, + data: [{ + timestamp: 13, + value: 15 + }, { + timestamp: 19, + value: 21 + }] + }] + }); + }; + + ctx.ds.query(options).then(function (result) { + expect(result.data).to.have.length(2); + expect(result.data.map(function (t) { + return t.target; + })).to.include.members(['memory', 'packets']); + expect(result.data[0].datapoints).to.deep.equal([[15, 13], [21, 19]]); + expect(result.data[1].datapoints).to.deep.equal([[15, 13], [21, 19]]); + }).then(function (v) { + return done(); + }, function (err) { + return done(err); + }); + }); + + it('should return multiple results with templated target', function (done) { + + var options = { + range: { + from: 15, + to: 30 + }, + targets: [{ + target: '$app/memory', + type: 'gauge', + rate: false, + queryBy: 'ids' + }] + }; + + ctx.templateSrv.replace = function (target, vars) { + expect(target).to.equal('$app'); + return "{app_1,app_2}"; + }; + + ctx.backendSrv.datasourceRequest = function (request) { + expect(request.url).to.have.string("/gauges/raw/query"); + expect(request.data.ids).to.include.members(['app_1/memory', 'app_2/memory']); + return ctx.$q.when({ + status: 200, + data: [{ + id: "app_1/memory", + data: [{ + timestamp: 13, + value: 15 + }, { + timestamp: 19, + value: 21 + }] + }, { + id: "app_2/memory", + data: [{ + timestamp: 13, + value: 28 + }, { + timestamp: 19, + value: 32 + }] + }] + }); + }; + + ctx.ds.query(options).then(function (result) { + expect(result.data).to.have.length(2); + expect(result.data.map(function (t) { + return t.target; + })).to.include.members(['app_1/memory', 'app_2/memory']); + expect(result.data[0].datapoints).to.deep.equal([[15, 13], [21, 19]]); + expect(result.data[1].datapoints).to.deep.equal([[28, 13], [32, 19]]); + }).then(function (v) { + return done(); + }, function (err) { + return done(err); + }); + }); +}); +//# sourceMappingURL=datasource_spec.js.map diff --git a/dist/test/spec/datasource_spec.js.map b/dist/test/spec/datasource_spec.js.map new file mode 100644 index 0000000..91e524c --- /dev/null +++ b/dist/test/spec/datasource_spec.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../../spec/datasource_spec.js"],"names":[],"mappings":"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","file":"datasource_spec.js","sourcesContent":["import {Datasource} from \"../module\";\nimport Q from \"q\";\n\ndescribe('HawkularDatasource', function () {\n var ctx = {};\n var hProtocol = 'https';\n var hHostname = 'test.com';\n var hPort = '876';\n var hPath = 'hawkular/metrics';\n var instanceSettings = {\n url: hProtocol + '://' + hHostname + ':' + hPort + '/' + hPath,\n jsonData: {\n tenant: 'test-tenant'\n }\n };\n\n var parsePathElements = function(request) {\n expect(request.method).to.equal('POST');\n expect(request.headers).to.have.property('Hawkular-Tenant', instanceSettings.jsonData.tenant);\n\n var parser = document.createElement('a');\n parser.href = request.url;\n\n expect(parser).to.have.property('protocol', hProtocol + ':');\n expect(parser).to.have.property('hostname', hHostname);\n expect(parser).to.have.property('port', hPort);\n expect(parser).to.have.property('pathname');\n\n return parser.pathname.split('/').filter(e => e.length != 0);\n }\n\n beforeEach(function () {\n ctx.$q = Q;\n ctx.backendSrv = {};\n ctx.backendSrv.datasourceRequest = function (request) {\n return ctx.$q.when({data: {'Implementation-Version': '1.0.0'}})\n };\n ctx.templateSrv = {\n replace: function(target, vars) {\n return target;\n }\n };\n ctx.ds = new Datasource(instanceSettings, ctx.$q, ctx.backendSrv, ctx.templateSrv);\n });\n\n it('should return an empty array when no targets are set', function (done) {\n ctx.ds.query({targets: []}).then(function (result) {\n expect(result).to.have.property('data').with.length(0);\n }).then(v => done(), err => done(err));\n });\n\n it('should return the server results when a target is set', function (done) {\n\n var options = {\n range: {\n from: 15,\n to: 30\n },\n targets: [{\n target: 'memory',\n type: 'gauge',\n rate: false,\n queryBy: 'ids'\n }, {\n target: 'packets',\n type: 'counter',\n rate: true,\n queryBy: 'ids'\n }]\n };\n\n ctx.backendSrv.datasourceRequest = function (request) {\n let pathElements = parsePathElements(request);\n var id = pathElements[2] == 'gauges' ? 'memory' : 'packets';\n\n expect(pathElements).to.have.length(5);\n expect(pathElements.slice(0, 2)).to.deep.equal(hPath.split('/'));\n expect(pathElements[2]).to.be.oneOf(['gauges', 'counters']);\n if (pathElements[2] == 'gauges') {\n expect(pathElements.slice(3)).to.deep.equal(['raw', 'query']);\n expect(request.data).to.deep.equal({\n start: options.range.from,\n end: options.range.to,\n ids: [id],\n order: 'ASC'\n });\n } else {\n expect(pathElements.slice(3)).to.deep.equal(['rate', 'query']);\n expect(request.data).to.deep.equal({\n start: options.range.from,\n end: options.range.to,\n ids: [id],\n order: 'ASC'\n });\n }\n\n return ctx.$q.when({\n status: 200,\n data: [{\n id: id,\n data: [{\n timestamp: 13,\n value: 15\n }, {\n timestamp: 19,\n value: 21\n }]\n }]\n });\n };\n\n ctx.ds.query(options).then(function (result) {\n expect(result.data).to.have.length(2);\n expect(result.data.map(t => t.target)).to.include.members(['memory', 'packets']);\n expect(result.data[0].datapoints).to.deep.equal([[15, 13], [21, 19]]);\n expect(result.data[1].datapoints).to.deep.equal([[15, 13], [21, 19]]);\n }).then(v => done(), err => done(err));\n });\n\n it('should return multiple results with templated target', function (done) {\n\n let options = {\n range: {\n from: 15,\n to: 30\n },\n targets: [{\n target: '$app/memory',\n type: 'gauge',\n rate: false,\n queryBy: 'ids'\n }]\n };\n\n ctx.templateSrv.replace = function(target, vars) {\n expect(target).to.equal('$app');\n return \"{app_1,app_2}\";\n };\n\n ctx.backendSrv.datasourceRequest = function(request) {\n expect(request.url).to.have.string(\"/gauges/raw/query\");\n expect(request.data.ids).to.include.members(['app_1/memory', 'app_2/memory']);\n return ctx.$q.when({\n status: 200,\n data: [{\n id: \"app_1/memory\",\n data: [{\n timestamp: 13,\n value: 15\n }, {\n timestamp: 19,\n value: 21\n }]\n },{\n id: \"app_2/memory\",\n data: [{\n timestamp: 13,\n value: 28\n }, {\n timestamp: 19,\n value: 32\n }]\n }]\n });\n };\n\n ctx.ds.query(options).then(function (result) {\n expect(result.data).to.have.length(2);\n expect(result.data.map(t => t.target)).to.include.members(['app_1/memory', 'app_2/memory']);\n expect(result.data[0].datapoints).to.deep.equal([[15, 13], [21, 19]]);\n expect(result.data[1].datapoints).to.deep.equal([[28, 13], [32, 19]]);\n }).then(v => done(), err => done(err));\n });\n});\n"]} \ No newline at end of file diff --git a/dist/test/spec/test-main.js b/dist/test/spec/test-main.js new file mode 100644 index 0000000..9af663a --- /dev/null +++ b/dist/test/spec/test-main.js @@ -0,0 +1,33 @@ +'use strict'; + +var _prunk = require('prunk'); + +var _prunk2 = _interopRequireDefault(_prunk); + +var _jsdom = require('jsdom'); + +var _chai = require('chai'); + +var _chai2 = _interopRequireDefault(_chai); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +// Mock Grafana modules that are not available outside of the core project +// Required for loading module.js +_prunk2.default.mock('./css/query-editor.css!', 'no css, dude.'); +_prunk2.default.mock('app/plugins/sdk', { + QueryCtrl: null +}); + +// Setup jsdom +// Required for loading angularjs +global.document = (0, _jsdom.jsdom)(''); +global.window = global.document.parentWindow; +global.navigator = window.navigator = {}; +global.Node = window.Node; + +// Setup Chai +_chai2.default.should(); +global.assert = _chai2.default.assert; +global.expect = _chai2.default.expect; +//# sourceMappingURL=test-main.js.map diff --git a/dist/test/spec/test-main.js.map b/dist/test/spec/test-main.js.map new file mode 100644 index 0000000..5946428 --- /dev/null +++ b/dist/test/spec/test-main.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../../spec/test-main.js"],"names":[],"mappings":";;AAAA;;;;AACA;;AACA;;;;;;AAEA;AACA;AACA,gBAAM,IAAN,CAAW,yBAAX,EAAsC,eAAtC;AACA,gBAAM,IAAN,CAAW,iBAAX,EAA8B;AAC1B,eAAW;AADe,CAA9B;;AAIA;AACA;AACA,OAAO,QAAP,GAAkB,kBAAM,0DAAN,CAAlB;AACA,OAAO,MAAP,GAAgB,OAAO,QAAP,CAAgB,YAAhC;AACA,OAAO,SAAP,GAAmB,OAAO,SAAP,GAAmB,EAAtC;AACA,OAAO,IAAP,GAAc,OAAO,IAArB;;AAEA;AACA,eAAK,MAAL;AACA,OAAO,MAAP,GAAgB,eAAK,MAArB;AACA,OAAO,MAAP,GAAgB,eAAK,MAArB","file":"test-main.js","sourcesContent":["import prunk from 'prunk';\nimport {jsdom} from 'jsdom';\nimport chai from 'chai';\n\n// Mock Grafana modules that are not available outside of the core project\n// Required for loading module.js\nprunk.mock('./css/query-editor.css!', 'no css, dude.');\nprunk.mock('app/plugins/sdk', {\n QueryCtrl: null\n});\n\n// Setup jsdom\n// Required for loading angularjs\nglobal.document = jsdom('');\nglobal.window = global.document.parentWindow;\nglobal.navigator = window.navigator = {};\nglobal.Node = window.Node;\n\n// Setup Chai\nchai.should();\nglobal.assert = chai.assert;\nglobal.expect = chai.expect;\n"]} \ No newline at end of file diff --git a/dist/test/spec/variables_spec.js b/dist/test/spec/variables_spec.js new file mode 100644 index 0000000..21b1716 --- /dev/null +++ b/dist/test/spec/variables_spec.js @@ -0,0 +1,51 @@ +"use strict"; + +var _variables = require("../variables"); + +var _q = require("q"); + +var _q2 = _interopRequireDefault(_q); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +describe('Variables', function () { + var ctx = { + templateSrv: {}, + variables: {} + }; + + beforeEach(function () { + ctx.templateSrv = { + replace: function replace(target, vars) { + return target; + } + }; + ctx.variables = new _variables.Variables(ctx.templateSrv); + }); + + it('should resolve single variable', function (done) { + ctx.templateSrv.replace = function (target, vars) { + expect(target).to.equal('$app'); + return "{app_1,app_2}"; + }; + var resolved = ctx.variables.resolve("$app/memory/usage", {}); + expect(resolved).to.deep.equal(['app_1/memory/usage', 'app_2/memory/usage']); + done(); + }); + + it('should resolve multiple variables', function (done) { + ctx.templateSrv.replace = function (target, vars) { + if (target === '$app') { + return "{app_1,app_2}"; + } + if (target === '$container') { + return "{1234,5678,90}"; + } + return target; + }; + var resolved = ctx.variables.resolve("$app/$container/memory/usage", {}); + expect(resolved).to.deep.equal(['app_1/1234/memory/usage', 'app_2/1234/memory/usage', 'app_1/5678/memory/usage', 'app_2/5678/memory/usage', 'app_1/90/memory/usage', 'app_2/90/memory/usage']); + done(); + }); +}); +//# sourceMappingURL=variables_spec.js.map diff --git a/dist/test/spec/variables_spec.js.map b/dist/test/spec/variables_spec.js.map new file mode 100644 index 0000000..95db982 --- /dev/null +++ b/dist/test/spec/variables_spec.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../../spec/variables_spec.js"],"names":[],"mappings":";;AAAA;;AACA;;;;;;AAEA,SAAS,WAAT,EAAsB,YAAY;AAChC,MAAI,MAAM;AACR,iBAAa,EADL;AAER,eAAW;AAFH,GAAV;;AAKA,aAAW,YAAY;AACrB,QAAI,WAAJ,GAAkB;AACd,eAAS,iBAAS,MAAT,EAAiB,IAAjB,EAAuB;AAC9B,eAAO,MAAP;AACD;AAHa,KAAlB;AAKA,QAAI,SAAJ,GAAgB,yBAAc,IAAI,WAAlB,CAAhB;AACD,GAPD;;AASA,KAAG,gCAAH,EAAqC,UAAU,IAAV,EAAgB;AACnD,QAAI,WAAJ,CAAgB,OAAhB,GAA0B,UAAS,MAAT,EAAiB,IAAjB,EAAuB;AAC/C,aAAO,MAAP,EAAe,EAAf,CAAkB,KAAlB,CAAwB,MAAxB;AACA,aAAO,eAAP;AACD,KAHD;AAIA,QAAI,WAAW,IAAI,SAAJ,CAAc,OAAd,CAAsB,mBAAtB,EAA2C,EAA3C,CAAf;AACA,WAAO,QAAP,EAAiB,EAAjB,CAAoB,IAApB,CAAyB,KAAzB,CAA+B,CAAC,oBAAD,EAAuB,oBAAvB,CAA/B;AACA;AACD,GARD;;AAUA,KAAG,mCAAH,EAAwC,UAAU,IAAV,EAAgB;AACtD,QAAI,WAAJ,CAAgB,OAAhB,GAA0B,UAAS,MAAT,EAAiB,IAAjB,EAAuB;AAC/C,UAAI,WAAW,MAAf,EAAuB;AACrB,eAAO,eAAP;AACD;AACD,UAAI,WAAW,YAAf,EAA6B;AAC3B,eAAO,gBAAP;AACD;AACD,aAAO,MAAP;AACD,KARD;AASA,QAAI,WAAW,IAAI,SAAJ,CAAc,OAAd,CAAsB,8BAAtB,EAAsD,EAAtD,CAAf;AACA,WAAO,QAAP,EAAiB,EAAjB,CAAoB,IAApB,CAAyB,KAAzB,CAA+B,CAC7B,yBAD6B,EAE7B,yBAF6B,EAG7B,yBAH6B,EAI7B,yBAJ6B,EAK7B,uBAL6B,EAM7B,uBAN6B,CAA/B;AAQA;AACD,GApBD;AAqBD,CA9CD","file":"variables_spec.js","sourcesContent":["import {Variables} from \"../variables\";\nimport Q from \"q\";\n\ndescribe('Variables', function () {\n let ctx = {\n templateSrv: {},\n variables: {}\n };\n\n beforeEach(function () {\n ctx.templateSrv = {\n replace: function(target, vars) {\n return target;\n }\n };\n ctx.variables = new Variables(ctx.templateSrv);\n });\n\n it('should resolve single variable', function (done) {\n ctx.templateSrv.replace = function(target, vars) {\n expect(target).to.equal('$app');\n return \"{app_1,app_2}\";\n };\n let resolved = ctx.variables.resolve(\"$app/memory/usage\", {});\n expect(resolved).to.deep.equal(['app_1/memory/usage', 'app_2/memory/usage']);\n done();\n });\n\n it('should resolve multiple variables', function (done) {\n ctx.templateSrv.replace = function(target, vars) {\n if (target === '$app') {\n return \"{app_1,app_2}\";\n }\n if (target === '$container') {\n return \"{1234,5678,90}\";\n }\n return target;\n };\n let resolved = ctx.variables.resolve(\"$app/$container/memory/usage\", {});\n expect(resolved).to.deep.equal([\n 'app_1/1234/memory/usage',\n 'app_2/1234/memory/usage',\n 'app_1/5678/memory/usage',\n 'app_2/5678/memory/usage',\n 'app_1/90/memory/usage',\n 'app_2/90/memory/usage'\n ]);\n done();\n });\n});\n"]} \ No newline at end of file diff --git a/dist/test/variables.js b/dist/test/variables.js new file mode 100644 index 0000000..af8f04b --- /dev/null +++ b/dist/test/variables.js @@ -0,0 +1,55 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var Variables = exports.Variables = function () { + function Variables(templateSrv) { + _classCallCheck(this, Variables); + + this.templateSrv = templateSrv; + } + + _createClass(Variables, [{ + key: 'resolve', + value: function resolve(target, options) { + var _this = this; + + var variables = options.scopedVars || this.templateSrv.variables; + // For each variable in target, and each values of a given variable, build a resolved target string + var variableNames = target.match(/\$\w+/g); + var resolved = [target]; + if (variableNames) { + variableNames.forEach(function (name) { + var values = _this.getVarValues(name, variables); + var newResolved = []; + values.forEach(function (val) { + resolved.forEach(function (target) { + newResolved.push(target.replace(name, val)); + }); + }); + resolved = newResolved; + }); + } + return resolved; + } + }, { + key: 'getVarValues', + value: function getVarValues(name, variables) { + var values = this.templateSrv.replace(name, variables); + // result might be in like "{id1,id2,id3}" (as string) + if (values.startsWith('{')) { + return values.substring(1, values.length - 1).split(','); + } + return [values]; + } + }]); + + return Variables; +}(); +//# sourceMappingURL=variables.js.map diff --git a/dist/test/variables.js.map b/dist/test/variables.js.map new file mode 100644 index 0000000..272ab39 --- /dev/null +++ b/dist/test/variables.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/variables.js"],"names":[],"mappings":";;;;;;;;;;IAAa,S,WAAA,S;AAEX,qBAAY,WAAZ,EAAyB;AAAA;;AACvB,SAAK,WAAL,GAAmB,WAAnB;AACD;;;;4BAEO,M,EAAQ,O,EAAS;AAAA;;AACvB,UAAI,YAAY,QAAQ,UAAR,IAAsB,KAAK,WAAL,CAAiB,SAAvD;AACA;AACA,UAAI,gBAAgB,OAAO,KAAP,CAAa,QAAb,CAApB;AACA,UAAI,WAAW,CAAC,MAAD,CAAf;AACA,UAAI,aAAJ,EAAmB;AACjB,sBAAc,OAAd,CAAsB,gBAAQ;AAC5B,cAAI,SAAS,MAAK,YAAL,CAAkB,IAAlB,EAAwB,SAAxB,CAAb;AACA,cAAI,cAAc,EAAlB;AACA,iBAAO,OAAP,CAAe,eAAO;AACpB,qBAAS,OAAT,CAAiB,kBAAU;AACzB,0BAAY,IAAZ,CAAiB,OAAO,OAAP,CAAe,IAAf,EAAqB,GAArB,CAAjB;AACD,aAFD;AAGD,WAJD;AAKA,qBAAW,WAAX;AACD,SATD;AAUD;AACD,aAAO,QAAP;AACD;;;iCAEY,I,EAAM,S,EAAW;AAC5B,UAAI,SAAS,KAAK,WAAL,CAAiB,OAAjB,CAAyB,IAAzB,EAA+B,SAA/B,CAAb;AACA;AACA,UAAI,OAAO,UAAP,CAAkB,GAAlB,CAAJ,EAA4B;AACxB,eAAO,OAAO,SAAP,CAAiB,CAAjB,EAAoB,OAAO,MAAP,GAAc,CAAlC,EAAqC,KAArC,CAA2C,GAA3C,CAAP;AACH;AACD,aAAO,CAAC,MAAD,CAAP;AACD","file":"variables.js","sourcesContent":["export class Variables {\n\n constructor(templateSrv) {\n this.templateSrv = templateSrv;\n }\n\n resolve(target, options) {\n let variables = options.scopedVars || this.templateSrv.variables;\n // For each variable in target, and each values of a given variable, build a resolved target string\n let variableNames = target.match(/\\$\\w+/g);\n var resolved = [target];\n if (variableNames) {\n variableNames.forEach(name => {\n let values = this.getVarValues(name, variables);\n let newResolved = [];\n values.forEach(val => {\n resolved.forEach(target => {\n newResolved.push(target.replace(name, val));\n });\n });\n resolved = newResolved;\n });\n }\n return resolved;\n }\n\n getVarValues(name, variables) {\n let values = this.templateSrv.replace(name, variables);\n // result might be in like \"{id1,id2,id3}\" (as string)\n if (values.startsWith('{')) {\n return values.substring(1, values.length-1).split(',');\n }\n return [values];\n }\n}\n"]} \ No newline at end of file diff --git a/dist/variables.js b/dist/variables.js new file mode 100644 index 0000000..ac11b73 --- /dev/null +++ b/dist/variables.js @@ -0,0 +1,84 @@ +'use strict'; + +System.register([], function (_export, _context) { + "use strict"; + + var _createClass, Variables; + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + return { + setters: [], + execute: function () { + _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + _export('Variables', Variables = function () { + function Variables(templateSrv) { + _classCallCheck(this, Variables); + + this.templateSrv = templateSrv; + } + + _createClass(Variables, [{ + key: 'resolve', + value: function resolve(target, options) { + var _this = this; + + var variables = options.scopedVars || this.templateSrv.variables; + // For each variable in target, and each values of a given variable, build a resolved target string + var variableNames = target.match(/\$\w+/g); + var resolved = [target]; + if (variableNames) { + variableNames.forEach(function (name) { + var values = _this.getVarValues(name, variables); + var newResolved = []; + values.forEach(function (val) { + resolved.forEach(function (target) { + newResolved.push(target.replace(name, val)); + }); + }); + resolved = newResolved; + }); + } + return resolved; + } + }, { + key: 'getVarValues', + value: function getVarValues(name, variables) { + var values = this.templateSrv.replace(name, variables); + // result might be in like "{id1,id2,id3}" (as string) + if (values.startsWith('{')) { + return values.substring(1, values.length - 1).split(','); + } + return [values]; + } + }]); + + return Variables; + }()); + + _export('Variables', Variables); + } + }; +}); +//# sourceMappingURL=variables.js.map diff --git a/dist/variables.js.map b/dist/variables.js.map new file mode 100644 index 0000000..8e1b054 --- /dev/null +++ b/dist/variables.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../src/variables.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAAa,S;AAEX,2BAAY,WAAZ,EAAyB;AAAA;;AACvB,eAAK,WAAL,GAAmB,WAAnB;AACD;;;;kCAEO,M,EAAQ,O,EAAS;AAAA;;AACvB,gBAAI,YAAY,QAAQ,UAAR,IAAsB,KAAK,WAAL,CAAiB,SAAvD;AACA;AACA,gBAAI,gBAAgB,OAAO,KAAP,CAAa,QAAb,CAApB;AACA,gBAAI,WAAW,CAAC,MAAD,CAAf;AACA,gBAAI,aAAJ,EAAmB;AACjB,4BAAc,OAAd,CAAsB,gBAAQ;AAC5B,oBAAI,SAAS,MAAK,YAAL,CAAkB,IAAlB,EAAwB,SAAxB,CAAb;AACA,oBAAI,cAAc,EAAlB;AACA,uBAAO,OAAP,CAAe,eAAO;AACpB,2BAAS,OAAT,CAAiB,kBAAU;AACzB,gCAAY,IAAZ,CAAiB,OAAO,OAAP,CAAe,IAAf,EAAqB,GAArB,CAAjB;AACD,mBAFD;AAGD,iBAJD;AAKA,2BAAW,WAAX;AACD,eATD;AAUD;AACD,mBAAO,QAAP;AACD;;;uCAEY,I,EAAM,S,EAAW;AAC5B,gBAAI,SAAS,KAAK,WAAL,CAAiB,OAAjB,CAAyB,IAAzB,EAA+B,SAA/B,CAAb;AACA;AACA,gBAAI,OAAO,UAAP,CAAkB,GAAlB,CAAJ,EAA4B;AACxB,qBAAO,OAAO,SAAP,CAAiB,CAAjB,EAAoB,OAAO,MAAP,GAAc,CAAlC,EAAqC,KAArC,CAA2C,GAA3C,CAAP;AACH;AACD,mBAAO,CAAC,MAAD,CAAP;AACD","file":"variables.js","sourcesContent":["export class Variables {\n\n constructor(templateSrv) {\n this.templateSrv = templateSrv;\n }\n\n resolve(target, options) {\n let variables = options.scopedVars || this.templateSrv.variables;\n // For each variable in target, and each values of a given variable, build a resolved target string\n let variableNames = target.match(/\\$\\w+/g);\n var resolved = [target];\n if (variableNames) {\n variableNames.forEach(name => {\n let values = this.getVarValues(name, variables);\n let newResolved = [];\n values.forEach(val => {\n resolved.forEach(target => {\n newResolved.push(target.replace(name, val));\n });\n });\n resolved = newResolved;\n });\n }\n return resolved;\n }\n\n getVarValues(name, variables) {\n let values = this.templateSrv.replace(name, variables);\n // result might be in like \"{id1,id2,id3}\" (as string)\n if (values.startsWith('{')) {\n return values.substring(1, values.length-1).split(',');\n }\n return [values];\n }\n}\n"]} \ No newline at end of file