Skip to content

Commit

Permalink
Add a dashboard view for a physical infra provider
Browse files Browse the repository at this point in the history
  • Loading branch information
felipedf committed Apr 11, 2018
1 parent d9ae734 commit 298943a
Show file tree
Hide file tree
Showing 21 changed files with 470 additions and 95 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,17 @@ angular.module('miq.util').factory('chartsMixin', ['$document', function($docume
grid: {y: {show: false}},
setAreaChart: true,
},
recentServersConfig: {
chartId: 'recentVmsChart',
tooltip: {
contents: dailyTimeTooltip,
position: lineChartTooltipPositionFactory('recentVmsChart'),
},
point: {r: 1},
size: {height: 145},
grid: {y: {show: false}},
setAreaChart: true,
},
};

var processData = function(data, xDataLabel, yDataLabel) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
angular.module( 'patternfly.charts' ).controller('utilizationTrendChartController', ['$q', 'providerId', 'chartsMixin', '$http', 'miqService', function($q, providerId, chartsMixin, $http, miqService) {
angular.module( 'patternfly.charts' ).controller('utilizationTrendChartController', ['$q', 'providerDashboard', 'providerId', 'chartsMixin', '$http', 'miqService', function($q, providerDashboard, providerId, chartsMixin, $http, miqService) {
var vm = this;

var init = function() {
ManageIQ.angular.scope = vm;
vm.data = {};
vm.loadingDone = false;

var url = '/ems_infra_dashboard/ems_utilization_data/' + providerId;
var url = '/' + providerDashboard + '/ems_utilization_data/' + providerId;
var metricsPromise = $http.get(url)
.then(function(response) {
vm.metricsData = response.data.data;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/* global miqHttpInject */
angular.module( 'patternfly.charts' ).controller( 'recentServersLineChartController', ['$q', 'providerId', '$http', 'chartsMixin', 'miqService', function($q, providerId, $http, chartsMixin, miqService) {
var vm = this;
vm.id = "recentServersLineChart_" + providerId;
var init = function() {
ManageIQ.angular.scope = vm;
vm.loadingDone = false;
vm.config = chartsMixin.chartConfig.recentServersConfig;
vm.timeframeLabel = __('Last 30 Days');
var url = '/ems_physical_infra_dashboard/recent_servers_data/' + providerId;
var serversDataPromise = $http.get(url)
.then(function(response) {
vm.data = response.data.data;
})
.catch(miqService.handleFailure);

$q.all([serversDataPromise]).then(function() {
if (vm.data.recentServers.dataAvailable === false) {
vm.data.dataAvailable = false;
} else {
vm.data = chartsMixin.processData(vm.data.recentServers, 'dates', vm.data.recentServers.config.label);
}
Object.assign(vm.config, vm.data);
vm.loadingDone = true;
});

vm.custShowXAxis = false;
vm.custShowYAxis = false;
vm.custAreaChart = true;
};

init();
}]);
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/* global miqHttpInject */

angular.module( 'patternfly.card' ).controller('statusCardController', ['$q', 'providerId', 'API', 'miqService', 'chartsMixin', function($q, providerId, API, miqService, chartsMixin) {
var vm = this;
var attributes = ["physical_servers", "physical_racks"];

var attrIconHsh = {
"physical_servers": "pficon pficon-cluster",
"physical_racks": "pficon pficon-enterprise",
};

var attrUrl = {
"physical_servers": "physical_servers",
"physical_racks": "physical_racks",
};

var init = function() {
ManageIQ.angular.scope = vm;
var promiseProviderData = API.get("/api/providers/" + providerId + "?attributes=" + attributes)
.then(function(data) {
vm.provider = data;
})
.catch(miqService.handleFailure);

$q.all([promiseProviderData]).then(function() {
vm.status = {
"iconImage": "/assets/svg/vendor-" + getIcon(vm.provider.type) + ".svg",
"largeIcon": true,
};

var attrHsh = {
"physical_servers": "Servers",
"physical_racks": "Racks",
};

vm.AggStatus = [];
for (var i = 0; i < attributes.length; i++) {
vm.AggStatus.push({
"id": attrHsh[attributes[i]] + '_' + providerId,
"iconClass": attrIconHsh[attributes[i]],
"title": __(attrHsh[attributes[i]]),
"count": vm.provider[attributes[i]].length,
"href": getUrl(attributes[i]),
"notification": {
"iconClass": "pficon pficon-error-circle-o",
"count": 0,
},
});
}
});
};

var getIcon = function getIcon(providerType) {
var type = providerType.split("::");
return type[2].toLowerCase();
};

var getUrl = function(entity) {
return providerId + "?display=" + attrUrl[entity];
};

init();
}]);
3 changes: 1 addition & 2 deletions app/assets/javascripts/services/topology_service.js
Original file line number Diff line number Diff line change
Expand Up @@ -270,9 +270,8 @@ ManageIQ.angular.app.service('topologyService', ['$location', '$http', 'miqServi
return controller.dataUrl;
}

var match = screenUrl.match(/(ems_container|show)\/([0-9]+)\?display=topology$/) ||
var match = screenUrl.match(/(ems_container|ems_physical_infra|show)\/([0-9]+)\?display=topology$/) ||
screenUrl.match(/(_topology)\/show\/([0-9]+)\/?$/);

if (match) {
var id = match[2];
var url = controller.detailUrl || controller.dataUrl;
Expand Down
1 change: 1 addition & 0 deletions app/controllers/ems_physical_infra_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ class EmsPhysicalInfraController < ApplicationController
include EmsCommon # common methods for EmsInfra/Cloud controllers
include Mixins::EmsCommonAngular
include Mixins::GenericSessionMixin
include Mixins::DashboardViewMixin

before_action :check_privileges
before_action :get_session_data
Expand Down
64 changes: 64 additions & 0 deletions app/controllers/ems_physical_infra_dashboard_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
class EmsPhysicalInfraDashboardController < ApplicationController
extend ActiveSupport::Concern

before_action :check_privileges
before_action :get_session_data
after_action :cleanup_action
after_action :set_session_data

def show
if params[:id].nil?
@breadcrumbs.clear
end
end

def data
render :json => {:data => collect_data(params[:id])}
end

def cluster_metrics_data
render :json => {:data => cluster_heatmap_data(params[:id])}
end

def recent_servers_data
render :json => {:data => recent_servers(params[:id])}
end

def recent_vms_data
render :json => {:data => recent_vms(params[:id])}
end

def ems_utilization_data
render :json => {:data => ems_data(params[:id])}
end

private

def collect_data(ems_id)
EmsPhysicalInfraDashboardService.new(ems_id, self).all_data
end

def cluster_heatmap_data(ems_id)
EmsPhysicalInfraDashboardService.new(ems_id, self).cluster_heatmap_data
end

def recent_servers(ems_id)
EmsPhysicalInfraDashboardService.new(ems_id, self).recent_servers_data
end

def recent_vms(ems_id)
EmsPhysicalInfraDashboardService.new(ems_id, self).recent_vms_data
end

def ems_data(ems_id)
EmsPhysicalInfraDashboardService.new(ems_id, self).ems_utilization_data
end

def get_session_data
@layout = "ems_physical_infra_dashboard"
end

def set_session_data
session[:layout] = @layout
end
end
2 changes: 1 addition & 1 deletion app/helpers/application_helper/toolbar_chooser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def view_toolbar_filename
'compare_view_tb'
elsif @lastaction == "drift"
'drift_view_tb'
elsif %w(ems_container ems_infra).include?(@layout) && %w(main dashboard topology).include?(@display)
elsif %w(ems_container ems_infra ems_physical_infra).include?(@layout) && %w(main dashboard topology).include?(@display)
'dashboard_summary_toggle_view_tb'
elsif %w(container_project).include?(@layout)
'container_project_view_tb'
Expand Down
149 changes: 149 additions & 0 deletions app/services/ems_physical_infra_dashboard_service.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
class EmsPhysicalInfraDashboardService < DashboardService
include UiServiceMixin
CPU_USAGE_PRECISION = 2 # 2 decimal points

def initialize(ems_id, controller)
@ems_id = ems_id
@ems = EmsPhysicalInfra.find(@ems_id) unless @ems_id.blank?
@controller = controller
end

def cluster_heatmap_data
{
:heatmaps => heatmaps
}.compact
end

def recent_servers_data
{
:recentServers => recent_servers
}.compact
end

def recent_vms_data
{
:recentVms => recentVms
}.compact
end

def ems_utilization_data
{
:ems_utilization => ems_utilization
}.compact
end

def heatmaps
# Get latest hourly rollup for each node.
cluster_ids = @ems.ems_clusters if @ems.present?
metrics = MetricRollup.latest_rollups(EmsCluster.name, cluster_ids)
metrics = metrics.where('timestamp > ?', 30.days.ago.utc).includes(:resource)
metrics = metrics.includes(:resource => [:ext_management_system]) unless @ems.present?

cluster_cpu_usage = []
cluster_memory_usage = []

metrics.each do |m|
next if m.resource.nil? # Metrics are purged asynchronously and might be missing their node
provider_name = @ems.present? ? @ems.name : m.resource.ext_management_system.name

cluster_cpu_usage << {
:id => m.resource.id,
:node => m.resource.name,
:provider => provider_name,
:unit => "Cores",
:total => m.derived_vm_numvcpus.present? ? m.derived_vm_numvcpus.round : nil,
:percent => m.cpu_usage_rate_average.present? ?
(m.cpu_usage_rate_average / 100.0).round(CPU_USAGE_PRECISION) : nil # pf accepts fractions 90% = 0.90
}

cluster_memory_usage << {
:id => m.resource.id,
:node => m.resource.name,
:provider => m.resource.ext_management_system.name,
:unit => "GB",
:total => m.derived_memory_available.present? ? (m.derived_memory_available / 1024).round : nil,
:percent => m.mem_usage_absolute_average.present? ?
(m.mem_usage_absolute_average / 100.0).round(CPU_USAGE_PRECISION) : nil # pf accepts fractions 90% = 0.90
}
end

{
:clusterCpuUsage => cluster_cpu_usage.presence,
:clusterMemoryUsage => cluster_memory_usage.presence,
:title => openstack? ? _('Deployment Roles Utilization') : _('Cluster Utilization')
}
end

def recent_servers
# Get recent servers
all_servers = recentRecords(PhysicalServer)
config = {
:title => _('Recent Servers'),
:label => _('Servers')
}
return { :dataAvailable => false, :config => config} if all_servers.blank?
{
:dataAvailable => true,
:xData => all_servers.keys,
:yData => all_servers.values.map,
:config => config
}
end

def recentVms
# Get recent VMs
all_vms = recentRecords(VmOrTemplate)
config = {
:title => _('Recent VMs'),
:label => _('VMs'),
}
return { :dataAvailable => false, :config => config } if all_vms.blank?
{
:dataAvailable => true,
:xData => all_vms.keys,
:yData => all_vms.values.map,
:config => config
}
end

def recentRecords(model)
all_records = Hash.new(0)
records = model.where('created_at > ? and ems_id = ?', 30.days.ago.utc, @ems.id)
records = records.includes(:resource => [:ext_management_system]) unless @ems.present?
records.sort_by { |r| r.created_at }.uniq.each do |r|
date = r.created_at.strftime("%Y-%m-%d")
all_records[date] += model.where('created_at = ?', r.created_at).count
end
all_records
end

def ems_utilization
used_cpu = Hash.new(0)
used_mem = Hash.new(0)
total_cpu = Hash.new(0)
total_mem = Hash.new(0)

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?
end

format_utilization_data(used_cpu, used_mem, total_cpu, total_mem)
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

@daily_metrics ||= Metric::Helper.find_for_interval_name('daily', tp)
.where(:resource => (@ems || ManageIQ::Providers::InfraManager.all))
.where('timestamp > ?', 30.days.ago.utc).order('timestamp')
end

def openstack?
@ems.kind_of?(ManageIQ::Providers::Openstack::InfraManager)
end
end

0 comments on commit 298943a

Please sign in to comment.