From 1f63deb71c3b11269ee19856001f6f99200aa1cd Mon Sep 17 00:00:00 2001 From: Zahi Akiva Date: Sun, 25 Dec 2016 14:50:01 +0200 Subject: [PATCH] Containers Dashboard: Show hourly and realtime trends --- .../container_dashboard_controller.js | 88 +++++-- .../container_dashboard/util/charts-mixin.js | 61 ++++- app/services/container_dashboard_service.rb | 230 ++++++++++++++---- .../ems_container/_show_dashboard.html.haml | 34 +-- .../container_dashboard_controller_spec.js | 12 +- .../container_dashboard_no_data_response.json | 22 +- .../json/container_dashboard_response.json | 102 ++++---- .../container_dashboard_service_spec.rb | 51 ++-- 8 files changed, 448 insertions(+), 152 deletions(-) diff --git a/app/assets/javascripts/controllers/container_dashboard/container_dashboard_controller.js b/app/assets/javascripts/controllers/container_dashboard/container_dashboard_controller.js index 27d5be1a7f6..a8d4038de7a 100644 --- a/app/assets/javascripts/controllers/container_dashboard/container_dashboard_controller.js +++ b/app/assets/javascripts/controllers/container_dashboard/container_dashboard_controller.js @@ -117,10 +117,32 @@ dashboardUtilsFactory.updateStatus($scope.objectStatus.routes, data.status.routes); // Node utilization donut - $scope.cpuUsageData = chartsMixin.processUtilizationData(data.ems_utilization.cpu, + if (data.ems_utilization.interval_name != "daily") { + $scope.cpuUsageSparklineConfig.tooltipFn = chartsMixin.hourlyTimeTooltip; + $scope.memoryUsageSparklineConfig.tooltipFn = chartsMixin.hourlyTimeTooltip; + } + if (data.ems_utilization.interval_name == "hourly") { + $scope.cpuUsageConfig.timeFrame = __('Last 24 hours'); + $scope.memoryUsageConfig.timeFrame = __('Last 24 hours'); + } else if (data.ems_utilization.interval_name == "realtime") { + $scope.cpuUsageConfig.timeFrame = __('Last 10 minutes'); + $scope.memoryUsageConfig.timeFrame = __('Last 10 minutes'); + } + + if (data.ems_utilization.xy_data.cpu != null) { + data.ems_utilization.xy_data.cpu.xData = data.ems_utilization.xy_data.cpu.xData.map(function (date) { + return dashboardUtilsFactory.parseDate(date) + }); + data.ems_utilization.xy_data.mem.xData = data.ems_utilization.xy_data.mem.xData.map(function (date) { + return dashboardUtilsFactory.parseDate(date) + }); + } + + $scope.cpuUsageData = chartsMixin.processUtilizationData(data.ems_utilization.xy_data.cpu, 'dates', $scope.cpuUsageConfig.units); - $scope.memoryUsageData = chartsMixin.processUtilizationData(data.ems_utilization.mem, + + $scope.memoryUsageData = chartsMixin.processUtilizationData(data.ems_utilization.xy_data.mem, 'dates', $scope.memoryUsageConfig.units); @@ -133,29 +155,59 @@ $scope.nodeMemoryUsage.loadingDone = true; // Network metrics - $scope.networkUtilizationDailyConfig = chartsMixin.chartConfig.dailyNetworkUsageConfig; + if (data.network_metrics.interval_name == "daily") { + $scope.networkUtilizationConfig = chartsMixin.chartConfig.dailyNetworkUsageConfig; + } else if (data.network_metrics.interval_name == "hourly") { + $scope.networkUtilizationConfig = chartsMixin.chartConfig.hourlyNetworkUsageConfig; + } else { + $scope.networkUtilizationConfig = chartsMixin.chartConfig.hourlyNetworkUsageConfig; + $scope.networkUtilizationConfig.timeFrame = __('Last 10 minutes'); + } + + if (data.network_metrics.xy_data != null) { + data.network_metrics.xy_data.xData = data.network_metrics.xy_data.xData.map(function (date) { + return dashboardUtilsFactory.parseDate(date) + }); + } - $scope.dailyNetworkUtilization = - chartsMixin.processUtilizationData(data.daily_network_metrics, - 'dates', - $scope.networkUtilizationDailyConfig.units); + $scope.networkUtilization = chartsMixin.processUtilizationData(data.network_metrics.xy_data, + 'dates', + $scope.networkUtilizationConfig.units); // Pod metrics - $scope.podEntityTrendDailyConfig = chartsMixin.chartConfig.dailyPodUsageConfig; + if (data.pod_metrics.interval_name == "daily") { + $scope.podEntityTrendConfig = chartsMixin.chartConfig.dailyPodUsageConfig; + } else { + $scope.podEntityTrendConfig = chartsMixin.chartConfig.hourlyPodUsageConfig; + } + + if (data.pod_metrics.xy_data != null) { + data.pod_metrics.xy_data.xData = data.pod_metrics.xy_data.xData.map(function (date) { + return dashboardUtilsFactory.parseDate(date) + }); + } - $scope.dailyPodEntityTrend = - chartsMixin.processPodUtilizationData(data.daily_pod_metrics, - 'dates', - $scope.podEntityTrendDailyConfig.createdLabel, - $scope.podEntityTrendDailyConfig.deletedLabel); + $scope.podEntityTrend = chartsMixin.processPodUtilizationData(data.pod_metrics.xy_data, + 'dates', + $scope.podEntityTrendConfig.createdLabel, + $scope.podEntityTrendConfig.deletedLabel); // Image metrics - $scope.imageEntityTrendDailyConfig = chartsMixin.chartConfig.dailyImageUsageConfig; + if (data.image_metrics.interval_name == "daily") { + $scope.imageEntityTrendConfig = chartsMixin.chartConfig.dailyImageUsageConfig; + } else { + $scope.imageEntityTrendConfig = chartsMixin.chartConfig.hourlyImageUsageConfig; + } + + if (data.image_metrics.xy_data != null) { + data.image_metrics.xy_data.xData = data.image_metrics.xy_data.xData.map(function (date) { + return dashboardUtilsFactory.parseDate(date) + }); + } - $scope.dailyImageEntityTrend = - chartsMixin.processUtilizationData(data.daily_image_metrics, - 'dates', - $scope.imageEntityTrendDailyConfig.createdLabel); + $scope.imageEntityTrend = chartsMixin.processUtilizationData(data.image_metrics.xy_data, + 'dates', + $scope.imageEntityTrendConfig.createdLabel); // Trend lines data $scope.loadingDone = true; diff --git a/app/assets/javascripts/controllers/container_dashboard/util/charts-mixin.js b/app/assets/javascripts/controllers/container_dashboard/util/charts-mixin.js index 4b313f5c6aa..352503241cd 100644 --- a/app/assets/javascripts/controllers/container_dashboard/util/charts-mixin.js +++ b/app/assets/javascripts/controllers/container_dashboard/util/charts-mixin.js @@ -9,6 +9,14 @@ angular.module('miq.util').factory('chartsMixin', ['pfUtils', function(pfUtils) }); }; + var hourlyTimeTooltip = function (data) { + var theMoment = moment(data[0].x); + return _.template('
<%- col1 %>: <%- col2 %>
')({ + col1: theMoment.format('h:mm A'), + col2: data[0].value + ' ' + data[0].name + }); + }; + var dailyPodTimeTooltip = function (data) { var theMoment = moment(data[0].x); return _.template('
<%- col1 %>
<%- col2 %>
')({ @@ -17,6 +25,14 @@ angular.module('miq.util').factory('chartsMixin', ['pfUtils', function(pfUtils) }); }; + var hourlyPodTimeTooltip = function (data) { + var theMoment = moment(data[0].x); + return _.template('
<%- col1 %>: <%- col2 %>
')({ + col1: theMoment.format('h:mm A'), + col2: data[0].value + ' ' + data[0].name + ', ' + data[1].value + ' ' + data[1].name + }); + }; + var lineChartTooltipPositionFactory = function(chartId) { var elementQuery = '#' + chartId + 'lineChart'; @@ -43,6 +59,7 @@ angular.module('miq.util').factory('chartsMixin', ['pfUtils', function(pfUtils) cpuUsageConfig: { chartId: 'cpuUsageChart', title: __('CPU'), + timeFrame: __('Last 30 Days'), units: __('Cores'), usageDataName: __('Used'), legendLeftText: __('Last 30 Days'), @@ -52,6 +69,7 @@ angular.module('miq.util').factory('chartsMixin', ['pfUtils', function(pfUtils) memoryUsageConfig: { chartId: 'memoryUsageChart', title: __('Memory'), + timeFrame: __('Last 30 Days'), units: __('GB'), usageDataName: __('Used'), legendLeftText: __('Last 30 Days'), @@ -66,9 +84,18 @@ angular.module('miq.util').factory('chartsMixin', ['pfUtils', function(pfUtils) dataName : __('KBps'), tooltipFn : dailyTimeTooltip }, + hourlyNetworkUsageConfig: { + chartId : 'networkUsageHourlyChart', + headTitle: __('Network Utilization Trend'), + timeFrame: __('Last 24 Hours'), + units : __('KBps'), + dataName : __('KBps'), + tooltipFn : hourlyTimeTooltip + }, dailyPodUsageConfig: { chartId : 'podUsageDailyChart', headTitle : __('Pod Creation and Deletion Trends'), + timeFrame : __('Last 30 days'), createdLabel: __('Created'), deletedLabel: __('Deleted'), tooltip : { @@ -81,9 +108,26 @@ angular.module('miq.util').factory('chartsMixin', ['pfUtils', function(pfUtils) grid : {y: {show: false}}, setAreaChart: true }, + hourlyPodUsageConfig: { + chartId : 'podUsageHourlyChart', + headTitle : __('Pod Creation and Deletion Trends'), + timeFrame : __('Last 24 hours'), + createdLabel: __('Created'), + deletedLabel: __('Deleted'), + tooltip : { + contents: hourlyPodTimeTooltip, + position: lineChartTooltipPositionFactory('podUsageHourlyChart'), + }, + point : {r: 1}, + size : {height: 145}, + color : {pattern: [pfUtils.colorPalette.blue, pfUtils.colorPalette.green]}, + grid : {y: {show: false}}, + setAreaChart: true + }, dailyImageUsageConfig: { chartId : 'imageUsageDailyChart', headTitle : __('New Image Usage Trend'), + timeFrame : __('Last 30 days'), createdLabel: __('Images'), tooltip : { contents: dailyTimeTooltip, @@ -93,6 +137,20 @@ angular.module('miq.util').factory('chartsMixin', ['pfUtils', function(pfUtils) size : {height: 93}, grid : {y: {show: false}}, setAreaChart: true + }, + hourlyImageUsageConfig: { + chartId : 'imageUsageHourlyChart', + headTitle : __('New Image Usage Trend'), + timeFrame : __('Last 24 hours'), + createdLabel: __('Images'), + tooltip : { + contents: hourlyTimeTooltip, + position: lineChartTooltipPositionFactory('imageUsageHourlyChart'), + }, + point : {r: 1}, + size : {height: 93}, + grid : {y: {show: false}}, + setAreaChart: true } }; @@ -151,6 +209,7 @@ angular.module('miq.util').factory('chartsMixin', ['pfUtils', function(pfUtils) processHeatmapData: processHeatmapData, processUtilizationData: processUtilizationData, processPodUtilizationData: processPodUtilizationData, - dailyTimeTooltip: dailyTimeTooltip + dailyTimeTooltip: dailyTimeTooltip, + hourlyTimeTooltip: hourlyTimeTooltip }; }]); diff --git a/app/services/container_dashboard_service.rb b/app/services/container_dashboard_service.rb index 08c02bebe33..83559532e59 100644 --- a/app/services/container_dashboard_service.rb +++ b/app/services/container_dashboard_service.rb @@ -10,15 +10,14 @@ def initialize(provider_id, controller) def all_data { - :providers_link => get_url_to_entity(:ems_container), - :status => status, - :providers => providers, - :heatmaps => heatmaps, - :ems_utilization => ems_utilization, - :hourly_network_metrics => hourly_network_metrics, - :daily_network_metrics => daily_network_metrics, - :daily_pod_metrics => daily_pod_metrics, - :daily_image_metrics => daily_image_metrics + :providers_link => get_url_to_entity(:ems_container), + :status => status, + :providers => providers, + :heatmaps => heatmaps, + :ems_utilization => ems_utilization, + :network_metrics => network_metrics, + :pod_metrics => pod_metrics, + :image_metrics => image_metrics }.compact end @@ -112,13 +111,22 @@ def get_url_to_entity(entity) end end - def heatmaps + def realtime_heatmaps + heatmaps_data(realtime_provider_metrics) + end + + def hourly_heatmaps # Get latest hourly rollup for each node. node_ids = @ems.container_nodes if @ems.present? metrics = MetricRollup.latest_rollups(ContainerNode.name, node_ids) metrics = metrics.where('timestamp > ?', 1.day.ago.utc).includes(:resource) metrics = metrics.includes(:resource => [:ext_management_system]) unless @ems.present? + data = heatmaps_data(metrics) + data if data[:nodeCpuUsage] + end + + def heatmaps_data(metrics) node_cpu_usage = [] node_memory_usage = [] @@ -149,7 +157,54 @@ def heatmaps } end - def ems_utilization + def heatmaps + hourly_heatmaps || realtime_heatmaps + end + + def fill_ems_utilization(m, time, used_cpu, used_mem, total_cpu, total_mem) + used_cpu[time] += m.v_derived_cpu_total_cores_used if m.v_derived_cpu_total_cores_used.present? + used_mem[time] += m.derived_memory_used if m.derived_memory_used.present? + total_cpu[time] += m.derived_vm_numvcpus if m.derived_vm_numvcpus.present? + total_mem[time] += m.derived_memory_available if m.derived_memory_available.present? + end + + def realtime_ems_utilization + used_cpu = Hash.new(0) + used_mem = Hash.new(0) + total_cpu = Hash.new(0) + total_mem = Hash.new(0) + + realtime_provider_metrics.each do |m| + minute = m.timestamp.beginning_of_minute.utc + fill_ems_utilization(m, minute, used_cpu, used_mem, total_cpu, total_mem) + end + + { + :interval_name => "realtime", + :xy_data => ems_utilization_data(used_cpu, total_cpu, used_mem, total_mem) || {:cpu => nil, :mem => nil} + } + end + + def hourly_ems_utilization + used_cpu = Hash.new(0) + used_mem = Hash.new(0) + total_cpu = Hash.new(0) + total_mem = Hash.new(0) + + hourly_provider_metrics.each do |m| + hour = m.timestamp.beginning_of_hour.utc + fill_ems_utilization(m, hour, used_cpu, used_mem, total_cpu, total_mem) + end + + if used_cpu.any? + { + :interval_name => "hourly", + :xy_data => ems_utilization_data(used_cpu, total_cpu, used_mem, total_mem) + } + end + end + + def daily_ems_utilization used_cpu = Hash.new(0) used_mem = Hash.new(0) total_cpu = Hash.new(0) @@ -157,12 +212,18 @@ def ems_utilization daily_provider_metrics.each do |metric| date = metric.timestamp.strftime("%Y-%m-%d") - used_cpu[date] += metric.v_derived_cpu_total_cores_used if metric.v_derived_cpu_total_cores_used.present? - used_mem[date] += metric.derived_memory_used if metric.derived_memory_used.present? - total_cpu[date] += metric.derived_vm_numvcpus if metric.derived_vm_numvcpus.present? - total_mem[date] += metric.derived_memory_available if metric.derived_memory_available.present? + fill_ems_utilization(metric, date, used_cpu, used_mem, total_cpu, total_mem) end + if used_cpu.any? + { + :interval_name => "daily", + :xy_data => ems_utilization_data(used_cpu, total_cpu, used_mem, total_mem) + } + end + end + + def ems_utilization_data(used_cpu, total_cpu, used_mem, total_mem) if used_cpu.any? { :cpu => { @@ -178,26 +239,37 @@ def ems_utilization :yData => used_mem.values.map { |m| (m / 1024.0).round } } } - else - { - :cpu => nil, - :mem => nil - } end end + def ems_utilization + daily_ems_utilization || hourly_ems_utilization || realtime_ems_utilization + end + + def realtime_network_metrics + realtime_network_metrics = Hash.new(0) + realtime_provider_metrics.each do |m| + minute = m.timestamp.beginning_of_minute.utc + realtime_network_metrics[minute] += m.net_usage_rate_average if m.net_usage_rate_average.present? + end + + { + :interval_name => "realtime", + :xy_data => trend_data(realtime_network_metrics) + } + end + def hourly_network_metrics - hourly_network_trend = Hash.new(0) - MetricRollup.with_interval_and_time_range("hourly", (1.day.ago.beginning_of_hour.utc)..(Time.now.utc)) - .where(:resource => (@ems || ManageIQ::Providers::ContainerManager.all)).each do |m| + hourly_network_metrics = Hash.new(0) + hourly_provider_metrics.each do |m| hour = m.timestamp.beginning_of_hour.utc - hourly_network_trend[hour] += m.net_usage_rate_average if m.net_usage_rate_average.present? + hourly_network_metrics[hour] += m.net_usage_rate_average if m.net_usage_rate_average.present? end - if hourly_network_trend.any? + if hourly_network_metrics.size > 1 { - :xData => hourly_network_trend.keys, - :yData => hourly_network_trend.values.map(&:round) + :interval_name => "hourly", + :xy_data => trend_data(hourly_network_metrics) } end end @@ -209,39 +281,83 @@ def daily_network_metrics daily_network_metrics[day] += m.net_usage_rate_average if m.net_usage_rate_average.present? end - if daily_network_metrics.any? + if daily_network_metrics.size > 1 { - :xData => daily_network_metrics.keys, - :yData => daily_network_metrics.values.map(&:round) + :interval_name => "daily", + :xy_data => trend_data(daily_network_metrics) } end end - def fill_daily_pod_metrics(metrics, pod_create_trend, pod_delete_trend) - metrics.each do |m| - timestamp = m.timestamp.strftime("%Y-%m-%d") + def network_metrics + daily_network_metrics || hourly_network_metrics || realtime_network_metrics + end + + def fill_pod_metrics(m, time, pod_create_trend, pod_delete_trend) + pod_create_trend[time] += m.stat_container_group_create_rate if m.stat_container_group_create_rate.present? + pod_delete_trend[time] += m.stat_container_group_delete_rate if m.stat_container_group_delete_rate.present? + end - pod_create_trend[timestamp] += m.stat_container_group_create_rate if m.stat_container_group_create_rate.present? - pod_delete_trend[timestamp] += m.stat_container_group_delete_rate if m.stat_container_group_delete_rate.present? + def hourly_pod_metrics + hourly_pod_create_trend = Hash.new(0) + hourly_pod_delete_trend = Hash.new(0) + hourly_provider_metrics.each do |m| + hour = m.timestamp.beginning_of_hour.utc + fill_pod_metrics(m, hour, hourly_pod_create_trend, hourly_pod_delete_trend) end + + { + :interval_name => "hourly", + :xy_data => create_delete_data(hourly_pod_create_trend, hourly_pod_delete_trend) + } end def daily_pod_metrics daily_pod_create_trend = Hash.new(0) daily_pod_delete_trend = Hash.new(0) - fill_daily_pod_metrics(daily_provider_metrics, - daily_pod_create_trend, daily_pod_delete_trend) + daily_provider_metrics.each do |m| + date = m.timestamp.strftime("%Y-%m-%d") + fill_pod_metrics(m, date, daily_pod_create_trend, daily_pod_delete_trend) + end + + if daily_pod_create_trend.size > 1 + { + :interval_name => "daily", + :xy_data => create_delete_data(daily_pod_create_trend, daily_pod_delete_trend) + } + end + end + + def pod_metrics + daily_pod_metrics || hourly_pod_metrics + end - if daily_pod_create_trend.any? + def create_delete_data(create_trend, delete_trend) + if create_trend.any? { - :xData => daily_pod_create_trend.keys, - :yCreated => daily_pod_create_trend.values.map(&:round), - :yDeleted => daily_pod_delete_trend.values.map(&:round) + :xData => create_trend.keys, + :yCreated => create_trend.values.map(&:round), + :yDeleted => delete_trend.values.map(&:round) } end end + def hourly_image_metrics + hourly_image_metrics = Hash.new(0) + hourly_provider_metrics.each do |m| + hour = m.timestamp.beginning_of_hour.utc + if m.stat_container_image_registration_rate.present? + hourly_image_metrics[hour] += m.stat_container_image_registration_rate + end + end + + { + :interval_name => "hourly", + :xy_data => trend_data(hourly_image_metrics) + } + end + def daily_image_metrics daily_image_metrics = Hash.new(0) daily_provider_metrics.each do |m| @@ -250,14 +366,40 @@ def daily_image_metrics m.stat_container_image_registration_rate if m.stat_container_image_registration_rate.present? end - if daily_image_metrics.any? + if daily_image_metrics.size > 1 { - :xData => daily_image_metrics.keys, - :yData => daily_image_metrics.values.map(&:round) + :interval_name => "daily", + :xy_data => trend_data(daily_image_metrics) } end end + def image_metrics + daily_image_metrics || hourly_image_metrics + end + + def trend_data(trend) + if trend.any? + { + :xData => trend.keys, + :yData => trend.values.map(&:round) + } + end + end + + def realtime_provider_metrics + current_user = @controller.current_user + tp = TimeProfile.profile_for_user_tz(current_user.id, current_user.get_timezone) || TimeProfile.default_time_profile + Metric::Helper.find_for_interval_name('realtime', tp) + .where(:resource => (@ems.try(:container_nodes) || ContainerNode.all)) + .where('timestamp > ?', 10.minutes.ago.utc).order('timestamp') + end + + def hourly_provider_metrics + MetricRollup.with_interval_and_time_range("hourly", (1.day.ago.beginning_of_hour.utc)..(Time.now.utc)) + .where(:resource => (@ems || ManageIQ::Providers::ContainerManager.all)) + end + def daily_provider_metrics current_user = @controller.current_user tp = TimeProfile.profile_for_user_tz(current_user.id, current_user.get_timezone) || TimeProfile.default_time_profile diff --git a/app/views/ems_container/_show_dashboard.html.haml b/app/views/ems_container/_show_dashboard.html.haml index 0bef5d901e9..614b1242828 100644 --- a/app/views/ems_container/_show_dashboard.html.haml +++ b/app/views/ems_container/_show_dashboard.html.haml @@ -78,7 +78,7 @@ "pf-utilization-trend-chart" => "", "sparkline-config" => "cpuUsageSparklineConfig"} %span.trend-footer-pf{"ng-class" => "{ 'chart-transparent-text': !cpuUsageData }"} - = _("Last 30 Days") + {{cpuUsageConfig.timeFrame}} .col-xs-6.col-sm-6.col-md-6 %div{"ng-if" => "memoryUsageData"} @@ -88,35 +88,35 @@ "pf-utilization-trend-chart" => "", "sparkline-config" => "memoryUsageSparklineConfig"} %span.trend-footer-pf{"ng-class" => "{ 'chart-transparent-text': !memoryUsageData }"} - = _("Last 30 Days") + {{memoryUsageConfig.timeFrame}} .col-xs-12.col-sm-6.col-md-5 .row.row-tile-pf .col-xs-12.col-sm-12.col-md-12 - %div{"head-title" => "{{networkUtilizationDailyConfig.headTitle}}", + %div{"head-title" => "{{networkUtilizationConfig.headTitle}}", "pf-card" => ""} .spinner.spinner-lg.loading{"ng-if" => "!loadingDone"} - %div{"chart-data" => "dailyNetworkUtilization", + %div{"chart-data" => "networkUtilization", "chart-height" => "chartHeight", - :config => "networkUtilizationDailyConfig", + :config => "networkUtilizationConfig", "ng-if" => "loadingDone", "pf-trends-chart" => ""} .row.row-tile-pf .col-xs-12.col-sm-12.col-md-12 - %div{"head-title" => "{{imageEntityTrendDailyConfig.headTitle}}", + %div{"head-title" => "{{imageEntityTrendConfig.headTitle}}", "pf-card" => ""} - .spinner.spinner-lg.loading{"ng-if" => "!imageEntityTrendDailyConfig"} - %div{"chart-data" => "dailyImageEntityTrend", + .spinner.spinner-lg.loading{"ng-if" => "!imageEntityTrendConfig"} + %div{"chart-data" => "imageEntityTrend", "chart-height" => "chartHeight", - :config => "imageEntityTrendDailyConfig", + :config => "imageEntityTrendConfig", "ng-if" => "loadingDone", "pf-line-chart" => ""} - %span.trend-footer-pf{"ng-class" => "{ 'chart-transparent-text': !imageEntityTrendDailyConfig }"} - = _("Last 30 Days") + %span.trend-footer-pf{"ng-class" => "{ 'chart-transparent-text': !imageEntityTrendConfig }"} + {{imageEntityTrendConfig.timeFrame}} .row.row-tile-pf.row-tile-pf-last .col-xs-12.col-sm-6.col-md-7 @@ -131,18 +131,18 @@ .col-xs-12.col-sm-6.col-md-5 .row.row-tile-pf .col-xs-12.col-sm-12.col-md-12 - %div{"head-title" => "{{podEntityTrendDailyConfig.headTitle}}", + %div{"head-title" => "{{podEntityTrendConfig.headTitle}}", "pf-card" => ""} - .spinner.spinner-lg.loading{"ng-if" => "!podEntityTrendDailyConfig"} - %div{"chart-data" => "dailyPodEntityTrend", + .spinner.spinner-lg.loading{"ng-if" => "!podEntityTrendConfig"} + %div{"chart-data" => "podEntityTrend", "chart-height" => "chartHeight", - :config => "podEntityTrendDailyConfig", + :config => "podEntityTrendConfig", "ng-if" => "loadingDone", "pf-line-chart" => ""} - %span.trend-footer-pf{"ng-class" => "{ 'chart-transparent-text': !podEntityTrendDailyConfig }"} - = _("Last 30 Days") + %span.trend-footer-pf{"ng-class" => "{ 'chart-transparent-text': !podEntityTrendConfig }"} + {{podEntityTrendConfig.timeFrame}} :javascript miq_bootstrap('.containers-dashboard'); diff --git a/spec/javascripts/controllers/containers/container_dashboard_controller_spec.js b/spec/javascripts/controllers/containers/container_dashboard_controller_spec.js index 88b991d3501..93ea1efb7e2 100644 --- a/spec/javascripts/controllers/containers/container_dashboard_controller_spec.js +++ b/spec/javascripts/controllers/containers/container_dashboard_controller_spec.js @@ -47,11 +47,11 @@ describe('containerDashboardController gets data and', function() { }); it('in network metrics', function() { - expect($scope.dailyNetworkUtilization).toBeDefined(); + expect($scope.networkUtilization).toBeDefined(); }); it('in pod metrics', function() { - expect($scope.dailyPodEntityTrend).toBeDefined(); + expect($scope.podEntityTrend).toBeDefined(); }); }); }); @@ -105,11 +105,11 @@ describe('containerDashboardController gets no data and', function() { }); it('in network metrics', function() { - expect($scope.dailyNetworkUtilization.dataAvailable).toBeDefined(); + expect($scope.networkUtilization.dataAvailable).toBeDefined(); }); it('in pod metrics', function() { - expect($scope.dailyPodEntityTrend.dataAvailable).toBeDefined(); + expect($scope.podEntityTrend.dataAvailable).toBeDefined(); }); }); }); @@ -161,11 +161,11 @@ describe('containerDashboardController gets data for one provider and', function }); it('in network metrics', function() { - expect($scope.dailyNetworkUtilization).toBeDefined(); + expect($scope.networkUtilization).toBeDefined(); }); it('in pod metrics', function() { - expect($scope.dailyPodEntityTrend).toBeDefined(); + expect($scope.podEntityTrend).toBeDefined(); }); }); }); diff --git a/spec/javascripts/fixtures/json/container_dashboard_no_data_response.json b/spec/javascripts/fixtures/json/container_dashboard_no_data_response.json index 649e9273937..9cee93840e7 100644 --- a/spec/javascripts/fixtures/json/container_dashboard_no_data_response.json +++ b/spec/javascripts/fixtures/json/container_dashboard_no_data_response.json @@ -57,11 +57,23 @@ } ], "ems_utilization": { - "cpu": null, - "mem": null + "interval_name": "realtime", + "xy_data": { + "cpu": null, + "mem": null + } + }, + "network_metrics" : { + "interval_name": "realtime", + "xy_data": null + }, + "pod_metrics" : { + "interval_name": "hourly", + "xy_data": null }, - "daily_network_metrics" : null, - "daily_pod_metrics" : null, - "daily_image_metrics" : null + "image_metrics" : { + "interval_name": "hourly", + "xy_data": null + } } } diff --git a/spec/javascripts/fixtures/json/container_dashboard_response.json b/spec/javascripts/fixtures/json/container_dashboard_response.json index 770362ac1b7..39225234cd8 100644 --- a/spec/javascripts/fixtures/json/container_dashboard_response.json +++ b/spec/javascripts/fixtures/json/container_dashboard_response.json @@ -73,60 +73,72 @@ } ], "ems_utilization": { - "cpu": { - "total": 8, - "used": 3, + "interval_name": "daily", + "xy_data": { + "cpu": { + "total": 8, + "used": 3, + "xData": [ + "2015-11-26" + ], + "yData": [ + 3 + ] + }, + "mem": { + "total": 21, + "used": 12, + "xData": [ + "2015-11-26" + ], + "yData": [ + 12 + ] + } + } + }, + "network_metrics" : { + "interval_name": "daily", + "xy_data": { "xData": [ - "2015-11-26" + "2015-12-07", + "2015-12-08" ], "yData": [ - 3 + 2420, + 2431 ] - }, - "mem": { - "total": 21, - "used": 12, + } + }, + "pod_metrics" : { + "interval_name": "daily", + "xy_data": { "xData": [ - "2015-11-26" + "2015-12-07", + "2015-12-08" ], - "yData": [ - 12 + "yCreated": [ + 8, + 87 + ], + "yDeleted": [ + 38, + 42 ] } }, - "daily_network_metrics" : { - "xData": [ - "2015-12-07", - "2015-12-08" - ], - "yData": [ - 2420, - 2431 - ] - }, - "daily_pod_metrics" : { - "xData": [ - "2015-12-07", - "2015-12-08" - ], - "yCreated": [ - 8, - 87 - ], - "yDeleted": [ - 38, - 42 - ] - }, - "daily_image_metrics" : { - "xData": [ - "2015-12-07", - "2015-12-08" - ], - "yData": [ - 23, - 45 - ] + "image_metrics" : { + "interval_name": "daily", + "xy_data": { + "xData": [ + "2015-12-07", + "2015-12-08" + ], + "yData": [ + 23, + 45 + ] + } } } } diff --git a/spec/services/container_dashboard_service_spec.rb b/spec/services/container_dashboard_service_spec.rb index 33e922d2927..eeffc13cb4a 100644 --- a/spec/services/container_dashboard_service_spec.rb +++ b/spec/services/container_dashboard_service_spec.rb @@ -71,8 +71,8 @@ ems_kubernetes.metric_rollups << old_metric.dup ems_kubernetes.metric_rollups << nil_fielded_metric.dup - node_utilization_all_providers = described_class.new(nil, controller).ems_utilization - node_utilization_single_provider = described_class.new(ems_openshift.id, controller).ems_utilization + node_utilization_all_providers = described_class.new(nil, controller).ems_utilization[:xy_data] + node_utilization_single_provider = described_class.new(ems_openshift.id, controller).ems_utilization[:xy_data] expect(node_utilization_single_provider).to eq( :cpu => { @@ -107,8 +107,8 @@ it "returns hash with nil values when no metrics available" do ems_openshift = FactoryGirl.create(:ems_openshift, :zone => @zone) - node_utilization_all_providers = described_class.new(nil, controller).ems_utilization - node_utilization_single_provider = described_class.new(ems_openshift.id, controller).ems_utilization + node_utilization_all_providers = described_class.new(nil, controller).ems_utilization[:xy_data] + node_utilization_single_provider = described_class.new(ems_openshift.id, controller).ems_utilization[:xy_data] expect(node_utilization_all_providers).to eq(:cpu => nil, :mem => nil) expect(node_utilization_single_provider).to eq(:cpu => nil, :mem => nil) end @@ -254,9 +254,17 @@ ems_openshift = FactoryGirl.create(:ems_openshift, :zone => @zone) ems_kubernetes = FactoryGirl.create(:ems_kubernetes, :zone => @zone) + previous_date = 8.days.ago current_date = 7.days.ago old_date = 35.days.ago + previous_metric_openshift = FactoryGirl.create( + :metric_rollup_cm_daily, + :timestamp => previous_date, + :net_usage_rate_average => 2000, + :time_profile => time_profile + ) + current_metric_openshift = FactoryGirl.create( :metric_rollup_cm_daily, :timestamp => current_date, @@ -275,22 +283,23 @@ :net_usage_rate_average => 1500, :time_profile => time_profile) + ems_openshift.metric_rollups << previous_metric_openshift ems_openshift.metric_rollups << current_metric_openshift ems_openshift.metric_rollups << old_metric ems_kubernetes.metric_rollups << current_metric_kubernetes ems_kubernetes.metric_rollups << old_metric.dup - daily_network_trends = described_class.new(nil, controller).daily_network_metrics - daily_network_trends_single_provider = described_class.new(ems_openshift.id, controller).daily_network_metrics + daily_network_trends = described_class.new(nil, controller).network_metrics[:xy_data] + daily_network_trends_single_provider = described_class.new(ems_openshift.id, controller).network_metrics[:xy_data] expect(daily_network_trends_single_provider).to eq( - :xData => [current_date.strftime("%Y-%m-%d")], - :yData => [1000] + :xData => [previous_date.strftime("%Y-%m-%d"), current_date.strftime("%Y-%m-%d")], + :yData => [2000, 1000] ) expect(daily_network_trends).to eq( - :xData => [current_date.strftime("%Y-%m-%d")], - :yData => [2500] + :xData => [previous_date.strftime("%Y-%m-%d"), current_date.strftime("%Y-%m-%d")], + :yData => [2000, 2500] ) end @@ -298,9 +307,17 @@ ems_openshift = FactoryGirl.create(:ems_openshift, :zone => @zone) ems_kubernetes = FactoryGirl.create(:ems_kubernetes, :zone => @zone) + previous_date = 3.hours.ago current_date = 2.hours.ago old_date = 2.days.ago + previous_metric_openshift = FactoryGirl.create( + :metric_rollup_cm_hr, + :timestamp => previous_date, + :net_usage_rate_average => 2000, + :time_profile => time_profile + ) + current_metric_openshift = FactoryGirl.create( :metric_rollup_cm_hr, :timestamp => current_date, @@ -324,6 +341,7 @@ :timestamp => old_date, :time_profile => time_profile) + ems_openshift.metric_rollups << previous_metric_openshift ems_openshift.metric_rollups << current_metric_openshift ems_openshift.metric_rollups << old_metric ems_openshift.metric_rollups << nil_fields_metric @@ -331,17 +349,18 @@ ems_kubernetes.metric_rollups << old_metric.dup ems_kubernetes.metric_rollups << nil_fields_metric.dup - hourly_network_trends = described_class.new(nil, controller).hourly_network_metrics - hourly_network_trends_single_provider = described_class.new(ems_openshift.id, controller).hourly_network_metrics + hourly_network_trends = described_class.new(nil, controller).network_metrics[:xy_data] + hourly_network_trends_single_provider = + described_class.new(ems_openshift.id, controller).network_metrics[:xy_data] expect(hourly_network_trends_single_provider).to eq( - :xData => [current_date.beginning_of_hour.utc], - :yData => [1000] + :xData => [previous_date.beginning_of_hour.utc, current_date.beginning_of_hour.utc], + :yData => [2000, 1000] ) expect(hourly_network_trends).to eq( - :xData => [current_date.beginning_of_hour.utc], - :yData => [2500] + :xData => [previous_date.beginning_of_hour.utc, current_date.beginning_of_hour.utc], + :yData => [2000, 2500] ) end