From 6a2d9d3e3d80c6cbbfce0b4c4d398349f1e2b680 Mon Sep 17 00:00:00 2001 From: lpichler Date: Mon, 30 Oct 2017 09:02:54 +0100 Subject: [PATCH 01/14] Add metering reports - to be able add/edit in UI - restrict column reporting columns(storing report definition) --- app/models/chargeback.rb | 2 +- app/models/metering_container_image.rb | 15 +++++++++++++++ app/models/metering_container_project.rb | 15 +++++++++++++++ app/models/metering_vm.rb | 20 ++++++++++++++++++++ config/miq_expression.yml | 3 +++ 5 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 app/models/metering_container_image.rb create mode 100644 app/models/metering_container_project.rb create mode 100644 app/models/metering_vm.rb diff --git a/app/models/chargeback.rb b/app/models/chargeback.rb index 643917b9373..2bcb9a06ea9 100644 --- a/app/models/chargeback.rb +++ b/app/models/chargeback.rb @@ -145,7 +145,7 @@ def calculate_costs(consumption, rates) end def self.report_cb_model(model) - model.gsub(/^Chargeback/, "") + model.gsub(/^(Chargeback|Metering)/, "") end def self.db_is_chargeback?(db) diff --git a/app/models/metering_container_image.rb b/app/models/metering_container_image.rb new file mode 100644 index 00000000000..d8d4319862a --- /dev/null +++ b/app/models/metering_container_image.rb @@ -0,0 +1,15 @@ +class MeteringContainerImage < ChargebackContainerImage + def self.report_col_options + { + "cpu_cores_used_metric" => {:grouping => [:total]}, + "fixed_compute_metric" => {:grouping => [:total]}, + "memory_used_metric" => {:grouping => [:total]}, + "metering_used_metric" => {:grouping => [:total]}, + "net_io_used_metric" => {:grouping => [:total]}, + } + end + + def self.build_results_for_report_MeteringContainerImage(options) + build_results_for_report_ChargebackContainerImage(options) + end +end diff --git a/app/models/metering_container_project.rb b/app/models/metering_container_project.rb new file mode 100644 index 00000000000..ea0e2d5aee1 --- /dev/null +++ b/app/models/metering_container_project.rb @@ -0,0 +1,15 @@ +class MeteringContainerProject < ChargebackContainerProject + def self.report_col_options + { + "cpu_cores_used_metric" => {:grouping => [:total]}, + "fixed_compute_metric" => {:grouping => [:total]}, + "memory_used_metric" => {:grouping => [:total]}, + "metering_used_metric" => {:grouping => [:total]}, + "net_io_used_metric" => {:grouping => [:total]}, + } + end + + def self.build_results_for_report_MeteringContainerProject(options) + build_results_for_report_ChargebackContainerProject(options) + end +end diff --git a/app/models/metering_vm.rb b/app/models/metering_vm.rb new file mode 100644 index 00000000000..3d0583f472e --- /dev/null +++ b/app/models/metering_vm.rb @@ -0,0 +1,20 @@ +class MeteringVm < ChargebackVm + def self.report_col_options + { + "cpu_allocated_metric" => {:grouping => [:total]}, + "cpu_used_metric" => {:grouping => [:total]}, + "disk_io_used_metric" => {:grouping => [:total]}, + "fixed_compute_metric" => {:grouping => [:total]}, + "memory_allocated_metric" => {:grouping => [:total]}, + "memory_used_metric" => {:grouping => [:total]}, + "metering_used_metric" => {:grouping => [:total]}, + "net_io_used_metric" => {:grouping => [:total]}, + "storage_allocated_metric" => {:grouping => [:total]}, + "storage_used_metric" => {:grouping => [:total]}, + } + end + + def self.build_results_for_report_MeteringVm(options) + build_results_for_report_ChargebackVm(options) + end +end diff --git a/config/miq_expression.yml b/config/miq_expression.yml index d07b14cff1b..3c8aad29cb7 100644 --- a/config/miq_expression.yml +++ b/config/miq_expression.yml @@ -61,6 +61,9 @@ - Switch - ManageIQ::Providers::CloudManager::Template - ManageIQ::Providers::InfraManager::Template +- MeteringContainerProject +- MeteringContainerImage +- MeteringVm - Tenant - User - VimPerformanceTrend From 5ddf7ea9885aa9b0af672b6459e013dc2cc708b9 Mon Sep 17 00:00:00 2001 From: lpichler Date: Mon, 30 Oct 2017 09:03:44 +0100 Subject: [PATCH 02/14] Disallow cost columns for metering reports --- lib/miq_expression.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/miq_expression.rb b/lib/miq_expression.rb index 0ab72adce6d..2762c5594a9 100644 --- a/lib/miq_expression.rb +++ b/lib/miq_expression.rb @@ -926,7 +926,9 @@ def self.reporting_available_fields(model, interval = nil) cb_model = Chargeback.report_cb_model(model) model.constantize.try(:refresh_dynamic_metric_columns) md = model_details(model, :include_model => false, :include_tags => true).select do |c| - c.last.ends_with?(*ReportController::Reports::Editor::CHARGEBACK_ALLOWED_FIELD_SUFFIXES) + allowed_suffixes = ReportController::Reports::Editor::CHARGEBACK_ALLOWED_FIELD_SUFFIXES + allowed_suffixes -= ['_cost'] if model.starts_with?('Metering') + c.last.ends_with?(*allowed_suffixes) end td = if TAG_CLASSES.include?(cb_model) tag_details(model, {}) + _custom_details_for(cb_model, {}) From 10e7f1ec0272e42f320914b4d9d6023fb98d6ac7 Mon Sep 17 00:00:00 2001 From: lpichler Date: Mon, 30 Oct 2017 09:07:05 +0100 Subject: [PATCH 03/14] Override method calculate cost don`t depend on rates only chargeable field is needed for getting metric value --- app/models/metering.rb | 13 +++++++++++++ app/models/metering_container_image.rb | 2 ++ app/models/metering_container_project.rb | 2 ++ app/models/metering_vm.rb | 2 ++ 4 files changed, 19 insertions(+) create mode 100644 app/models/metering.rb diff --git a/app/models/metering.rb b/app/models/metering.rb new file mode 100644 index 00000000000..80779d43de6 --- /dev/null +++ b/app/models/metering.rb @@ -0,0 +1,13 @@ +module Metering + def calculate_costs(consumption, _) + self.fixed_compute_metric = consumption.chargeback_fields_present if consumption.chargeback_fields_present + + relevant_fields.each do |field| + next unless self.class.report_col_options.include?(field) + group, source, * = field.split('_') + chargable_field = ChargeableField.find_by(:group => group, :source => source) + value = chargable_field.measure(consumption, @options) if chargable_field + self[field] = (value || 0) unless field == 'fixed_compute_metric' + end + end +end diff --git a/app/models/metering_container_image.rb b/app/models/metering_container_image.rb index d8d4319862a..95818237e1f 100644 --- a/app/models/metering_container_image.rb +++ b/app/models/metering_container_image.rb @@ -1,4 +1,6 @@ class MeteringContainerImage < ChargebackContainerImage + include Metering + def self.report_col_options { "cpu_cores_used_metric" => {:grouping => [:total]}, diff --git a/app/models/metering_container_project.rb b/app/models/metering_container_project.rb index ea0e2d5aee1..12736ed32ce 100644 --- a/app/models/metering_container_project.rb +++ b/app/models/metering_container_project.rb @@ -1,4 +1,6 @@ class MeteringContainerProject < ChargebackContainerProject + include Metering + def self.report_col_options { "cpu_cores_used_metric" => {:grouping => [:total]}, diff --git a/app/models/metering_vm.rb b/app/models/metering_vm.rb index 3d0583f472e..2f8762bf6ca 100644 --- a/app/models/metering_vm.rb +++ b/app/models/metering_vm.rb @@ -1,4 +1,6 @@ class MeteringVm < ChargebackVm + include Metering + def self.report_col_options { "cpu_allocated_metric" => {:grouping => [:total]}, From f1d9681763a2b37fcc4268e42ebaad369ecf9203 Mon Sep 17 00:00:00 2001 From: lpichler Date: Mon, 30 Oct 2017 09:08:23 +0100 Subject: [PATCH 04/14] Sum used metrics instead of averaging --- app/models/chargeable_field.rb | 4 ++++ app/models/chargeback/consumption_with_rollups.rb | 5 +++++ app/models/metering.rb | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/app/models/chargeable_field.rb b/app/models/chargeable_field.rb index 2c702faf8ad..be3167cdd3f 100644 --- a/app/models/chargeable_field.rb +++ b/app/models/chargeable_field.rb @@ -41,6 +41,10 @@ def showback_dimension "fixed_storage_2" => ['fixed_storage_2', '', 'occurrence']}[metric_index] end + def measure_metering(consumption, options, sub_metric = nil) + used? ? consumption.sum(metric) : measure(consumption, options, sub_metric) + end + def measure(consumption, options, sub_metric = nil) return consumption.consumed_hours_in_interval if metering? return 1.0 if fixed? diff --git a/app/models/chargeback/consumption_with_rollups.rb b/app/models/chargeback/consumption_with_rollups.rb index 1762ddb9a08..f8c37cedbeb 100644 --- a/app/models/chargeback/consumption_with_rollups.rb +++ b/app/models/chargeback/consumption_with_rollups.rb @@ -31,6 +31,11 @@ def tag_list_with_prefix @tag_list_with_prefix ||= @rollups.map(&:tag_list_with_prefix).flatten.uniq end + def sum(metric, sub_metric = nil) + metric = ChargeableField::VIRTUAL_COL_USES[metric] || metric + values(metric, sub_metric).sum + end + def max(metric, sub_metric = nil) values(metric, sub_metric).max end diff --git a/app/models/metering.rb b/app/models/metering.rb index 80779d43de6..f8c95a6804a 100644 --- a/app/models/metering.rb +++ b/app/models/metering.rb @@ -6,7 +6,7 @@ def calculate_costs(consumption, _) next unless self.class.report_col_options.include?(field) group, source, * = field.split('_') chargable_field = ChargeableField.find_by(:group => group, :source => source) - value = chargable_field.measure(consumption, @options) if chargable_field + value = chargable_field.measure_metering(consumption, @options) if chargable_field self[field] = (value || 0) unless field == 'fixed_compute_metric' end end From f8025d472a88527f66163e81f00f8e72f3c3c09b Mon Sep 17 00:00:00 2001 From: lpichler Date: Mon, 30 Oct 2017 09:38:45 +0100 Subject: [PATCH 05/14] Offer metering used hours only in metering reports --- app/models/chargeback.rb | 2 -- app/models/metering_container_image.rb | 4 ++++ app/models/metering_container_project.rb | 4 ++++ app/models/metering_vm.rb | 4 ++++ spec/models/chargeback_container_image_spec.rb | 3 +++ spec/models/chargeback_container_project_spec.rb | 3 +++ spec/models/chargeback_vm_spec.rb | 3 +++ 7 files changed, 21 insertions(+), 2 deletions(-) diff --git a/app/models/chargeback.rb b/app/models/chargeback.rb index 2bcb9a06ea9..7f7459e2a60 100644 --- a/app/models/chargeback.rb +++ b/app/models/chargeback.rb @@ -9,8 +9,6 @@ class Chargeback < ActsAsArModel :tag_name => :string, :label_name => :string, :fixed_compute_metric => :integer, - :metering_used_metric => :integer, - :metering_used_cost => :float ) def self.build_results_for_report_chargeback(options) diff --git a/app/models/metering_container_image.rb b/app/models/metering_container_image.rb index 95818237e1f..baff96f064f 100644 --- a/app/models/metering_container_image.rb +++ b/app/models/metering_container_image.rb @@ -1,4 +1,8 @@ class MeteringContainerImage < ChargebackContainerImage + set_columns_hash( + :metering_used_metric => :integer, + ) + include Metering def self.report_col_options diff --git a/app/models/metering_container_project.rb b/app/models/metering_container_project.rb index 12736ed32ce..c566dec9f60 100644 --- a/app/models/metering_container_project.rb +++ b/app/models/metering_container_project.rb @@ -1,4 +1,8 @@ class MeteringContainerProject < ChargebackContainerProject + set_columns_hash( + :metering_used_metric => :integer, + ) + include Metering def self.report_col_options diff --git a/app/models/metering_vm.rb b/app/models/metering_vm.rb index 2f8762bf6ca..a4f494edda2 100644 --- a/app/models/metering_vm.rb +++ b/app/models/metering_vm.rb @@ -1,4 +1,8 @@ class MeteringVm < ChargebackVm + set_columns_hash( # Fields common to any chargeback type + :metering_used_metric => :integer, + ) + include Metering def self.report_col_options diff --git a/spec/models/chargeback_container_image_spec.rb b/spec/models/chargeback_container_image_spec.rb index a50649beb62..15b010cb516 100644 --- a/spec/models/chargeback_container_image_spec.rb +++ b/spec/models/chargeback_container_image_spec.rb @@ -32,6 +32,9 @@ let(:metric_rollup_params) { {:parent_ems_id => ems.id, :tag_names => ""} } before do + # TODO: remove metering columns form specs + described_class.set_columns_hash(:metering_used_metric => :integer, :metering_used_cost => :float) + MiqRegion.seed ChargebackRateDetailMeasure.seed ChargeableField.seed diff --git a/spec/models/chargeback_container_project_spec.rb b/spec/models/chargeback_container_project_spec.rb index f3064c7b634..1c960622758 100644 --- a/spec/models/chargeback_container_project_spec.rb +++ b/spec/models/chargeback_container_project_spec.rb @@ -31,6 +31,9 @@ let(:metric_rollup_params) { {:parent_ems_id => ems.id, :tag_names => ""} } before do + # TODO: remove metering columns form specs + described_class.set_columns_hash(:metering_used_metric => :integer, :metering_used_cost => :float) + MiqRegion.seed ChargebackRateDetailMeasure.seed ChargeableField.seed diff --git a/spec/models/chargeback_vm_spec.rb b/spec/models/chargeback_vm_spec.rb index 61c7356aa9d..76fa6bc12e3 100644 --- a/spec/models/chargeback_vm_spec.rb +++ b/spec/models/chargeback_vm_spec.rb @@ -56,6 +56,9 @@ end before do + # TODO: remove metering columns form specs + described_class.set_columns_hash(:metering_used_metric => :integer, :metering_used_cost => :float) + MiqRegion.seed ChargebackRateDetailMeasure.seed ChargeableField.seed From 89d6e1f94599c3a85b8b5635481de2fe6466ddeb Mon Sep 17 00:00:00 2001 From: lpichler Date: Mon, 30 Oct 2017 09:40:58 +0100 Subject: [PATCH 06/14] Do not offer metering hours in rate editor --- db/fixtures/chargeback_rates.yml | 10 ---------- spec/models/chargeback_rate_detail_spec.rb | 1 - 2 files changed, 11 deletions(-) diff --git a/db/fixtures/chargeback_rates.yml b/db/fixtures/chargeback_rates.yml index 0eaad4ab04c..fc005abaa43 100644 --- a/db/fixtures/chargeback_rates.yml +++ b/db/fixtures/chargeback_rates.yml @@ -106,16 +106,6 @@ :finish: Infinity :fixed_rate: 0.0 :variable_rate: 0.0 - - :description: Metering - Hours Used - :metric: metering_used_hours - :per_time: hourly - :per_unit: hours - :type_currency: Dollars - :tiers: - - :start: 0 - :finish: Infinity - :fixed_rate: 0.0 - :variable_rate: 1 - :description: Default :guid: 7d7aaf20-5214-11df-a888-001d09066d98 :rate_type: Storage diff --git a/spec/models/chargeback_rate_detail_spec.rb b/spec/models/chargeback_rate_detail_spec.rb index 8df4a445262..b5b2ab34423 100644 --- a/spec/models/chargeback_rate_detail_spec.rb +++ b/spec/models/chargeback_rate_detail_spec.rb @@ -29,7 +29,6 @@ fixed_compute_2 derived_memory_available derived_memory_used - metering_used_hours net_usage_rate_average ) From 42882db196c823c45e48988e79579b51ab42beeb Mon Sep 17 00:00:00 2001 From: lpichler Date: Mon, 30 Oct 2017 10:07:45 +0100 Subject: [PATCH 07/14] FixBug:Use count of metric rollups for metering hours it is same as fixed compute metric Chargeable field is not used for getting metric value for metering hours metric and for fixed --- app/models/metering.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/models/metering.rb b/app/models/metering.rb index f8c95a6804a..3188c32ad4e 100644 --- a/app/models/metering.rb +++ b/app/models/metering.rb @@ -1,13 +1,15 @@ module Metering def calculate_costs(consumption, _) self.fixed_compute_metric = consumption.chargeback_fields_present if consumption.chargeback_fields_present + self.metering_used_metric = fixed_compute_metric relevant_fields.each do |field| next unless self.class.report_col_options.include?(field) group, source, * = field.split('_') chargable_field = ChargeableField.find_by(:group => group, :source => source) + next if field == "fixed_compute_metric" || chargable_field && chargable_field.metering? value = chargable_field.measure_metering(consumption, @options) if chargable_field - self[field] = (value || 0) unless field == 'fixed_compute_metric' + self[field] = (value || 0) end end end From ccb787d327206f2b1425a0d77759b265176850e4 Mon Sep 17 00:00:00 2001 From: lpichler Date: Mon, 30 Oct 2017 10:22:25 +0100 Subject: [PATCH 08/14] Add existence hours metric --- app/models/metering.rb | 3 ++- app/models/metering_container_image.rb | 1 + app/models/metering_container_project.rb | 1 + app/models/metering_vm.rb | 1 + 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/models/metering.rb b/app/models/metering.rb index 3188c32ad4e..beecb7e7e92 100644 --- a/app/models/metering.rb +++ b/app/models/metering.rb @@ -2,12 +2,13 @@ module Metering def calculate_costs(consumption, _) self.fixed_compute_metric = consumption.chargeback_fields_present if consumption.chargeback_fields_present self.metering_used_metric = fixed_compute_metric + self.existence_hours_metric = consumption.consumed_hours_in_interval relevant_fields.each do |field| next unless self.class.report_col_options.include?(field) group, source, * = field.split('_') chargable_field = ChargeableField.find_by(:group => group, :source => source) - next if field == "fixed_compute_metric" || chargable_field && chargable_field.metering? + next if field == "existence_hours_metric" || field == "fixed_compute_metric" || chargable_field && chargable_field.metering? value = chargable_field.measure_metering(consumption, @options) if chargable_field self[field] = (value || 0) end diff --git a/app/models/metering_container_image.rb b/app/models/metering_container_image.rb index baff96f064f..b46aa140644 100644 --- a/app/models/metering_container_image.rb +++ b/app/models/metering_container_image.rb @@ -1,6 +1,7 @@ class MeteringContainerImage < ChargebackContainerImage set_columns_hash( :metering_used_metric => :integer, + :existence_hours_metric => :interger ) include Metering diff --git a/app/models/metering_container_project.rb b/app/models/metering_container_project.rb index c566dec9f60..4b34c1aa4e4 100644 --- a/app/models/metering_container_project.rb +++ b/app/models/metering_container_project.rb @@ -1,6 +1,7 @@ class MeteringContainerProject < ChargebackContainerProject set_columns_hash( :metering_used_metric => :integer, + :existence_hours_metric => :interger ) include Metering diff --git a/app/models/metering_vm.rb b/app/models/metering_vm.rb index a4f494edda2..1f591e80333 100644 --- a/app/models/metering_vm.rb +++ b/app/models/metering_vm.rb @@ -1,6 +1,7 @@ class MeteringVm < ChargebackVm set_columns_hash( # Fields common to any chargeback type :metering_used_metric => :integer, + :existence_hours_metric => :integer ) include Metering From 3c7692882d31db63d5ed509d5b4b16de3bd79f3e Mon Sep 17 00:00:00 2001 From: lpichler Date: Mon, 30 Oct 2017 11:49:34 +0100 Subject: [PATCH 09/14] Fix mapping string field to ChargeableField --- app/models/metering.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/app/models/metering.rb b/app/models/metering.rb index beecb7e7e92..09032515559 100644 --- a/app/models/metering.rb +++ b/app/models/metering.rb @@ -7,6 +7,22 @@ def calculate_costs(consumption, _) relevant_fields.each do |field| next unless self.class.report_col_options.include?(field) group, source, * = field.split('_') + + if field == 'net_io_used_metric' + group = 'net_io' + source = 'used' + end + + if field == 'disk_io_used_metric' + group = 'disk_io' + source = 'used' + end + + if field == 'cpu_cores_used_metric' + group = 'cpu_cores' + source = 'used' + end + chargable_field = ChargeableField.find_by(:group => group, :source => source) next if field == "existence_hours_metric" || field == "fixed_compute_metric" || chargable_field && chargable_field.metering? value = chargable_field.measure_metering(consumption, @options) if chargable_field From 91e559fd840495f3eccb0caf9fc49798c4050ed6 Mon Sep 17 00:00:00 2001 From: lpichler Date: Mon, 30 Oct 2017 11:55:14 +0100 Subject: [PATCH 10/14] specs for MeteringVM --- spec/models/metering_vm_spec.rb | 81 +++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 spec/models/metering_vm_spec.rb diff --git a/spec/models/metering_vm_spec.rb b/spec/models/metering_vm_spec.rb new file mode 100644 index 00000000000..74623f81e3a --- /dev/null +++ b/spec/models/metering_vm_spec.rb @@ -0,0 +1,81 @@ +describe MeteringVm do + include Spec::Support::ChargebackHelper + + let(:admin) { FactoryGirl.create(:user_admin) } + let(:base_options) do + {:interval_size => 2, + :end_interval_offset => 0, + :ext_options => {:tz => 'UTC'}, + :userid => admin.userid} + end + + let(:derived_vm_numvcpus) { 1.0 } + let(:derived_memory_available) { 1000.0 } + let(:cpu_usagemhz_rate_average) { 50.0 } + let(:disk_usage_rate_average) { 100.0 } + let(:derived_memory_used) { 100.0 } + let(:net_usage_rate_average) { 25.0 } + let(:derived_vm_used_disk_storage) { 1.0.gigabytes } + let(:derived_vm_allocated_disk_storage) { 4.0.gigabytes } + + let(:starting_date) { Time.parse('2012-09-01 23:59:59Z').utc } + let(:ts) { starting_date.in_time_zone(Metric::Helper.get_time_zone(base_options[:ext_options])) } + let(:report_run_time) { month_end } + let(:month_beginning) { ts.beginning_of_month.utc } + let(:month_end) { ts.end_of_month.utc } + let(:hours_in_month) { Time.days_in_month(month_beginning.month, month_beginning.year) * 24 } + let(:count_of_metric_rollup) { MetricRollup.where(:timestamp => month_beginning...month_end).count } + let(:ems) { FactoryGirl.create(:ems_vmware) } + let(:vm) { FactoryGirl.create(:vm_vmware, :name => "test_vm", :evm_owner => admin, :ems_ref => "ems_ref", :created_on => month_beginning) } + let(:hardware) { FactoryGirl.create(:hardware, :memory_mb => 8124, :cpu_total_cores => 1, :cpu_speed => 9576) } + let(:host) { FactoryGirl.create(:host, :storages => [storage], :hardware => hardware, :vms => [vm]) } + let(:storage) { FactoryGirl.create(:storage_target_vmware) } + let(:ems_cluster) { FactoryGirl.create(:ems_cluster, :ext_management_system => ems, :hosts => [host]) } + + before do + MiqRegion.seed + ChargebackRateDetailMeasure.seed + ChargeableField.seed + MiqEnterprise.seed + EvmSpecHelper.create_guid_miq_server_zone + Timecop.travel(report_run_time) + end + + after do + Timecop.return + end + + let(:metric_rollup_params) do + { + :tag_names => "environment/prod", + :parent_host_id => host.id, + :parent_ems_cluster_id => ems_cluster.id, + :parent_ems_id => ems.id, + :parent_storage_id => storage.id, + } + end + + context 'monthly' do + subject { MeteringVm.build_results_for_report_MeteringVm(options).first.first } + + let(:options) { base_options.merge(:interval => 'monthly', :interval_size => 4, :entity_id => vm.id) } + + before do + add_metric_rollups_for(vm, month_beginning...month_end, 12.hours, metric_rollup_params) + end + + it 'calculates metering values' do + expect(subject.cpu_allocated_metric).to eq(derived_vm_numvcpus) + expect(subject.cpu_used_metric).to eq(cpu_usagemhz_rate_average * count_of_metric_rollup) + expect(subject.disk_io_used_metric).to eq(disk_usage_rate_average * count_of_metric_rollup) + expect(subject.fixed_compute_metric).to eq(count_of_metric_rollup) + expect(subject.memory_allocated_metric).to eq(derived_memory_available) + expect(subject.memory_used_metric).to eq(derived_memory_used * count_of_metric_rollup) + expect(subject.metering_used_metric).to eq(count_of_metric_rollup) + expect(subject.existence_hours_metric).to eq(month_beginning.end_of_month.day * 24) + expect(subject.net_io_used_metric).to eq(net_usage_rate_average * count_of_metric_rollup) + expect(subject.storage_allocated_metric).to eq(derived_vm_allocated_disk_storage) + expect(subject.storage_used_metric).to eq(derived_vm_used_disk_storage * count_of_metric_rollup) + end + end +end From 596ab79ffa4181bb79920a55008b555094607c8f Mon Sep 17 00:00:00 2001 From: lpichler Date: Mon, 30 Oct 2017 12:23:43 +0100 Subject: [PATCH 11/14] specs for MeteringContainerProject --- .../models/metering_container_project_spec.rb | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 spec/models/metering_container_project_spec.rb diff --git a/spec/models/metering_container_project_spec.rb b/spec/models/metering_container_project_spec.rb new file mode 100644 index 00000000000..4574c75ff4f --- /dev/null +++ b/spec/models/metering_container_project_spec.rb @@ -0,0 +1,67 @@ +describe MeteringContainerProject do + include Spec::Support::ChargebackHelper + + let(:admin) { FactoryGirl.create(:user_admin) } + let(:base_options) do + {:interval_size => 2, + :end_interval_offset => 0, + :ext_options => {:tz => 'UTC'}, + :userid => admin.userid} + end + + let(:cpu_usage_rate_average) { 50.0 } + let(:derived_memory_used) { 100.0 } + let(:net_usage_rate_average) { 25.0 } + + let(:starting_date) { Time.parse('2012-09-01 23:59:59Z').utc } + let(:ts) { starting_date.in_time_zone(Metric::Helper.get_time_zone(base_options[:ext_options])) } + let(:report_run_time) { month_end } + let(:month_beginning) { ts.beginning_of_month.utc } + let(:month_end) { ts.end_of_month.utc } + let(:count_of_metric_rollup) { MetricRollup.where(:timestamp => month_beginning...month_end).count } + let(:ems) { FactoryGirl.create(:ems_vmware) } + let(:project) { FactoryGirl.create(:container_project, :name => "my project", :ext_management_system => ems, :created_on => month_beginning) } + let(:hardware) { FactoryGirl.create(:hardware, :memory_mb => 8124, :cpu_total_cores => 1, :cpu_speed => 9576) } + let(:host) { FactoryGirl.create(:host, :storages => [storage], :hardware => hardware, :vms => [vm]) } + let(:storage) { FactoryGirl.create(:storage_target_vmware) } + let(:ems_cluster) { FactoryGirl.create(:ems_cluster, :ext_management_system => ems, :hosts => [host]) } + + before do + MiqRegion.seed + ChargebackRateDetailMeasure.seed + ChargeableField.seed + MiqEnterprise.seed + EvmSpecHelper.create_guid_miq_server_zone + Timecop.travel(report_run_time) + end + + after do + Timecop.return + end + + let(:metric_rollup_params) do + { + :parent_ems_id => ems.id, + :tag_names => "", + } + end + + context 'monthly' do + subject { MeteringContainerProject.build_results_for_report_MeteringContainerProject(options).first.first } + + let(:options) { base_options.merge(:interval => 'monthly', :interval_size => 4, :entity_id => project.id) } + + before do + add_metric_rollups_for(project, month_beginning...month_end, 12.hours, metric_rollup_params) + end + + it 'calculates metering values' do + expect(subject.cpu_cores_used_metric).to eq(cpu_usage_rate_average * count_of_metric_rollup) + expect(subject.fixed_compute_metric).to eq(count_of_metric_rollup) + expect(subject.memory_used_metric).to eq(derived_memory_used * count_of_metric_rollup) + expect(subject.metering_used_metric).to eq(count_of_metric_rollup) + expect(subject.existence_hours_metric).to eq(month_beginning.end_of_month.day * 24) + expect(subject.net_io_used_metric).to eq(net_usage_rate_average * count_of_metric_rollup) + end + end +end From 2dbdaa2bb3ab136b344f59a9ec7bb47b6901642e Mon Sep 17 00:00:00 2001 From: lpichler Date: Mon, 30 Oct 2017 13:28:36 +0100 Subject: [PATCH 12/14] Rubocop fixes --- app/models/metering_container_image.rb | 4 ++-- app/models/metering_container_project.rb | 4 ++-- app/models/metering_vm.rb | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/models/metering_container_image.rb b/app/models/metering_container_image.rb index b46aa140644..04b02e543d4 100644 --- a/app/models/metering_container_image.rb +++ b/app/models/metering_container_image.rb @@ -1,7 +1,7 @@ class MeteringContainerImage < ChargebackContainerImage set_columns_hash( - :metering_used_metric => :integer, - :existence_hours_metric => :interger + :metering_used_metric => :integer, + :existence_hours_metric => :integer ) include Metering diff --git a/app/models/metering_container_project.rb b/app/models/metering_container_project.rb index 4b34c1aa4e4..0bfa3402253 100644 --- a/app/models/metering_container_project.rb +++ b/app/models/metering_container_project.rb @@ -1,7 +1,7 @@ class MeteringContainerProject < ChargebackContainerProject set_columns_hash( - :metering_used_metric => :integer, - :existence_hours_metric => :interger + :metering_used_metric => :integer, + :existence_hours_metric => :integer ) include Metering diff --git a/app/models/metering_vm.rb b/app/models/metering_vm.rb index 1f591e80333..d32b89370eb 100644 --- a/app/models/metering_vm.rb +++ b/app/models/metering_vm.rb @@ -1,6 +1,6 @@ class MeteringVm < ChargebackVm - set_columns_hash( # Fields common to any chargeback type - :metering_used_metric => :integer, + set_columns_hash( + :metering_used_metric => :integer, :existence_hours_metric => :integer ) From b1298f9219dd6c1ea4b0e971a7b227fbc2d66fbd Mon Sep 17 00:00:00 2001 From: lpichler Date: Mon, 30 Oct 2017 18:19:25 +0100 Subject: [PATCH 13/14] Add recently added cpu_cores_allocated_metric and memory_allocated_metric - we are probably allowing both names of metric --- app/models/chargeback/consumption_with_rollups.rb | 2 +- app/models/metering.rb | 5 +++++ app/models/metering_container_image.rb | 12 +++++++----- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/app/models/chargeback/consumption_with_rollups.rb b/app/models/chargeback/consumption_with_rollups.rb index f8c37cedbeb..9d1af4ff864 100644 --- a/app/models/chargeback/consumption_with_rollups.rb +++ b/app/models/chargeback/consumption_with_rollups.rb @@ -47,7 +47,7 @@ def avg(metric, sub_metric = nil) def current_value(metric, _sub_metric) # used for containers allocated metrics case metric - when 'derived_vm_numvcpu_cores' # Allocated CPU count + when 'derived_vm_numvcpu_cores', 'derived_vm_numvcpus_cores' # Allocated CPU count resource.try(:limit_cpu_cores).to_f when 'derived_memory_available' resource.try(:limit_memory_bytes).to_f / 1.megabytes # bytes to megabytes diff --git a/app/models/metering.rb b/app/models/metering.rb index 09032515559..16ebf30a384 100644 --- a/app/models/metering.rb +++ b/app/models/metering.rb @@ -23,6 +23,11 @@ def calculate_costs(consumption, _) source = 'used' end + if field == 'cpu_cores_allocated_metric' + group = 'cpu_cores' + source = 'allocated' + end + chargable_field = ChargeableField.find_by(:group => group, :source => source) next if field == "existence_hours_metric" || field == "fixed_compute_metric" || chargable_field && chargable_field.metering? value = chargable_field.measure_metering(consumption, @options) if chargable_field diff --git a/app/models/metering_container_image.rb b/app/models/metering_container_image.rb index 04b02e543d4..b486630fc01 100644 --- a/app/models/metering_container_image.rb +++ b/app/models/metering_container_image.rb @@ -8,11 +8,13 @@ class MeteringContainerImage < ChargebackContainerImage def self.report_col_options { - "cpu_cores_used_metric" => {:grouping => [:total]}, - "fixed_compute_metric" => {:grouping => [:total]}, - "memory_used_metric" => {:grouping => [:total]}, - "metering_used_metric" => {:grouping => [:total]}, - "net_io_used_metric" => {:grouping => [:total]}, + "cpu_cores_allocated_metric" => {:grouping => [:total]}, + "cpu_cores_used_metric" => {:grouping => [:total]}, + "fixed_compute_metric" => {:grouping => [:total]}, + "memory_allocated_metric" => {:grouping => [:total]}, + "memory_used_metric" => {:grouping => [:total]}, + "metering_used_metric" => {:grouping => [:total]}, + "net_io_used_metric" => {:grouping => [:total]}, } end From 99cebac29196919026694549c06a1c21ae0fa23e Mon Sep 17 00:00:00 2001 From: lpichler Date: Mon, 30 Oct 2017 18:21:11 +0100 Subject: [PATCH 14/14] Add specs for metering container iamge --- spec/models/metering_container_image_spec.rb | 62 ++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 spec/models/metering_container_image_spec.rb diff --git a/spec/models/metering_container_image_spec.rb b/spec/models/metering_container_image_spec.rb new file mode 100644 index 00000000000..35a168f358d --- /dev/null +++ b/spec/models/metering_container_image_spec.rb @@ -0,0 +1,62 @@ +describe MeteringContainerImage do + include Spec::Support::ChargebackHelper + let(:base_options) { {:interval_size => 2, :end_interval_offset => 0, :ext_options => {:tz => 'UTC'} } } + let(:hourly_rate) { 0.01 } + let(:count_hourly_rate) { 1.00 } + let(:starting_date) { Time.parse('2012-09-01 23:59:59Z').utc } + let(:ts) { starting_date.in_time_zone(Metric::Helper.get_time_zone(options[:ext_options])) } + let(:report_run_time) { month_end } + let(:month_beginning) { ts.beginning_of_month.utc } + let(:month_end) { ts.end_of_month.utc } + let(:hours_in_month) { Time.days_in_month(month_beginning.month, month_beginning.year) * 24 } + let(:ems) { FactoryGirl.create(:ems_openshift) } + let(:metric_rollup_params) { {:parent_ems_id => ems.id, :tag_names => ""} } + + before do + # TODO: remove metering columns form specs + described_class.set_columns_hash(:metering_used_metric => :integer, :metering_used_cost => :float) + + MiqRegion.seed + ChargebackRateDetailMeasure.seed + ChargeableField.seed + ChargebackRate.seed + + MiqEnterprise.seed + + EvmSpecHelper.create_guid_miq_server_zone + @node = FactoryGirl.create(:container_node, :name => "node") + @image = FactoryGirl.create(:container_image, :ext_management_system => ems) + @label = FactoryGirl.build(:custom_attribute, :name => "version/1.2/_label-1", :value => "test/1.0.0 rc_2", :section => 'docker_labels') + @project = FactoryGirl.create(:container_project, :name => "my project", :ext_management_system => ems) + @group = FactoryGirl.create(:container_group, :ext_management_system => ems, :container_project => @project, + :container_node => @node) + @container = FactoryGirl.create(:kubernetes_container, :container_group => @group, :container_image => @image, + :limit_memory_bytes => 1.megabytes, :limit_cpu_cores => 1.0) + + Timecop.travel(report_run_time) + end + + after do + Timecop.return + end + + context "Monthly" do + let(:options) { base_options.merge(:interval => 'monthly', :entity_id => @project.id, :tag => nil) } + + before do + add_metric_rollups_for(@container, month_beginning...month_end, 12.hours, metric_rollup_params) + + Range.new(month_beginning, month_end, true).step_value(12.hours).each do |time| + @container.vim_performance_states << FactoryGirl.create(:vim_performance_state, :timestamp => time, :image_tag_names => "environment/prod") + end + end + + subject { MeteringContainerImage.build_results_for_report_MeteringContainerImage(options).first.first } + + it "allocated fields" do + expect(subject.memory_allocated_metric).to eq(@container.limit_memory_bytes / 1.megabytes) + expect(subject.cpu_cores_allocated_metric).to eq(@container.limit_cpu_cores) + expect(subject.cpu_cores_allocated_metric).to eq(@container.limit_memory_bytes / 1.megabytes) + end + end +end