From ff2e8518b072df3de0a6834f20bace236c7fb930 Mon Sep 17 00:00:00 2001 From: lpichler Date: Tue, 3 Oct 2017 11:08:00 +0200 Subject: [PATCH 1/6] Add new metering used hours to yaml files to specify rates --- db/fixtures/chargeable_fields.yml | 5 +++++ db/fixtures/chargeback_rates.yml | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/db/fixtures/chargeable_fields.yml b/db/fixtures/chargeable_fields.yml index c181964473c..150bf24f82f 100644 --- a/db/fixtures/chargeable_fields.yml +++ b/db/fixtures/chargeable_fields.yml @@ -58,3 +58,8 @@ :group: fixed :source: storage_2 :description: Fixed Storage Cost 2 +- :metric: user_metering_hours + :group: metering + :source: used + :description: Metering - Hours Used + diff --git a/db/fixtures/chargeback_rates.yml b/db/fixtures/chargeback_rates.yml index 24d07f315f1..de9c7170e29 100644 --- a/db/fixtures/chargeback_rates.yml +++ b/db/fixtures/chargeback_rates.yml @@ -96,6 +96,16 @@ :finish: Infinity :fixed_rate: 0.0 :variable_rate: 0.0 + - :description: Metering - Hours Used + :metric: user_metering_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 From 4fe3f0aaa752b1d2575820c01cd61ca011edd1b3 Mon Sep 17 00:00:00 2001 From: lpichler Date: Tue, 3 Oct 2017 11:11:49 +0200 Subject: [PATCH 2/6] Add new columns for metric and cost to chargeback reports - for available fields in report definition - adding as keys to hash with results (this hash is passed to report engine) --- app/models/chargeback.rb | 2 ++ app/models/chargeback_container_image.rb | 2 ++ app/models/chargeback_container_project.rb | 2 ++ app/models/chargeback_vm.rb | 2 ++ 4 files changed, 8 insertions(+) diff --git a/app/models/chargeback.rb b/app/models/chargeback.rb index 7a4b449e9ba..8014289ab58 100644 --- a/app/models/chargeback.rb +++ b/app/models/chargeback.rb @@ -8,6 +8,8 @@ class Chargeback < ActsAsArModel :entity => :binary, :tag_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/chargeback_container_image.rb b/app/models/chargeback_container_image.rb index ea8a7e50402..9555cf2d3f0 100644 --- a/app/models/chargeback_container_image.rb +++ b/app/models/chargeback_container_image.rb @@ -83,6 +83,8 @@ def self.report_col_options "fixed_cost" => {:grouping => [:total]}, "memory_used_cost" => {:grouping => [:total]}, "memory_used_metric" => {:grouping => [:total]}, + "metering_used_metric" => {:grouping => [:total]}, + "metering_used_cost" => {:grouping => [:total]}, "net_io_used_cost" => {:grouping => [:total]}, "net_io_used_metric" => {:grouping => [:total]}, "total_cost" => {:grouping => [:total]} diff --git a/app/models/chargeback_container_project.rb b/app/models/chargeback_container_project.rb index 998343cfbf7..67e00ed0bb5 100644 --- a/app/models/chargeback_container_project.rb +++ b/app/models/chargeback_container_project.rb @@ -64,6 +64,8 @@ def self.report_col_options "fixed_cost" => {:grouping => [:total]}, "memory_used_cost" => {:grouping => [:total]}, "memory_used_metric" => {:grouping => [:total]}, + "metering_used_metric" => {:grouping => [:total]}, + "metering_used_cost" => {:grouping => [:total]}, "net_io_used_cost" => {:grouping => [:total]}, "net_io_used_metric" => {:grouping => [:total]}, "total_cost" => {:grouping => [:total]} diff --git a/app/models/chargeback_vm.rb b/app/models/chargeback_vm.rb index 755d2b6360a..c61078f16bb 100644 --- a/app/models/chargeback_vm.rb +++ b/app/models/chargeback_vm.rb @@ -88,6 +88,8 @@ def self.report_col_options "memory_cost" => {:grouping => [:total]}, "memory_used_cost" => {:grouping => [:total]}, "memory_used_metric" => {:grouping => [:total]}, + "metering_used_cost" => {:grouping => [:total]}, + "metering_used_metric" => {:grouping => [:total]}, "net_io_used_cost" => {:grouping => [:total]}, "net_io_used_metric" => {:grouping => [:total]}, "storage_allocated_cost" => {:grouping => [:total]}, From 6f2a7fe1ea225eabc1253ea87501ad3a9146264f Mon Sep 17 00:00:00 2001 From: lpichler Date: Tue, 3 Oct 2017 11:13:26 +0200 Subject: [PATCH 3/6] Add cost calculations for metering used hours metering used hours * hourly rate --- app/models/chargeable_field.rb | 5 +++++ app/models/chargeback_rate_detail.rb | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/app/models/chargeable_field.rb b/app/models/chargeable_field.rb index 2a1e2e6efa3..e5f628ab6bd 100644 --- a/app/models/chargeable_field.rb +++ b/app/models/chargeable_field.rb @@ -20,6 +20,7 @@ class ChargeableField < ApplicationRecord validates :group, :source, :presence => true def measure(consumption, options) + return consumption.consumed_hours_in_interval if metering? return 1.0 if fixed? return 0 if consumption.none?(metric) return consumption.send(options.method_for_allocated_metrics, metric) if allocated? @@ -45,6 +46,10 @@ def cost_keys 'total_cost'] end + def metering? + group == 'metering' && source == 'used' + end + private def rate_name diff --git a/app/models/chargeback_rate_detail.rb b/app/models/chargeback_rate_detail.rb index a52895462f4..1e31c13eee6 100644 --- a/app/models/chargeback_rate_detail.rb +++ b/app/models/chargeback_rate_detail.rb @@ -164,7 +164,9 @@ def gratis? def metric_and_cost_by(consumption, options) metric_value = chargeable_field.measure(consumption, options) - [metric_value, hourly_cost(metric_value, consumption) * consumption.consumed_hours_in_interval] + hourly_cost = hourly_cost(metric_value, consumption) + cost = chargeable_field.metering? ? hourly_cost : hourly_cost * consumption.consumed_hours_in_interval + [metric_value, cost] end def first_tier?(tier,tiers) From 2a3fb1e7d2af4ae83ba89bcf4758a43a283b0b15 Mon Sep 17 00:00:00 2001 From: lpichler Date: Tue, 3 Oct 2017 11:14:24 +0200 Subject: [PATCH 4/6] Add format 'Hours' for reporting the new metric --- db/fixtures/miq_report_formats.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/db/fixtures/miq_report_formats.yml b/db/fixtures/miq_report_formats.yml index 5666f3535c7..ad1c08c179c 100644 --- a/db/fixtures/miq_report_formats.yml +++ b/db/fixtures/miq_report_formats.yml @@ -48,6 +48,7 @@ :memory_used_cost: :currency_precision_2 :memory_allocated_cost: :currency_precision_2 :memory_cost: :currency_precision_2 + :metering_used_cost: :currency_precision_2 :storage_used_cost: :currency_precision_2 :storage_allocated_cost: :currency_precision_2 :storage_cost: :currency_precision_2 @@ -191,6 +192,7 @@ :memory_used_metric: :megabytes_precision_2 :memory_mb: :megabytes :mem_cpu: :megabytes + :metering_used_metric: :hours :min_derived_memory_used: :megabytes :ram_size: :megabytes :trend_derived_memory_used: :megabytes @@ -474,6 +476,17 @@ :delimiter: "," :precision: 1 + :hours: + :description: Hours + :columns: + :sub_types: + - :hours + :function: + :function: + :name: number_with_delimiter + :delimiter: "," + :suffix: ! ' Hours' + :mhz_precision_2: :description: Megahertz Avg (12.11 Mhz) :columns: From decd671fbc12c745e5bd3fcfb6ac28dc314596d7 Mon Sep 17 00:00:00 2001 From: lpichler Date: Tue, 3 Oct 2017 11:13:59 +0200 Subject: [PATCH 5/6] Add factories for metering used hours --- spec/factories/chargeable_field.rb | 7 +++++++ spec/factories/chargeback_rate.rb | 1 + spec/factories/chargeback_rate_detail.rb | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/spec/factories/chargeable_field.rb b/spec/factories/chargeable_field.rb index 4c3fea9fffe..ea7a7135c6c 100644 --- a/spec/factories/chargeable_field.rb +++ b/spec/factories/chargeable_field.rb @@ -82,4 +82,11 @@ source 'used' detail_measure { FactoryGirl.build(:chargeback_measure_bytes) } end + + factory :chargeable_field_metering_used, :parent => :chargeable_field do + description 'Metering Used Hours' + metric 'metering_used_hours' + group 'metering' + source 'used' + end end diff --git a/spec/factories/chargeback_rate.rb b/spec/factories/chargeback_rate.rb index 32808b4b296..8ba029cf279 100644 --- a/spec/factories/chargeback_rate.rb +++ b/spec/factories/chargeback_rate.rb @@ -42,6 +42,7 @@ chargeback_rate_detail_memory_allocated chargeback_rate_detail_memory_used chargeback_rate_detail_net_io_used + chargeback_rate_detail_metering_used ).each do |factory_name| chargeback_rate.chargeback_rate_details << FactoryGirl.create(factory_name, :tiers_with_three_intervals, diff --git a/spec/factories/chargeback_rate_detail.rb b/spec/factories/chargeback_rate_detail.rb index 085ede07b5d..3c8566c3408 100644 --- a/spec/factories/chargeback_rate_detail.rb +++ b/spec/factories/chargeback_rate_detail.rb @@ -97,4 +97,8 @@ factory :chargeback_rate_detail_fixed_compute_cost, :traits => [:daily], :parent => :chargeback_rate_detail do chargeable_field { FactoryGirl.build(:chargeable_field_fixed_compute_1) } end + + factory :chargeback_rate_detail_metering_used, :traits => [:daily], :parent => :chargeback_rate_detail do + chargeable_field { FactoryGirl.build(:chargeable_field_metering_used) } + end end From ed7b1ef51bfd617fa0ad7cc844e674b5e65be1d5 Mon Sep 17 00:00:00 2001 From: lpichler Date: Mon, 4 Sep 2017 16:20:45 +0200 Subject: [PATCH 6/6] Add spec for metering used hours metric and cost --- .../models/chargeback_container_image_spec.rb | 17 ++++++- .../chargeback_container_project_spec.rb | 13 ++++- spec/models/chargeback_vm_spec.rb | 50 +++++++++++++------ 3 files changed, 62 insertions(+), 18 deletions(-) diff --git a/spec/models/chargeback_container_image_spec.rb b/spec/models/chargeback_container_image_spec.rb index 5b663db7596..b06014c4095 100644 --- a/spec/models/chargeback_container_image_spec.rb +++ b/spec/models/chargeback_container_image_spec.rb @@ -13,7 +13,12 @@ let(:hourly_variable_tier_rate) { {:variable_rate => hourly_rate.to_s} } - let(:detail_params) { {:chargeback_rate_detail_fixed_compute_cost => { :tiers => [hourly_variable_tier_rate] } } } + let(:detail_params) do + { + :chargeback_rate_detail_fixed_compute_cost => {:tiers => [hourly_variable_tier_rate]}, + :chargeback_rate_detail_metering_used => {:tiers => [hourly_variable_tier_rate]} + } + end let!(:chargeback_rate) do FactoryGirl.create(:chargeback_rate, :detail_params => detail_params) @@ -80,6 +85,11 @@ it "fixed_compute" do expect(subject.fixed_compute_1_cost).to eq(hourly_rate * hours_in_day) end + + it 'calculates metering used hours and cost' do + expect(subject.metering_used_metric).to eq(hours_in_day) + expect(subject.metering_used_cost).to eq(hours_in_day * hourly_rate) + end end context "Monthly" do @@ -100,6 +110,11 @@ # .to be_within(0.01) is used since theres a float error here expect(subject.fixed_compute_1_cost).to be_within(0.01).of(hourly_rate * hours_in_month) end + + it 'calculates metering used hours and cost' do + expect(subject.metering_used_metric).to eq(hours_in_month) + expect(subject.metering_used_cost).to eq(hours_in_month * hourly_rate) + end end context "Label" do diff --git a/spec/models/chargeback_container_project_spec.rb b/spec/models/chargeback_container_project_spec.rb index 55ab2ebeab7..cdf67567606 100644 --- a/spec/models/chargeback_container_project_spec.rb +++ b/spec/models/chargeback_container_project_spec.rb @@ -18,7 +18,8 @@ :chargeback_rate_detail_fixed_compute_cost => {:tiers => [hourly_variable_tier_rate]}, :chargeback_rate_detail_cpu_cores_used => {:tiers => [hourly_variable_tier_rate]}, :chargeback_rate_detail_net_io_used => {:tiers => [hourly_variable_tier_rate]}, - :chargeback_rate_detail_memory_used => {:tiers => [hourly_variable_tier_rate]} + :chargeback_rate_detail_memory_used => {:tiers => [hourly_variable_tier_rate]}, + :chargeback_rate_detail_metering_used => {:tiers => [hourly_variable_tier_rate]} } end @@ -99,6 +100,11 @@ expect(subject.fixed_compute_1_cost).to eq(hourly_rate * hours_in_day) expect(subject.fixed_compute_metric).to eq(@metric_size) end + + it 'calculates metering used hours and cost' do + expect(subject.metering_used_metric).to eq(hours_in_day) + expect(subject.metering_used_cost).to eq(hours_in_day * hourly_rate) + end end context "Monthly" do @@ -133,6 +139,11 @@ expect(subject.fixed_compute_1_cost).to be_within(0.01).of(hourly_rate * hours_in_month) expect(subject.fixed_compute_metric).to eq(@metric_size) end + + it 'calculates metering used hours and cost' do + expect(subject.metering_used_metric).to eq(hours_in_month) + expect(subject.metering_used_cost).to eq(hours_in_month * hourly_rate) + end end context "tagged project" do diff --git a/spec/models/chargeback_vm_spec.rb b/spec/models/chargeback_vm_spec.rb index f175bac7a89..116a21a4110 100644 --- a/spec/models/chargeback_vm_spec.rb +++ b/spec/models/chargeback_vm_spec.rb @@ -27,15 +27,16 @@ let(:detail_params) do { - :chargeback_rate_detail_cpu_used => {:tiers => [hourly_variable_tier_rate]}, - :chargeback_rate_detail_cpu_allocated => {:tiers => [count_hourly_variable_tier_rate]}, - :chargeback_rate_detail_memory_allocated => {:tiers => [hourly_variable_tier_rate]}, - :chargeback_rate_detail_memory_used => {:tiers => [hourly_variable_tier_rate]}, - :chargeback_rate_detail_disk_io_used => {:tiers => [hourly_variable_tier_rate]}, - :chargeback_rate_detail_net_io_used => {:tiers => [hourly_variable_tier_rate]}, - :chargeback_rate_detail_storage_used => {:tiers => [count_hourly_variable_tier_rate]}, - :chargeback_rate_detail_storage_allocated => {:tiers => [count_hourly_variable_tier_rate]}, - :chargeback_rate_detail_fixed_compute_cost => {:tiers => [hourly_variable_tier_rate]} + :chargeback_rate_detail_cpu_used => {:tiers => [hourly_variable_tier_rate]}, + :chargeback_rate_detail_cpu_allocated => {:tiers => [count_hourly_variable_tier_rate]}, + :chargeback_rate_detail_memory_allocated => {:tiers => [hourly_variable_tier_rate]}, + :chargeback_rate_detail_memory_used => {:tiers => [hourly_variable_tier_rate]}, + :chargeback_rate_detail_disk_io_used => {:tiers => [hourly_variable_tier_rate]}, + :chargeback_rate_detail_net_io_used => {:tiers => [hourly_variable_tier_rate]}, + :chargeback_rate_detail_storage_used => {:tiers => [count_hourly_variable_tier_rate]}, + :chargeback_rate_detail_storage_allocated => {:tiers => [count_hourly_variable_tier_rate]}, + :chargeback_rate_detail_fixed_compute_cost => {:tiers => [hourly_variable_tier_rate]}, + :chargeback_rate_detail_metering_used => {:tiers => [count_hourly_variable_tier_rate]} } end @@ -206,6 +207,11 @@ expect(subject.storage_cost).to eq(subject.storage_allocated_cost + subject.storage_used_cost) end + it 'calculates metering used hours and cost' do + expect(subject.metering_used_metric).to eq(hours_in_day) + expect(subject.metering_used_cost).to eq(hours_in_day * count_hourly_rate) + end + context "fixed rates" do let(:hourly_fixed_rate) { 10.0 } @@ -335,6 +341,11 @@ expect(subject.net_io_used_cost).to be_within(0.01).of(used_metric * hourly_rate * hours_in_month) end + it 'calculates metering used hours and cost' do + expect(subject.metering_used_metric).to eq(hours_in_month) + expect(subject.metering_used_cost).to eq(count_hourly_rate * hours_in_month) + end + context "fixed rates" do let(:hourly_fixed_rate) { 10.0 } @@ -524,10 +535,11 @@ end context 'without metric rollups' do - let(:cores) { 7 } - let(:mem_mb) { 1777 } - let(:disk_gb) { 7 } - let(:disk_b) { disk_gb * 1024**3 } + let(:cores) { 7 } + let(:mem_mb) { 1777 } + let(:disk_gb) { 7 } + let(:disk_b) { disk_gb * 1024**3 } + let(:metering_used_hours) { 24 } let(:hardware) do FactoryGirl.build(:hardware, @@ -540,6 +552,7 @@ let(:mem_cost) { mem_mb * hourly_rate * 24 } let(:cpu_cost) { cores * count_hourly_rate * 24 } let(:disk_cost) { disk_gb * count_hourly_rate * 24 } + let(:metering_used_cost) { metering_used_hours * count_hourly_rate } context 'for SCVMM (hyper-v)' do let!(:vm1) do @@ -561,11 +574,13 @@ it 'allocated metrics are calculated properly' do expect(subject.memory_allocated_metric).to eq(mem_mb) expect(subject.memory_allocated_cost).to eq(mem_cost) + expect(subject.metering_used_metric).to eq(metering_used_hours) + expect(subject.metering_used_cost).to eq(metering_used_cost) expect(subject.cpu_allocated_metric).to eq(cores) expect(subject.cpu_allocated_cost).to eq(cpu_cost) expect(subject.storage_allocated_metric).to eq(disk_b) expect(subject.storage_allocated_cost).to eq(disk_cost) - expect(subject.total_cost).to eq(fixed_cost + cpu_cost + mem_cost + disk_cost) + expect(subject.total_cost).to eq(fixed_cost + cpu_cost + mem_cost + disk_cost + metering_used_cost) end end @@ -586,14 +601,17 @@ expect(subject.fixed_compute_1_cost).to eq(fixed_cost) end - it 'allocated metrics are calculated properly' do + it 'metrics are calculated properly' do expect(subject.memory_allocated_metric).to eq(mem_mb) expect(subject.memory_allocated_cost).to eq(mem_cost) + expect(subject.metering_used_metric).to eq(metering_used_hours) + expect(subject.metering_used_cost).to eq(metering_used_cost) expect(subject.cpu_allocated_metric).to eq(cores) expect(subject.cpu_allocated_cost).to eq(cpu_cost) expect(subject.storage_allocated_metric).to eq(disk_b) expect(subject.storage_allocated_cost).to eq(disk_cost) - expect(subject.total_cost).to eq(fixed_cost + cpu_cost + mem_cost + disk_cost) + + expect(subject.total_cost).to eq(fixed_cost + cpu_cost + mem_cost + disk_cost + metering_used_cost) end context 'metrics are included (but dont have any)' do