From c2f63006815eabf5acb1f5973ae919bea2e8273d Mon Sep 17 00:00:00 2001 From: Julia Shmeleva Date: Tue, 21 Jan 2020 13:51:54 -0800 Subject: [PATCH 1/3] add support of hard coded strings in template variables --- src/constants.js | 25 +++++++++---- src/datasource.js | 91 +++++++++++++++++++++++++++++++---------------- src/query_ctrl.js | 1 - 3 files changed, 80 insertions(+), 37 deletions(-) diff --git a/src/constants.js b/src/constants.js index d4a71c352..87edeca90 100644 --- a/src/constants.js +++ b/src/constants.js @@ -9,9 +9,22 @@ export const windows = ['1m', '5m', '1h'] export const environments = ['local', 'OCI Instance'] -export const compartmentsQueryRegex = /^compartments\(\)/; -export const regionsQueryRegex = /^regions\(\)/; -export const namespacesQueryRegex = /namespaces\((\$?\w+)(,\s*\$\w+)*\)/; -export const metricsQueryRegex = /metrics\((\s*\$?\w+)(\s*,\s*\$\w+)(\s*,\s*\$\w+\s*)*\)/; -export const dimensionKeysQueryRegex = /dimensions\((\s*\$?\w+)(\s*,\s*\$\w+)(\s*,\s*\$\w+)(\s*,\s*\$\w+\s*)*\)/; -export const dimensionValuesQueryRegex = /dimensionOptions\((\s*\$?\w+)(\s*,\s*\$\w+)(\s*,\s*\$\w+)(\s*,\s*\$\w+)(\s*,\s*\$\w+\s*)*\)/; \ No newline at end of file +export const compartmentsQueryRegex = /^compartments\(\)\s*/; +export const regionsQueryRegex = /^regions\(\)\s*/; +export const namespacesQueryRegex = /^namespaces\(\s*(\".+\"|\'.+\'|\$\w+)\s*,\s*(\".+\"|\'.+\'|\$\w+)\s*\)/; +export const metricsQueryRegex = /^metrics\(\s*(\".+\"|\'.+\'|\$\w+)\s*,\s*(\".+\"|\'.+\'|\$\w+)\s*,\s*(\".+\"|\'.+\'|\$\w+)\s*\)/; +export const dimensionKeysQueryRegex = /^dimensions\(\s*(\".+\"|\'.+\'|\$\w+)\s*,\s*(\".+\"|\'.+\'|\$\w+)\s*,\s*(\".+\"|\'.+\'|\$\w+)\s*,\s*(\".+\"|\'.+\'|\$\w+)\s*\)/; +export const dimensionValuesQueryRegex = /^dimensionOptions\(\s*(\".+\"|\'.+\'|\$\w+)\s*,\s*(\".+\"|\'.+\'|\$\w+)\s*,\s*(\".+\"|\'.+\'|\$\w+)\s*,\s*(\".+\"|\'.+\'|\$\w+)\s*,\s*(\".+\"|\'.+\'|\$\w+)\s*\)/; + +export const removeQuotes = str => { + if (!str) return str; + + let res = str; + if (str.startsWith("'") || str.startsWith('"')) { + res = res.slice(1); + } + if (str.endsWith("'") || str.endsWith('"')) { + res = res.slice(0, res.length - 1); + } + return res; +} \ No newline at end of file diff --git a/src/datasource.js b/src/datasource.js index e9e3c0969..0e7cc4e1e 100644 --- a/src/datasource.js +++ b/src/datasource.js @@ -3,7 +3,7 @@ ** Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. */ import _ from 'lodash' -import { aggregations, dimensionKeysQueryRegex, namespacesQueryRegex, metricsQueryRegex, regionsQueryRegex, compartmentsQueryRegex, dimensionValuesQueryRegex, adsQueryRegex } from './constants' +import { aggregations, dimensionKeysQueryRegex, namespacesQueryRegex, metricsQueryRegex, regionsQueryRegex, compartmentsQueryRegex, dimensionValuesQueryRegex, removeQuotes } from './constants' import retryOrThrow from './util/retry' import { SELECT_PLACEHOLDERS } from './query_ctrl' @@ -20,6 +20,12 @@ export default class OCIDatasource { this.backendSrv = backendSrv this.templateSrv = templateSrv this.timeSrv = timeSrv + + this.compartmentsCache = []; + this.regionsCache = []; + + this.getRegions(); + this.getCompartments(); } /** @@ -88,7 +94,7 @@ export default class OCIDatasource { * Required method * Used by query editor to get metric suggestions */ - metricFindQuery(target) { + async metricFindQuery(target) { if (typeof (target) === 'string') { // used in template editor for creating variables return this.templateMetricQuery(target); @@ -102,6 +108,7 @@ export default class OCIDatasource { return this.q.when([]); } + const compartmentId = await this.getCompartmentId(compartment); return this.doRequest({ targets: [{ environment: this.environment, @@ -109,7 +116,7 @@ export default class OCIDatasource { tenancyOCID: this.tenancyOCID, queryType: 'search', region: _.isEmpty(region) ? this.defaultRegion : region, - compartment: compartment, + compartment: compartmentId, namespace: namespace }], range: this.timeSrv.timeRange() @@ -282,8 +289,8 @@ export default class OCIDatasource { let namespaceQuery = varString.match(namespacesQueryRegex) if (namespaceQuery) { let target = { - region: this.getVariableValue(namespaceQuery[1]), - compartment: this.getVariableValue(namespaceQuery[2]).replace(',', '').trim() + region: removeQuotes(this.getVariableValue(namespaceQuery[1])), + compartment: removeQuotes(this.getVariableValue(namespaceQuery[2])) } return this.getNamespaces(target).catch(err => { throw new Error('Unable to get namespaces: ' + err) }) } @@ -291,9 +298,9 @@ export default class OCIDatasource { let metricQuery = varString.match(metricsQueryRegex) if (metricQuery) { let target = { - region: this.getVariableValue(metricQuery[1].trim()), - compartment: this.getVariableValue(metricQuery[2].replace(',', '').trim()), - namespace: this.getVariableValue(metricQuery[3].replace(',', '').trim()) + region: removeQuotes(this.getVariableValue(metricQuery[1])), + compartment: removeQuotes(this.getVariableValue(metricQuery[2])), + namespace: removeQuotes(this.getVariableValue(metricQuery[3])) } return this.metricFindQuery(target).catch(err => { throw new Error('Unable to get metrics: ' + err) }) } @@ -301,10 +308,10 @@ export default class OCIDatasource { let dimensionsQuery = varString.match(dimensionKeysQueryRegex) if (dimensionsQuery) { let target = { - region: this.getVariableValue(dimensionsQuery[1].trim()), - compartment: this.getVariableValue(dimensionsQuery[2].replace(',', '').trim()), - namespace: this.getVariableValue(dimensionsQuery[3].replace(',', '').trim()), - metric: this.getVariableValue(dimensionsQuery[4].replace(',', '').trim()), + region: removeQuotes(this.getVariableValue(dimensionsQuery[1])), + compartment: removeQuotes(this.getVariableValue(dimensionsQuery[2])), + namespace: removeQuotes(this.getVariableValue(dimensionsQuery[3])), + metric: removeQuotes(this.getVariableValue(dimensionsQuery[4])), } return this.getDimensionKeys(target).catch(err => { throw new Error('Unable to get dimensions: ' + err) }) } @@ -312,12 +319,12 @@ export default class OCIDatasource { let dimensionOptionsQuery = varString.match(dimensionValuesQueryRegex) if (dimensionOptionsQuery) { let target = { - region: this.getVariableValue(dimensionOptionsQuery[1].trim()), - compartment: this.getVariableValue(dimensionOptionsQuery[2].replace(',', '').trim()), - namespace: this.getVariableValue(dimensionOptionsQuery[3].replace(',', '').trim()), - metric: this.getVariableValue(dimensionOptionsQuery[4].replace(',', '').trim()) + region: removeQuotes(this.getVariableValue(dimensionOptionsQuery[1])), + compartment: removeQuotes(this.getVariableValue(dimensionOptionsQuery[2])), + namespace: removeQuotes(this.getVariableValue(dimensionOptionsQuery[3])), + metric: removeQuotes(this.getVariableValue(dimensionOptionsQuery[4])) } - const dimensionKey = this.getVariableValue(dimensionOptionsQuery[5].replace(',', '').trim()); + const dimensionKey = removeQuotes(this.getVariableValue(dimensionOptionsQuery[5])); return this.getDimensionValues(target, dimensionKey).catch(err => { throw new Error('Unable to get dimension options: ' + err) }) } @@ -325,6 +332,10 @@ export default class OCIDatasource { } getRegions() { + if (this.regionsCache && this.regionsCache.length > 0) { + return this.q.when(this.regionsCache); + } + return this.doRequest({ targets: [{ environment: this.environment, @@ -334,11 +345,16 @@ export default class OCIDatasource { }], range: this.timeSrv.timeRange() }).then((items) => { - return this.mapToTextValue(items, 'regions') + this.regionsCache = this.mapToTextValue(items, 'regions'); + return this.regionsCache; }); } getCompartments() { + if (this.compartmentsCache && this.compartmentsCache.length > 0) { + return this.q.when(this.compartmentsCache); + } + return this.doRequest({ targets: [{ environment: this.environment, @@ -349,17 +365,26 @@ export default class OCIDatasource { }], range: this.timeSrv.timeRange() }).then((items) => { - return this.mapToTextValue(items, 'compartments') + this.compartmentsCache = this.mapToTextValue(items, 'compartments'); + return this.compartmentsCache; + }); + } + + getCompartmentId(compartment) { + return this.getCompartments().then(compartments => { + const compartmentFound = compartments.find(c => c.text === compartment || c.value === compartment); + return compartmentFound ? compartmentFound.value : compartment; }); } - getNamespaces(target) { + async getNamespaces(target) { const region = target.region === SELECT_PLACEHOLDERS.REGION ? '' : this.getVariableValue(target.region); const compartment = target.compartment === SELECT_PLACEHOLDERS.COMPARTMENT ? '' : this.getVariableValue(target.compartment); if (_.isEmpty(compartment)) { return this.q.when([]); } + const compartmentId = await this.getCompartmentId(compartment); return this.doRequest({ targets: [{ environment: this.environment, @@ -367,7 +392,7 @@ export default class OCIDatasource { tenancyOCID: this.tenancyOCID, queryType: 'namespaces', region: _.isEmpty(region) ? this.defaultRegion : region, - compartment: compartment + compartment: compartmentId }], range: this.timeSrv.timeRange() }).then((items) => { @@ -393,6 +418,8 @@ export default class OCIDatasource { continue; } dimensionsMap[m] = null; + + const compartmentId = await this.getCompartmentId(compartment); await this.doRequest({ targets: [{ environment: this.environment, @@ -400,7 +427,7 @@ export default class OCIDatasource { tenancyOCID: this.tenancyOCID, queryType: 'dimensions', region: _.isEmpty(region) ? this.defaultRegion : region, - compartment: compartment, + compartment: compartmentId, namespace: namespace, metric: m }], @@ -523,14 +550,18 @@ export default class OCIDatasource { /** * Get all template variable descriptors */ - getVariableDescriptors(regex, type) { - let vars = this.templateSrv.variables || []; + getVariableDescriptors(regex, includeCustom = true) { + const vars = this.templateSrv.variables || []; + if (regex) { - vars = vars.filter(item => item.query.match(regex) !== null); - } - if (type) { - vars = vars.filter(item => item.type === type) + let regexVars = vars.filter(item => item.query.match(regex) !== null); + if (includeCustom) { + const custom = vars.filter(item => item.type === 'custom' || item.type === 'constant'); + regexVars = regexVars.concat(custom); + } + return regexVars; } + return vars; } @@ -538,8 +569,8 @@ export default class OCIDatasource { * List all variable names optionally filtered by regex or/and type * Returns list of names with '$' at the beginning. Example: ['$dimensionKey', '$dimensionValue'] */ - getVariables(regex, type) { - const varDescriptors = this.getVariableDescriptors(regex, type) || []; + getVariables(regex, includeCustom) { + const varDescriptors = this.getVariableDescriptors(regex, includeCustom) || []; return varDescriptors.map(item => `$${item.name}`); } diff --git a/src/query_ctrl.js b/src/query_ctrl.js index 663d20303..7f8895a23 100644 --- a/src/query_ctrl.js +++ b/src/query_ctrl.js @@ -130,7 +130,6 @@ export class OCIDatasourceQueryCtrl extends QueryCtrl { // return all the values for the key const vars = this.datasource.getVariables(dimensionValuesQueryRegex) || []; - const custom = this.datasource.getVariables(null, 'custom') || []; const optionsWithVariables = vars.concat(custom).concat(options); const segments = optionsWithVariables.map(v => this.uiSegmentSrv.newSegment({ value: v })); return segments; From 07422c780bccec037db42ae7087a85c0180e4dbd Mon Sep 17 00:00:00 2001 From: Julia Shmeleva Date: Thu, 23 Jan 2020 09:46:48 -0800 Subject: [PATCH 2/3] fix filtering compartments in template variables --- src/datasource.js | 23 ++++++++++++++--------- src/query_ctrl.js | 46 +++++++++++++++------------------------------- 2 files changed, 29 insertions(+), 40 deletions(-) diff --git a/src/datasource.js b/src/datasource.js index 0e7cc4e1e..b4d310f56 100644 --- a/src/datasource.js +++ b/src/datasource.js @@ -41,8 +41,8 @@ export default class OCIDatasource { * Required method * Used by panels to get data */ - query(options) { - var query = this.buildQueryParameters(options); + async query(options) { + var query = await this.buildQueryParameters(options); if (query.targets.length <= 0) { return this.q.when({ data: [] }); @@ -128,7 +128,7 @@ export default class OCIDatasource { /** * Build and validate query parameters. */ - buildQueryParameters(options) { + async buildQueryParameters(options) { let queries = options.targets .filter(t => !t.hide) .filter(t => !_.isEmpty(this.getVariableValue(t.compartment, options.scopedVars)) && t.compartment !== SELECT_PLACEHOLDERS.COMPARTMENT) @@ -144,7 +144,8 @@ export default class OCIDatasource { // we support multiselect for dimension values, so we need to parse 1 query into multiple queries queries = this.splitMultiValueDimensionsIntoQuieries(queries, options); - queries = queries.map(t => { + const results = []; + for (let t of queries) { const region = t.region === SELECT_PLACEHOLDERS.REGION ? '' : this.getVariableValue(t.region, options.scopedVars); let query = this.getVariableValue(t.target, options.scopedVars); @@ -161,7 +162,8 @@ export default class OCIDatasource { query = `${this.getVariableValue(t.metric, options.scopedVars)}[${t.window}]${dimension}.${t.aggregation}`; } - return { + const compartmentId = await this.getCompartmentId(this.getVariableValue(t.compartment, options.scopedVars)); + const result = { environment: this.environment, datasourceId: this.id, tenancyOCID: this.tenancyOCID, @@ -171,13 +173,14 @@ export default class OCIDatasource { hide: t.hide, type: t.type || 'timeserie', region: _.isEmpty(region) ? this.defaultRegion : region, - compartment: this.getVariableValue(t.compartment, options.scopedVars), + compartment: compartmentId, namespace: this.getVariableValue(t.namespace, options.scopedVars), query: query } - }); + results.push(result); + }; - options.targets = queries; + options.targets = results; return options; } @@ -283,7 +286,9 @@ export default class OCIDatasource { let compartmentQuery = varString.match(compartmentsQueryRegex) if (compartmentQuery) { - return this.getCompartments().catch(err => { throw new Error('Unable to get compartments: ' + err) }) + return this.getCompartments().then(compartments => { + return compartments.map(c => ({ text: c.text, value: c.text })); + }).catch(err => { throw new Error('Unable to get compartments: ' + err) }) } let namespaceQuery = varString.match(namespacesQueryRegex) diff --git a/src/query_ctrl.js b/src/query_ctrl.js index 7f8895a23..aaef16b08 100644 --- a/src/query_ctrl.js +++ b/src/query_ctrl.js @@ -38,8 +38,6 @@ export class OCIDatasourceQueryCtrl extends QueryCtrl { this.getDimensionOperatorSegment = () => this.uiSegmentSrv.newOperator('='); this.getSelectDimensionValueSegment = () => uiSegmentSrv.newSegment({ value: SELECT_PLACEHOLDERS.DIMENSION_VALUE, type: 'value' }); - this.regionsCache = []; - this.compartmentsCache = []; this.dimensionsCache = {}; // rebuild dimensionSegments on query editor load @@ -58,46 +56,32 @@ export class OCIDatasourceQueryCtrl extends QueryCtrl { // ****************************** Options ********************************** getRegions() { - if (!_.isEmpty(this.regionsCache)) { - return this.q.when(this.regionsCache); - } - return this.datasource.getRegions() - .then((regions) => { - this.regionsCache = this.appendVariables(regions, regionsQueryRegex); - return this.regionsCache; - }); + return this.datasource.getRegions().then(regions => { + return this.appendVariables(regions, regionsQueryRegex); + }); } getCompartments() { - if (!_.isEmpty(this.compartmentsCache)) { - return this.q.when(this.compartmentsCache); - } - return this.datasource.getCompartments() - .then((compartments) => { - this.compartmentsCache = this.appendVariables(compartments, compartmentsQueryRegex); - return this.compartmentsCache; - }); + return this.datasource.getCompartments().then(compartments => { + return this.appendVariables(compartments, compartmentsQueryRegex); + }); } getNamespaces() { - return this.datasource.getNamespaces(this.target) - .then((namespaces) => { - return this.appendVariables(namespaces, namespacesQueryRegex); - }); + return this.datasource.getNamespaces(this.target).then(namespaces => { + return this.appendVariables(namespaces, namespacesQueryRegex); + }); } getMetrics() { - return this.datasource.metricFindQuery(this.target) - .then((metrics) => { - return this.appendVariables(metrics, metricsQueryRegex); - }); + return this.datasource.metricFindQuery(this.target).then(metrics => { + return this.appendVariables(metrics, metricsQueryRegex); + }); } getAggregations() { - return this.datasource.getAggregations().then((aggs) => { - return aggs.map((val) => { - return { text: val, value: val }; - }) + return this.datasource.getAggregations().then(aggs => { + return aggs.map((val) => ({ text: val, value: val })); }); } @@ -130,7 +114,7 @@ export class OCIDatasourceQueryCtrl extends QueryCtrl { // return all the values for the key const vars = this.datasource.getVariables(dimensionValuesQueryRegex) || []; - const optionsWithVariables = vars.concat(custom).concat(options); + const optionsWithVariables = vars.concat(options); const segments = optionsWithVariables.map(v => this.uiSegmentSrv.newSegment({ value: v })); return segments; }); From 617f8b8d591371f6e840eb6eb12d3bfb4eed896e Mon Sep 17 00:00:00 2001 From: Julia Shmeleva Date: Thu, 23 Jan 2020 11:11:19 -0800 Subject: [PATCH 3/3] version update --- build.sh | 1 + plugin.json | 4 ++-- src/plugin.json | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/build.sh b/build.sh index cb9fddbbf..f3750e86c 100755 --- a/build.sh +++ b/build.sh @@ -39,6 +39,7 @@ GOOS=$GOOS go build -o ./dist/oci-plugin$POST # For debugger # GOOS=$GOOS go build -o ./dist/oci-plugin$POST -gcflags="all=-N -l" +# For release # GOOS=linux go build -o ./dist/oci-plugin_linux_amd64 # GOOS=windows GOARCH=amd64 go build -o ./dist/oci-plugin_windows_amd64.exe # tar cvf plugin.tar ./dist diff --git a/plugin.json b/plugin.json index 17a5d3d0c..d94270cce 100644 --- a/plugin.json +++ b/plugin.json @@ -26,8 +26,8 @@ {"name": "GitHub", "url": "https://github.com/oracle/oci-grafana-plugin"}, {"name": "MIT License", "url": "https://github.com/oracle/oci-grafana-plugin"} ], - "version": "1.0.5", - "updated": "2019-09-24" + "version": "1.0.6", + "updated": "2020-01-23" }, "dependencies": { diff --git a/src/plugin.json b/src/plugin.json index 1cf36a6d1..827db8a3f 100644 --- a/src/plugin.json +++ b/src/plugin.json @@ -26,8 +26,8 @@ {"name": "GitHub", "url": "https://github.com/oracle/oci-grafana-plugin"}, {"name": "UPL", "url": "https://oss.oracle.com/licenses/upl"} ], - "version": "1.0.5", - "updated": "2019-09-24" + "version": "1.0.6", + "updated": "2020-01-23" }, "dependencies": {