forked from ManageIQ/manageiq
-
Notifications
You must be signed in to change notification settings - Fork 1
/
consumption_with_rollups.rb
235 lines (186 loc) · 7.73 KB
/
consumption_with_rollups.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
class Chargeback
class ConsumptionWithRollups < Consumption
delegate :timestamp, :resource, :resource_id, :resource_name, :resource_type, :parent_ems,
:parents_determining_rate, :resource_current_tag_names,
:to => :first_metric_rollup_record
attr_accessor :start_time, :end_time
def initialize(metric_rollup_records, start_time, end_time)
super(start_time, end_time)
@rollup_records = metric_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('|')
keys = [tags] + first_metric_rollup_record.resource_parents.map(&:id)
keys += [first_metric_rollup_record.resource.container_image, timestamp] if resource_type == Container.name
keys.join('_')
end
end
def tag_names
@tag_names ||= rollup_records.inject([]) do |memo, rollup|
memo |= all_tag_names(rollup)
memo
end
end
TAG_MANAGED_PREFIX = "/tag/managed/".freeze
def tag_prefix
klass_prefix = case resource_type
when Container.name then 'container_image'
when ContainerImage.name then 'container_image'
when VmOrTemplate.name then 'vm'
when ContainerProject.name then 'container_project'
end
klass_prefix + TAG_MANAGED_PREFIX
end
def chargeback_container_labels
docker_labels.try(:collect_concat) do |l|
escaped_name = AssignmentMixin.escape(l.name)
escaped_value = AssignmentMixin.escape(l.value)
[
# The assignments in tags can appear the old way as they are, or escaped
"container_image/label/managed/#{l.name}/#{l.value}",
"container_image/label/managed/#{escaped_name}/#{escaped_value}"
]
end || []
end
def container_tag_list_with_prefix
if resource.kind_of?(ContainerImage)
state = resource.vim_performance_state_for_ts(timestamp)
image_tag_name = "#{state.image_tag_names}|" if state
image_tag_name.split("|")
else
[]
end
end
def tag_list_with_prefix_for(rollup)
(all_tag_names(rollup) + container_tag_list_with_prefix).uniq.reject(&:empty?).map { |x| "#{tag_prefix}#{x}" } + chargeback_container_labels
end
def tag_list_with_prefix
@tag_list_with_prefix ||= rollup_records.map { |rollup| tag_list_with_prefix_for(rollup) }.flatten.uniq
end
def sum(metric, sub_metric = nil)
values(metric, sub_metric).sum
end
def max(metric, sub_metric = nil)
values = values(metric, sub_metric)
values.present? ? values.max : 0
end
def sum_of_maxes_from_grouped_values(metric, sub_metric = nil)
return max(metric, sub_metric) if sub_metric
@grouped_values ||= {}
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
end.compact.sum
end
def avg(metric, sub_metric = nil)
metric_sum = values(metric, sub_metric).sum
metric_sum / consumed_hours_in_interval
end
def current_value(metric, _sub_metric) # used for containers allocated metrics
case metric
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
end
end
def none?(metric, sub_metric)
values(metric, sub_metric).empty?
end
def chargeback_fields_present
@chargeback_fields_present ||= rollup_records.count { |rollup| chargeback_fields_present?(rollup) }
end
def chargeback_fields_present?(rollup_record)
MetricRollup::CHARGEBACK_METRIC_FIELDS.any? do |field|
rollup = rollup_field(rollup_record, field)
rollup.present? && rollup.nonzero?
end
end
def metering_used_fields_present?(rollup_record)
MetricRollup::METERING_USED_METRIC_FIELDS.any? do |field|
rollup = rollup_field(rollup_record, field)
rollup.present? && rollup.nonzero?
end
end
def metering_used_fields_present
@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_records.count do |rollup|
rollup_record = rollup_field(rollup, metric)
rollup_record.present? && rollup_record.nonzero?
end
end
def resource_tag_names(rollup)
tags_names = rollup[ChargeableField.col_index(:tag_names)]
tags_names ? tags_names.split('|') : []
end
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 docker_labels
resource.try(:docker_labels) || resource.try(:container_image).try(:docker_labels)
end
def born_at
# metrics can be older than resource (first capture may go few days back)
[super, first_metric_rollup_record.timestamp].compact.min
end
def sub_metric_rollups(sub_metric)
q = VimPerformanceState.where(:timestamp => start_time...end_time, :resource => resource, :capture_interval => 3_600)
q.map { |x| x.state_data.try(:[], :allocated_disk_types).try(:[], sub_metric) || 0 }
end
def values(metric, sub_metric = nil)
@values ||= {}
@values["#{metric}#{sub_metric}"] ||= sub_metric ? sub_metric_rollups(sub_metric) : rollup_records.collect { |x| rollup_field(x, metric) }.compact
end
def rollup_field(rollup, metric)
if metric == "v_derived_cpu_total_cores_used"
return v_derived_cpu_total_cores_used_for(rollup)
end
if metric == "derived_vm_numvcpu_cores"
return rollup[ChargeableField.col_index('derived_vm_numvcpus')]
end
rollup[ChargeableField.col_index(metric)]
end
def v_derived_cpu_total_cores_used_for(rollup)
cpu_usage_rate_average = rollup[ChargeableField.col_index("cpu_usage_rate_average")]
derived_vm_numvcpus = rollup[ChargeableField.col_index("derived_vm_numvcpus")]
return nil if cpu_usage_rate_average.nil? || derived_vm_numvcpus.nil? || derived_vm_numvcpus == 0
(cpu_usage_rate_average * derived_vm_numvcpus) / 100.0
end
def first_metric_rollup_record
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] ||= @rollup_records.select do |rollup|
(resource_tag_names(rollup) & [tag_name_filter]).present?
end
end
end
end