Skip to content

Commit

Permalink
Merge pull request #21059 from lpichler/prefer_rollups_tags_to_groupi…
Browse files Browse the repository at this point in the history
…ng_in_chargeback

Prefer rollup records with tags to grouping in chargeback
  • Loading branch information
gtanzillo authored Feb 23, 2021
2 parents b43ffdb + 8bf9fec commit c43b209
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 9 deletions.
1 change: 1 addition & 0 deletions app/models/chargeback.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
7 changes: 7 additions & 0 deletions app/models/chargeback/consumption.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
55 changes: 46 additions & 9 deletions app/models/chargeback/consumption_with_rollups.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class ConsumptionWithRollups < Consumption

def initialize(metric_rollup_records, start_time, end_time)
super(start_time, end_time)
@rollup_array = metric_rollup_records
@rollup_records = metric_rollup_records
end

def hash_features_affecting_rate
Expand All @@ -21,7 +21,7 @@ def hash_features_affecting_rate
end

def tag_names
@tag_names ||= @rollup_array.inject([]) do |memo, rollup|
@tag_names ||= rollup_records.inject([]) do |memo, rollup|
memo |= all_tag_names(rollup)
memo
end
Expand Down Expand Up @@ -67,7 +67,7 @@ def tag_list_with_prefix_for(rollup)
end

def tag_list_with_prefix
@tag_list_with_prefix ||= @rollup_array.map { |rollup| tag_list_with_prefix_for(rollup) }.flatten.uniq
@tag_list_with_prefix ||= rollup_records.map { |rollup| tag_list_with_prefix_for(rollup) }.flatten.uniq
end

def sum(metric, sub_metric = nil)
Expand All @@ -82,7 +82,7 @@ def max(metric, sub_metric = nil)
def sum_of_maxes_from_grouped_values(metric, sub_metric = nil)
return max(metric, sub_metric) if sub_metric
@grouped_values ||= {}
grouped_rollups = @rollup_array.group_by { |x| x[ChargeableField.col_index(:resource_id)] }
grouped_rollups = rollup_records.group_by { |x| x[ChargeableField.col_index(:resource_id)] }

@grouped_values[metric] ||= grouped_rollups.map do |_, rollups|
rollups.map { |x| rollup_field(x, metric) }.compact.max
Expand All @@ -108,7 +108,7 @@ def none?(metric, sub_metric)
end

def chargeback_fields_present
@chargeback_fields_present ||= @rollup_array.count { |rollup| chargeback_fields_present?(rollup) }
@chargeback_fields_present ||= rollup_records.count { |rollup| chargeback_fields_present?(rollup) }
end

def chargeback_fields_present?(rollup_record)
Expand All @@ -126,12 +126,12 @@ def metering_used_fields_present?(rollup_record)
end

def metering_used_fields_present
@metering_used_fields_present ||= @rollup_array.count { |rollup| metering_used_fields_present?(rollup) }
@metering_used_fields_present ||= rollup_records.count { |rollup| metering_used_fields_present?(rollup) }
end

def metering_allocated_for(metric)
@metering_allocated_metric ||= {}
@metering_allocated_metric[metric] ||= @rollup_array.count do |rollup|
@metering_allocated_metric[metric] ||= rollup_records.count do |rollup|
rollup_record = rollup_field(rollup, metric)
rollup_record.present? && rollup_record.nonzero?
end
Expand All @@ -146,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
Expand All @@ -161,7 +165,7 @@ def sub_metric_rollups(sub_metric)
def values(metric, sub_metric = nil)
@values ||= {}
@values["#{metric}#{sub_metric}"] ||= begin
sub_metric ? sub_metric_rollups(sub_metric) : @rollup_array.collect { |x| rollup_field(x, metric) }.compact
sub_metric ? sub_metric_rollups(sub_metric) : rollup_records.collect { |x| rollup_field(x, metric) }.compact
end
end

Expand All @@ -183,8 +187,41 @@ def v_derived_cpu_total_cores_used_for(rollup)
end

def first_metric_rollup_record
first_rollup_id = @rollup_array.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
27 changes: 27 additions & 0 deletions spec/models/chargeback_vm_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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.select { |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
Expand Down

0 comments on commit c43b209

Please sign in to comment.