Commit 93f05ed3 authored by Paul Slaughter's avatar Paul Slaughter

Merge branch...

Merge branch '195670-save-full-dashboard-to-vue-store-so-it-can-be-edited-and-saved-back-to-the-backend' into 'master'

Move entire metrics dashboard to Vuex state

See merge request gitlab-org/gitlab!22722
parents 13a5d8a0 db674e2d
...@@ -39,7 +39,7 @@ export const requestMetricsDashboard = ({ commit }) => { ...@@ -39,7 +39,7 @@ export const requestMetricsDashboard = ({ commit }) => {
}; };
export const receiveMetricsDashboardSuccess = ({ commit, dispatch }, { response, params }) => { export const receiveMetricsDashboardSuccess = ({ commit, dispatch }, { response, params }) => {
commit(types.SET_ALL_DASHBOARDS, response.all_dashboards); commit(types.SET_ALL_DASHBOARDS, response.all_dashboards);
commit(types.RECEIVE_METRICS_DATA_SUCCESS, response.dashboard.panel_groups); commit(types.RECEIVE_METRICS_DATA_SUCCESS, response.dashboard);
return dispatch('fetchPrometheusMetrics', params); return dispatch('fetchPrometheusMetrics', params);
}; };
export const receiveMetricsDashboardFailure = ({ commit }, error) => { export const receiveMetricsDashboardFailure = ({ commit }, error) => {
......
...@@ -84,23 +84,26 @@ export default { ...@@ -84,23 +84,26 @@ export default {
state.emptyState = 'loading'; state.emptyState = 'loading';
state.showEmptyState = true; state.showEmptyState = true;
}, },
[types.RECEIVE_METRICS_DATA_SUCCESS](state, groupData) { [types.RECEIVE_METRICS_DATA_SUCCESS](state, dashboard) {
state.dashboard.panel_groups = groupData.map((group, i) => { state.dashboard = {
const key = `${slugify(group.group || 'default')}-${i}`; ...dashboard,
let { panels = [] } = group; panel_groups: dashboard.panel_groups.map((group, i) => {
const key = `${slugify(group.group || 'default')}-${i}`;
// each panel has metric information that needs to be normalized let { panels = [] } = group;
panels = panels.map(panel => ({
...panel, // each panel has metric information that needs to be normalized
metrics: normalizePanelMetrics(panel.metrics, panel.y_label), panels = panels.map(panel => ({
})); ...panel,
metrics: normalizePanelMetrics(panel.metrics, panel.y_label),
return { }));
...group,
panels, return {
key, ...group,
}; panels,
}); key,
};
}),
};
if (!state.dashboard.panel_groups.length) { if (!state.dashboard.panel_groups.length) {
state.emptyState = 'noData'; state.emptyState = 'noData';
......
...@@ -345,7 +345,7 @@ describe('Dashboard', () => { ...@@ -345,7 +345,7 @@ describe('Dashboard', () => {
it('metrics can be swapped', done => { it('metrics can be swapped', done => {
const firstDraggable = findDraggables().at(0); const firstDraggable = findDraggables().at(0);
const mockMetrics = [...metricsGroupsAPIResponse[1].panels]; const mockMetrics = [...metricsGroupsAPIResponse.panel_groups[1].panels];
const firstTitle = mockMetrics[0].title; const firstTitle = mockMetrics[0].title;
const secondTitle = mockMetrics[1].title; const secondTitle = mockMetrics[1].title;
......
...@@ -331,77 +331,80 @@ export const mockedQueryResultPayloadCoresTotal = { ...@@ -331,77 +331,80 @@ export const mockedQueryResultPayloadCoresTotal = {
], ],
}; };
export const metricsGroupsAPIResponse = [ export const metricsGroupsAPIResponse = {
{ dashboard: 'Environment metrics',
group: 'Response metrics (NGINX Ingress VTS)', panel_groups: [
priority: 10, {
panels: [ group: 'Response metrics (NGINX Ingress VTS)',
{ priority: 10,
metrics: [ panels: [
{ {
id: 'response_metrics_nginx_ingress_throughput_status_code', metrics: [
label: 'Status Code', {
metric_id: 1, id: 'response_metrics_nginx_ingress_throughput_status_code',
prometheus_endpoint_path: label: 'Status Code',
'/root/autodevops-deploy/environments/32/prometheus/api/v1/query_range?query=sum%28rate%28nginx_upstream_responses_total%7Bupstream%3D~%22%25%7Bkube_namespace%7D-%25%7Bci_environment_slug%7D-.%2A%22%7D%5B2m%5D%29%29+by+%28status_code%29', metric_id: 1,
query_range: prometheus_endpoint_path:
'sum(rate(nginx_upstream_responses_total{upstream=~"%{kube_namespace}-%{ci_environment_slug}-.*"}[2m])) by (status_code)', '/root/autodevops-deploy/environments/32/prometheus/api/v1/query_range?query=sum%28rate%28nginx_upstream_responses_total%7Bupstream%3D~%22%25%7Bkube_namespace%7D-%25%7Bci_environment_slug%7D-.%2A%22%7D%5B2m%5D%29%29+by+%28status_code%29',
unit: 'req / sec', query_range:
}, 'sum(rate(nginx_upstream_responses_total{upstream=~"%{kube_namespace}-%{ci_environment_slug}-.*"}[2m])) by (status_code)',
], unit: 'req / sec',
title: 'Throughput', },
type: 'area-chart', ],
weight: 1, title: 'Throughput',
y_label: 'Requests / Sec', type: 'area-chart',
}, weight: 1,
], y_label: 'Requests / Sec',
}, },
{ ],
group: 'System metrics (Kubernetes)', },
priority: 5, {
panels: [ group: 'System metrics (Kubernetes)',
{ priority: 5,
title: 'Memory Usage (Pod average)', panels: [
type: 'area-chart', {
y_label: 'Memory Used per Pod', title: 'Memory Usage (Pod average)',
weight: 2, type: 'area-chart',
metrics: [ y_label: 'Memory Used per Pod',
{ weight: 2,
id: 'system_metrics_kubernetes_container_memory_average', metrics: [
query_range: {
'avg(sum(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-([^c].*|c([^a]|a([^n]|n([^a]|a([^r]|r[^y])))).*|)-(.*)",namespace="%{kube_namespace}"}) by (job)) without (job) / count(avg(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-([^c].*|c([^a]|a([^n]|n([^a]|a([^r]|r[^y])))).*|)-(.*)",namespace="%{kube_namespace}"}) without (job)) /1024/1024', id: 'system_metrics_kubernetes_container_memory_average',
label: 'Pod average', query_range:
unit: 'MB', 'avg(sum(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-([^c].*|c([^a]|a([^n]|n([^a]|a([^r]|r[^y])))).*|)-(.*)",namespace="%{kube_namespace}"}) by (job)) without (job) / count(avg(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-([^c].*|c([^a]|a([^n]|n([^a]|a([^r]|r[^y])))).*|)-(.*)",namespace="%{kube_namespace}"}) without (job)) /1024/1024',
metric_id: 17, label: 'Pod average',
prometheus_endpoint_path: unit: 'MB',
'/root/autodevops-deploy/environments/32/prometheus/api/v1/query_range?query=avg%28sum%28container_memory_usage_bytes%7Bcontainer_name%21%3D%22POD%22%2Cpod_name%3D~%22%5E%25%7Bci_environment_slug%7D-%28%5B%5Ec%5D.%2A%7Cc%28%5B%5Ea%5D%7Ca%28%5B%5En%5D%7Cn%28%5B%5Ea%5D%7Ca%28%5B%5Er%5D%7Cr%5B%5Ey%5D%29%29%29%29.%2A%7C%29-%28.%2A%29%22%2Cnamespace%3D%22%25%7Bkube_namespace%7D%22%7D%29+by+%28job%29%29+without+%28job%29+%2F+count%28avg%28container_memory_usage_bytes%7Bcontainer_name%21%3D%22POD%22%2Cpod_name%3D~%22%5E%25%7Bci_environment_slug%7D-%28%5B%5Ec%5D.%2A%7Cc%28%5B%5Ea%5D%7Ca%28%5B%5En%5D%7Cn%28%5B%5Ea%5D%7Ca%28%5B%5Er%5D%7Cr%5B%5Ey%5D%29%29%29%29.%2A%7C%29-%28.%2A%29%22%2Cnamespace%3D%22%25%7Bkube_namespace%7D%22%7D%29+without+%28job%29%29+%2F1024%2F1024', metric_id: 17,
appearance: { prometheus_endpoint_path:
line: { '/root/autodevops-deploy/environments/32/prometheus/api/v1/query_range?query=avg%28sum%28container_memory_usage_bytes%7Bcontainer_name%21%3D%22POD%22%2Cpod_name%3D~%22%5E%25%7Bci_environment_slug%7D-%28%5B%5Ec%5D.%2A%7Cc%28%5B%5Ea%5D%7Ca%28%5B%5En%5D%7Cn%28%5B%5Ea%5D%7Ca%28%5B%5Er%5D%7Cr%5B%5Ey%5D%29%29%29%29.%2A%7C%29-%28.%2A%29%22%2Cnamespace%3D%22%25%7Bkube_namespace%7D%22%7D%29+by+%28job%29%29+without+%28job%29+%2F+count%28avg%28container_memory_usage_bytes%7Bcontainer_name%21%3D%22POD%22%2Cpod_name%3D~%22%5E%25%7Bci_environment_slug%7D-%28%5B%5Ec%5D.%2A%7Cc%28%5B%5Ea%5D%7Ca%28%5B%5En%5D%7Cn%28%5B%5Ea%5D%7Ca%28%5B%5Er%5D%7Cr%5B%5Ey%5D%29%29%29%29.%2A%7C%29-%28.%2A%29%22%2Cnamespace%3D%22%25%7Bkube_namespace%7D%22%7D%29+without+%28job%29%29+%2F1024%2F1024',
width: 2, appearance: {
line: {
width: 2,
},
}, },
}, },
}, ],
], },
}, {
{ title: 'Core Usage (Total)',
title: 'Core Usage (Total)', type: 'area-chart',
type: 'area-chart', y_label: 'Total Cores',
y_label: 'Total Cores', weight: 3,
weight: 3, metrics: [
metrics: [ {
{ id: 'system_metrics_kubernetes_container_cores_total',
id: 'system_metrics_kubernetes_container_cores_total', query_range:
query_range: 'avg(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^%{ci_environment_slug}-(.*)",namespace="%{kube_namespace}"}[15m])) by (job)) without (job)',
'avg(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^%{ci_environment_slug}-(.*)",namespace="%{kube_namespace}"}[15m])) by (job)) without (job)', label: 'Total',
label: 'Total', unit: 'cores',
unit: 'cores', metric_id: 13,
metric_id: 13, },
}, ],
], },
}, ],
], },
}, ],
]; };
export const environmentData = [ export const environmentData = [
{ {
......
...@@ -298,7 +298,7 @@ describe('Monitoring store actions', () => { ...@@ -298,7 +298,7 @@ describe('Monitoring store actions', () => {
); );
expect(commit).toHaveBeenCalledWith( expect(commit).toHaveBeenCalledWith(
types.RECEIVE_METRICS_DATA_SUCCESS, types.RECEIVE_METRICS_DATA_SUCCESS,
metricsDashboardResponse.dashboard.panel_groups, metricsDashboardResponse.dashboard,
); );
expect(dispatch).toHaveBeenCalledWith('fetchPrometheusMetrics', params); expect(dispatch).toHaveBeenCalledWith('fetchPrometheusMetrics', params);
}); });
...@@ -441,7 +441,7 @@ describe('Monitoring store actions', () => { ...@@ -441,7 +441,7 @@ describe('Monitoring store actions', () => {
beforeEach(() => { beforeEach(() => {
state = storeState(); state = storeState();
[metric] = metricsDashboardResponse.dashboard.panel_groups[0].panels[0].metrics; [metric] = metricsDashboardResponse.dashboard.panel_groups[0].panels[0].metrics;
[data] = metricsGroupsAPIResponse[0].panels[0].metrics; [data] = metricsGroupsAPIResponse.panel_groups[0].panels[0].metrics;
}); });
it('commits result', done => { it('commits result', done => {
......
...@@ -100,12 +100,12 @@ describe('Monitoring mutations', () => { ...@@ -100,12 +100,12 @@ describe('Monitoring mutations', () => {
values: [[0, 1], [1, 1], [1, 3]], values: [[0, 1], [1, 1], [1, 3]],
}, },
]; ];
const dashboardGroups = metricsDashboardResponse.dashboard.panel_groups; const { dashboard } = metricsDashboardResponse;
const getMetric = () => stateCopy.dashboard.panel_groups[0].panels[0].metrics[0]; const getMetric = () => stateCopy.dashboard.panel_groups[0].panels[0].metrics[0];
describe('REQUEST_METRIC_RESULT', () => { describe('REQUEST_METRIC_RESULT', () => {
beforeEach(() => { beforeEach(() => {
mutations[types.RECEIVE_METRICS_DATA_SUCCESS](stateCopy, dashboardGroups); mutations[types.RECEIVE_METRICS_DATA_SUCCESS](stateCopy, dashboard);
}); });
it('stores a loading state on a metric', () => { it('stores a loading state on a metric', () => {
expect(stateCopy.showEmptyState).toBe(true); expect(stateCopy.showEmptyState).toBe(true);
...@@ -128,7 +128,7 @@ describe('Monitoring mutations', () => { ...@@ -128,7 +128,7 @@ describe('Monitoring mutations', () => {
describe('RECEIVE_METRIC_RESULT_SUCCESS', () => { describe('RECEIVE_METRIC_RESULT_SUCCESS', () => {
beforeEach(() => { beforeEach(() => {
mutations[types.RECEIVE_METRICS_DATA_SUCCESS](stateCopy, dashboardGroups); mutations[types.RECEIVE_METRICS_DATA_SUCCESS](stateCopy, dashboard);
}); });
it('clears empty state', () => { it('clears empty state', () => {
expect(stateCopy.showEmptyState).toBe(true); expect(stateCopy.showEmptyState).toBe(true);
...@@ -161,7 +161,7 @@ describe('Monitoring mutations', () => { ...@@ -161,7 +161,7 @@ describe('Monitoring mutations', () => {
describe('RECEIVE_METRIC_RESULT_FAILURE', () => { describe('RECEIVE_METRIC_RESULT_FAILURE', () => {
beforeEach(() => { beforeEach(() => {
mutations[types.RECEIVE_METRICS_DATA_SUCCESS](stateCopy, dashboardGroups); mutations[types.RECEIVE_METRICS_DATA_SUCCESS](stateCopy, dashboard);
}); });
it('maintains the loading state when a metric fails', () => { it('maintains the loading state when a metric fails', () => {
expect(stateCopy.showEmptyState).toBe(true); expect(stateCopy.showEmptyState).toBe(true);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment