From 308f8843e7add5e40e4f9089e35f1de66631baa0 Mon Sep 17 00:00:00 2001 From: Libor Pichler Date: Wed, 17 Feb 2021 11:56:46 +0100 Subject: [PATCH] Use tagged metric rollups in consumption with rollups --- app/models/chargeback.rb | 1 + app/models/chargeback/consumption.rb | 7 +++ .../chargeback/consumption_with_rollups.rb | 43 ++++++++++++++++--- spec/models/chargeback_vm_spec.rb | 27 ++++++++++++ 4 files changed, 73 insertions(+), 5 deletions(-) diff --git a/app/models/chargeback.rb b/app/models/chargeback.rb index 4c9d6a73d2f1..c9d5c9798f28 100644 --- a/app/models/chargeback.rb +++ b/app/models/chargeback.rb @@ -62,6 +62,7 @@ def self.build_results_for_report_chargeback(options) key = result_key[:key] _log.debug("Report row key #{key}") + consumption.tag_filter_for_rollup_records(result_key[:key_object].tag) if result_key[:key_object]&.tag data[key] ||= new(options, consumption, region.region, result_key) chargeback_rates = data[key]["chargeback_rates"].split(', ') + rates_to_apply.collect(&:description) diff --git a/app/models/chargeback/consumption.rb b/app/models/chargeback/consumption.rb index a7eef08419ed..9918d09ace31 100644 --- a/app/models/chargeback/consumption.rb +++ b/app/models/chargeback/consumption.rb @@ -45,6 +45,13 @@ def report_interval_end [Time.current, @end_time].min end + def rollup_records_tag_names + tag_names + end + + def tag_filter_for_rollup_records(_tag) + end + private def hours_in_interval diff --git a/app/models/chargeback/consumption_with_rollups.rb b/app/models/chargeback/consumption_with_rollups.rb index 1ac5eaa40fba..86710e39e708 100644 --- a/app/models/chargeback/consumption_with_rollups.rb +++ b/app/models/chargeback/consumption_with_rollups.rb @@ -11,10 +11,6 @@ def initialize(metric_rollup_records, start_time, end_time) @rollup_records = metric_rollup_records end - def rollup_records - @rollup_records - end - def hash_features_affecting_rate @hash_features_affecting_rate ||= begin tags = tag_names.reject { |n| n.starts_with?('folder_path_') }.sort.join('|') @@ -150,6 +146,10 @@ def all_tag_names(rollup) resource_current_tag_names | resource_tag_names(rollup) end + def tag_filter_for_rollup_records(tag) + @tag_filter_for_rollup_records = tag + end + private def born_at @@ -187,8 +187,41 @@ def v_derived_cpu_total_cores_used_for(rollup) end def first_metric_rollup_record - first_rollup_id = rollup_records.first[ChargeableField.col_index(:id)] + first_rollup_id = @rollup_records.first[ChargeableField.col_index(:id)] @fmrr ||= MetricRollup.find(first_rollup_id) if first_rollup_id end + + def tag_name_filter + return nil unless @tag_filter_for_rollup_records + + @tag_filter_for_rollup_records.name.split("/").last(2).join("/") + end + + def rollup_records_tagged_partially? + tag_name_filter && tag_filtered_for_rollup_records.present? && tag_filtered_for_rollup_records.count != @rollup_records.count + end + + def current_resource_tags_in_tag_filter? + (resource_current_tag_names & [tag_name_filter]).present? + end + + def rollup_records + if rollup_records_tagged_partially? && !current_resource_tags_in_tag_filter? + tag_filtered_for_rollup_records + else + @rollup_records + end + end + + def tag_filtered_for_rollup_records + return @rollup_records unless tag_name_filter + + @tag_filtered_for_rollup_records ||= {} + @tag_filtered_for_rollup_records[tag_name_filter] ||= begin + @rollup_records.select do |rollup| + (resource_tag_names(rollup) & [tag_name_filter]).present? + end + end + end end end diff --git a/spec/models/chargeback_vm_spec.rb b/spec/models/chargeback_vm_spec.rb index 3dbea54b3d2c..8a791ab96283 100644 --- a/spec/models/chargeback_vm_spec.rb +++ b/spec/models/chargeback_vm_spec.rb @@ -1297,6 +1297,33 @@ def result_row_by(chargeback_result, date) expect(production_result_part.cpu_used_metric).to be_within(0.01).of(cpu_used_metric_vm5) expect(production_result_part.cpu_used_cost).to be_within(0.01).of(cpu_used_metric_vm5 * hourly_rate * hours_in_month) end + + context "partial metric rollups in consumption" do + let(:vm_6) { FactoryBot.create(:vm_vmware, :name => "test_vm_6", :evm_owner => admin, :created_on => month_beginning) } + let(:human_resources_tag) { department_tag_category.entries.find_by(:description => "Human Resources").tag } + let(:human_resources_result_part) { subject.detect { |x| x.tag_name == "Human Resources" } } + let(:human_resources_tag_name) { human_resources_tag.name.split("/").last(2).join("/") } + + before do + mid_month = month_beginning + 10.days + + add_metric_rollups_for(vm_6, mid_month...month_end, 12.hours, metric_rollup_params) + + metric_rollup_params[:tag_names] = "#{metric_rollup_params[:tag_names]}|#{human_resources_tag_name}" + add_metric_rollups_for(vm_6, month_beginning...mid_month, 12.hours, metric_rollup_params) + end + + it "calculates consumption based on rollup records with resource's tag_name" do + filtered_rollup_records = vm_6.metric_rollups.filter { |rollup| rollup.tag_names.include?(human_resources_tag_name) } + + cpu_used_metric_vm6 = filtered_rollup_records.sum(&:cpu_usagemhz_rate_average) / hours_in_month + + expect(human_resources_result_part.fixed_compute_metric).to eq(filtered_rollup_records.count) + + expect(human_resources_result_part.cpu_used_cost).to be_within(0.01).of(cpu_used_metric_vm6 * hourly_rate * hours_in_month) + expect(human_resources_result_part.cpu_used_metric).to be_within(0.01).of(cpu_used_metric_vm6) + end + end end context "Group by single tag category" do