summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/monitoring/stores
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-06-24 03:08:44 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-06-24 03:08:44 +0000
commit4870899d6cec693b58acbef91636e1310160fa28 (patch)
tree305628a2a8436e77b0c3972f8053df771a89843c /app/assets/javascripts/monitoring/stores
parent082b24b03bbb9dca7edf1341aa7b0a51c9aeb18b (diff)
downloadgitlab-ce-4870899d6cec693b58acbef91636e1310160fa28.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/monitoring/stores')
-rw-r--r--app/assets/javascripts/monitoring/stores/actions.js38
-rw-r--r--app/assets/javascripts/monitoring/stores/mutation_types.js3
-rw-r--r--app/assets/javascripts/monitoring/stores/mutations.js17
-rw-r--r--app/assets/javascripts/monitoring/stores/variable_mapping.js113
4 files changed, 149 insertions, 22 deletions
diff --git a/app/assets/javascripts/monitoring/stores/actions.js b/app/assets/javascripts/monitoring/stores/actions.js
index 6527a799759..aaa7865f30a 100644
--- a/app/assets/javascripts/monitoring/stores/actions.js
+++ b/app/assets/javascripts/monitoring/stores/actions.js
@@ -21,6 +21,7 @@ import {
PROMETHEUS_TIMEOUT,
ENVIRONMENT_AVAILABLE_STATE,
DEFAULT_DASHBOARD_PATH,
+ VARIABLE_TYPES,
} from '../constants';
function prometheusMetricQueryParams(timeRange) {
@@ -191,8 +192,12 @@ export const fetchDashboardData = ({ state, dispatch, getters }) => {
return Promise.reject();
}
+ // Time range params must be pre-calculated once for all metrics and options
+ // A subsequent call, may calculate a different time range
const defaultQueryParams = prometheusMetricQueryParams(state.timeRange);
+ dispatch('fetchVariableMetricLabelValues', { defaultQueryParams });
+
const promises = [];
state.dashboard.panelGroups.forEach(group => {
group.panels.forEach(panel => {
@@ -466,10 +471,41 @@ export const duplicateSystemDashboard = ({ state }, payload) => {
// Variables manipulation
export const updateVariablesAndFetchData = ({ commit, dispatch }, updatedVariable) => {
- commit(types.UPDATE_VARIABLES, updatedVariable);
+ commit(types.UPDATE_VARIABLE_VALUE, updatedVariable);
return dispatch('fetchDashboardData');
};
+export const fetchVariableMetricLabelValues = ({ state, commit }, { defaultQueryParams }) => {
+ const { start_time, end_time } = defaultQueryParams;
+ const optionsRequests = [];
+
+ Object.entries(state.variables).forEach(([key, variable]) => {
+ if (variable.type === VARIABLE_TYPES.metric_label_values) {
+ const { prometheusEndpointPath, label } = variable.options;
+
+ const optionsRequest = backOffRequest(() =>
+ axios.get(prometheusEndpointPath, {
+ params: { start_time, end_time },
+ }),
+ )
+ .then(({ data }) => data.data)
+ .then(data => {
+ commit(types.UPDATE_VARIABLE_METRIC_LABEL_VALUES, { variable, label, data });
+ })
+ .catch(() => {
+ createFlash(
+ sprintf(s__('Metrics|There was an error getting options for variable "%{name}".'), {
+ name: key,
+ }),
+ );
+ });
+ optionsRequests.push(optionsRequest);
+ }
+ });
+
+ return Promise.all(optionsRequests);
+};
+
// prevent babel-plugin-rewire from generating an invalid default during karma tests
export default () => {};
diff --git a/app/assets/javascripts/monitoring/stores/mutation_types.js b/app/assets/javascripts/monitoring/stores/mutation_types.js
index 17563f966f5..d43065749c1 100644
--- a/app/assets/javascripts/monitoring/stores/mutation_types.js
+++ b/app/assets/javascripts/monitoring/stores/mutation_types.js
@@ -3,7 +3,8 @@ export const REQUEST_METRICS_DASHBOARD = 'REQUEST_METRICS_DASHBOARD';
export const RECEIVE_METRICS_DASHBOARD_SUCCESS = 'RECEIVE_METRICS_DASHBOARD_SUCCESS';
export const RECEIVE_METRICS_DASHBOARD_FAILURE = 'RECEIVE_METRICS_DASHBOARD_FAILURE';
export const SET_VARIABLES = 'SET_VARIABLES';
-export const UPDATE_VARIABLES = 'UPDATE_VARIABLES';
+export const UPDATE_VARIABLE_VALUE = 'UPDATE_VARIABLE_VALUE';
+export const UPDATE_VARIABLE_METRIC_LABEL_VALUES = 'UPDATE_VARIABLE_METRIC_LABEL_VALUES';
export const REQUEST_DASHBOARD_STARRING = 'REQUEST_DASHBOARD_STARRING';
export const RECEIVE_DASHBOARD_STARRING_SUCCESS = 'RECEIVE_DASHBOARD_STARRING_SUCCESS';
diff --git a/app/assets/javascripts/monitoring/stores/mutations.js b/app/assets/javascripts/monitoring/stores/mutations.js
index 08e6f00b866..53c8029e46b 100644
--- a/app/assets/javascripts/monitoring/stores/mutations.js
+++ b/app/assets/javascripts/monitoring/stores/mutations.js
@@ -2,9 +2,10 @@ import Vue from 'vue';
import { pick } from 'lodash';
import * as types from './mutation_types';
import { mapToDashboardViewModel, normalizeQueryResponseData } from './utils';
+import httpStatusCodes from '~/lib/utils/http_status';
import { BACKOFF_TIMEOUT } from '../../lib/utils/common_utils';
import { endpointKeys, initialStateKeys, metricStates } from '../constants';
-import httpStatusCodes from '~/lib/utils/http_status';
+import { optionsFromSeriesData } from './variable_mapping';
/**
* Locate and return a metric in the dashboard by its id
@@ -205,10 +206,16 @@ export default {
[types.SET_VARIABLES](state, variables) {
state.variables = variables;
},
- [types.UPDATE_VARIABLES](state, updatedVariable) {
- Object.assign(state.variables[updatedVariable.key], {
- ...state.variables[updatedVariable.key],
- value: updatedVariable.value,
+ [types.UPDATE_VARIABLE_VALUE](state, { key, value }) {
+ Object.assign(state.variables[key], {
+ ...state.variables[key],
+ value,
});
},
+ [types.UPDATE_VARIABLE_METRIC_LABEL_VALUES](state, { variable, label, data = [] }) {
+ const values = optionsFromSeriesData({ label, data });
+
+ // Add new options with assign to ensure Vue reactivity
+ Object.assign(variable.options, { values });
+ },
};
diff --git a/app/assets/javascripts/monitoring/stores/variable_mapping.js b/app/assets/javascripts/monitoring/stores/variable_mapping.js
index c0a8150063b..0b268402992 100644
--- a/app/assets/javascripts/monitoring/stores/variable_mapping.js
+++ b/app/assets/javascripts/monitoring/stores/variable_mapping.js
@@ -46,7 +46,7 @@ const textAdvancedVariableParser = advTextVar => ({
* @param {Object} custom variable option
* @returns {Object} normalized custom variable options
*/
-const normalizeCustomVariableOptions = ({ default: defaultOpt = false, text, value }) => ({
+const normalizeVariableValues = ({ default: defaultOpt = false, text, value }) => ({
default: defaultOpt,
text: text || value,
value,
@@ -59,17 +59,19 @@ const normalizeCustomVariableOptions = ({ default: defaultOpt = false, text, val
* The default value is the option with default set to true or the first option
* if none of the options have default prop true.
*
- * @param {Object} advVariable advance custom variable
+ * @param {Object} advVariable advanced custom variable
* @returns {Object}
*/
const customAdvancedVariableParser = advVariable => {
- const options = (advVariable?.options?.values ?? []).map(normalizeCustomVariableOptions);
- const defaultOpt = options.find(opt => opt.default === true) || options[0];
+ const values = (advVariable?.options?.values ?? []).map(normalizeVariableValues);
+ const defaultValue = values.find(opt => opt.default === true) || values[0];
return {
type: VARIABLE_TYPES.custom,
label: advVariable.label,
- value: defaultOpt?.value,
- options,
+ value: defaultValue?.value,
+ options: {
+ values,
+ },
};
};
@@ -80,7 +82,7 @@ const customAdvancedVariableParser = advVariable => {
* @param {String} opt option from simple custom variable
* @returns {Object}
*/
-const parseSimpleCustomOptions = opt => ({ text: opt, value: opt });
+export const parseSimpleCustomValues = opt => ({ text: opt, value: opt });
/**
* Custom simple variables are rendered as dropdown elements in the dashboard
@@ -95,12 +97,28 @@ const parseSimpleCustomOptions = opt => ({ text: opt, value: opt });
* @returns {Object}
*/
const customSimpleVariableParser = simpleVar => {
- const options = (simpleVar || []).map(parseSimpleCustomOptions);
+ const values = (simpleVar || []).map(parseSimpleCustomValues);
return {
type: VARIABLE_TYPES.custom,
- value: options[0].value,
+ value: values[0].value,
label: null,
- options: options.map(normalizeCustomVariableOptions),
+ options: {
+ values: values.map(normalizeVariableValues),
+ },
+ };
+};
+
+const metricLabelValuesVariableParser = variable => {
+ const { label, options = {} } = variable;
+ return {
+ type: VARIABLE_TYPES.metric_label_values,
+ value: null,
+ label,
+ options: {
+ prometheusEndpointPath: options.prometheus_endpoint_path || '',
+ label: options.label || null,
+ values: [], // values are initially empty
+ },
};
};
@@ -123,14 +141,16 @@ const isSimpleCustomVariable = customVar => Array.isArray(customVar);
* @return {Function} parser method
*/
const getVariableParser = variable => {
- if (isSimpleCustomVariable(variable)) {
+ if (isString(variable)) {
+ return textSimpleVariableParser;
+ } else if (isSimpleCustomVariable(variable)) {
return customSimpleVariableParser;
- } else if (variable.type === VARIABLE_TYPES.custom) {
- return customAdvancedVariableParser;
} else if (variable.type === VARIABLE_TYPES.text) {
return textAdvancedVariableParser;
- } else if (isString(variable)) {
- return textSimpleVariableParser;
+ } else if (variable.type === VARIABLE_TYPES.custom) {
+ return customAdvancedVariableParser;
+ } else if (variable.type === VARIABLE_TYPES.metric_label_values) {
+ return metricLabelValuesVariableParser;
}
return () => null;
};
@@ -200,4 +220,67 @@ export const mergeURLVariables = (varsFromYML = {}) => {
return variables;
};
+/**
+ * Converts series data to options that can be added to a
+ * variable. Series data is returned from the Prometheus API
+ * `/api/v1/series`.
+ *
+ * Finds a `label` in the series data, so it can be used as
+ * a filter.
+ *
+ * For example, for the arguments:
+ *
+ * {
+ * "label": "job"
+ * "data" : [
+ * {
+ * "__name__" : "up",
+ * "job" : "prometheus",
+ * "instance" : "localhost:9090"
+ * },
+ * {
+ * "__name__" : "up",
+ * "job" : "node",
+ * "instance" : "localhost:9091"
+ * },
+ * {
+ * "__name__" : "process_start_time_seconds",
+ * "job" : "prometheus",
+ * "instance" : "localhost:9090"
+ * }
+ * ]
+ * }
+ *
+ * It returns all the different "job" values:
+ *
+ * [
+ * {
+ * "label": "node",
+ * "value": "node"
+ * },
+ * {
+ * "label": "prometheus",
+ * "value": "prometheus"
+ * }
+ * ]
+ *
+ * @param {options} options object
+ * @param {options.seriesLabel} name of the searched series label
+ * @param {options.data} series data from the series API
+ * @return {array} Options objects with the shape `{ label, value }`
+ *
+ * @see https://prometheus.io/docs/prometheus/latest/querying/api/#finding-series-by-label-matchers
+ */
+export const optionsFromSeriesData = ({ label, data = [] }) => {
+ const optionsSet = data.reduce((set, seriesObject) => {
+ // Use `new Set` to deduplicate options
+ if (seriesObject[label]) {
+ set.add(seriesObject[label]);
+ }
+ return set;
+ }, new Set());
+
+ return [...optionsSet].map(parseSimpleCustomValues);
+};
+
export default {};