app/models/chargeback/report_options.rb
class Chargeback
# ReportOptions are usualy stored in MiqReport.db_options[:options]
ReportOptions = Struct.new(
:interval, # daily | weekly | monthly
:interval_size, # number of :intervals in the report (i.e. `12` months, `4` weeks)
:end_interval_offset, # report ends :intervals ago (i.e. `3` months ago, or `2` weeks ago)
:owner, # userid
:tenant_id,
:tag, # like /managed/environment/prod (Mutually exclusive with :user)
:report_cols, # cols visible in the final report
:provide_id,
:entity_id, # 1/2/3.../all rails id of entity (ContainerProject or Vm)
:service_id,
:groupby,
:groupby_tag,
:groupby_label,
:userid,
:ext_options,
:include_metrics, # enable charging allocated resources with C & U
:method_for_allocated_metrics,
:cumulative_rate_calculation
) do
def self.new_from_h(hash)
new(*hash.values_at(*members))
end
# skip metric value field because we don't want
# to accumulate metric values(only costs)
def skip_field_accumulation?(field, value)
return false if cumulative_rate_calculation? == false
return false unless field.ends_with?("_metric") && value
true
end
def cumulative_rate_calculation?
!!self[:cumulative_rate_calculation]
end
ALLOCATED_METHODS_WHITELIST = %i[max avg current_value].freeze
def method_for_allocated_metrics
method = (self[:method_for_allocated_metrics] || :max).to_sym
unless ALLOCATED_METHODS_WHITELIST.include?(method)
raise "Invalid method for allocated calculations #{method}"
end
return :sum_of_maxes_from_grouped_values if method == :max && group_by_tenant?
method
end
# include_metrics = nil is default value(true)
def include_metrics?
include_metrics.nil? || include_metrics
end
def initialize(*)
super
self.interval ||= 'daily'
self.end_interval_offset ||= 0
self.ext_options ||= {}
end
def tz
# TODO: Support time profiles via options[:ext_options][:time_profile]
@tz ||= Metric::Helper.get_time_zone(ext_options)
end
def report_time_range
raise _("Option 'interval_size' is required") if interval_size.nil?
start_interval_offset = (end_interval_offset + interval_size - 1)
ts = Time.now.in_time_zone(tz)
case interval
when 'daily'
start_time = (ts - start_interval_offset.days).beginning_of_day
end_time = (ts - end_interval_offset.days).end_of_day
when 'weekly'
start_time = (ts - start_interval_offset.weeks).beginning_of_week
end_time = (ts - end_interval_offset.weeks).end_of_week
when 'monthly'
start_time = (ts - start_interval_offset.months).beginning_of_month
end_time = (ts - end_interval_offset.months).end_of_month
else
raise _("interval '%{interval}' is not supported") % {:interval => interval}
end
start_time..end_time
end
def start_of_report_step(timestamp)
ts = timestamp.in_time_zone(tz)
case interval
when 'daily'
ts.beginning_of_day
when 'weekly'
ts.beginning_of_week
when 'monthly'
ts.beginning_of_month
else
raise _("interval '%{interval}' is not supported") % {:interval => interval}
end
end
def report_step_range(timestamp)
ts = timestamp.in_time_zone(tz)
case interval
when 'daily'
[ts.beginning_of_day, ts.end_of_day, ts.strftime('%m/%d/%Y')]
when 'weekly'
s_ts = ts.beginning_of_week
e_ts = ts.end_of_week
[s_ts, e_ts, "Week of #{s_ts.strftime('%m/%d/%Y')}"]
when 'monthly'
s_ts = ts.beginning_of_month
e_ts = ts.end_of_month
[s_ts, e_ts, s_ts.strftime('%b %Y')]
else
raise _("interval '%{interval}' is not supported") % {:interval => interval}
end
end
def duration_of_report_step
case interval
when 'daily' then 1.day
when 'weekly' then 1.week
when 'monthly' then 1.month
end
end
def tenant_for(consumption)
consumption.resource.tenant
end
def classification_for(consumption)
tags = consumption.tag_names.select do |x|
Array(groupby_tag).detect { |group_by_tag| x.starts_with?(group_by_tag) }
end.compact
tags.map { |x| tag_hash[x.split("/").second] } if tags.present?
end
def group_by_tenant?
self[:groupby] == 'tenant'
end
def group_by_date_first?
self[:groupby] == 'date-first'
end
def group_by_date_only?
self[:groupby] == 'date-only'
end
private
def tag_hash
categories = Array(groupby_tag)
if categories
@tag_hash ||= categories.each_with_object({}) do |category, return_value|
tags = Classification.hash_all_by_type_and_name[category][:entry]
tags.each do |key, value|
return_value[key] = value
end
end
end
end
end
end