forked from ManageIQ/manageiq
-
Notifications
You must be signed in to change notification settings - Fork 1
/
chargeback_rate.rb
195 lines (163 loc) · 7.38 KB
/
chargeback_rate.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
class ChargebackRate < ApplicationRecord
include UuidMixin
ASSIGNMENT_PARENT_ASSOCIATIONS = [:host, :ems_cluster, :storage, :ext_management_system, :my_enterprise]
################################################################################
# NOTE: #
# ensure_unassigned must occur before the taggings relation is destroyed, #
# since it uses the taggings for its calculation. The :dependent => :destroy #
# on taggings is part of the destroy callback chain, so we must define this #
# before_destroy here, before that relation is defined, otherwise the callback #
# chain is out of order. The taggings relation is defined in ar_taggable.rb, #
# and is brought in by the call to acts_as_miq_taggable in the AssignmentMixin #
################################################################################
before_destroy :ensure_unassigned
before_destroy :ensure_nondefault
include AssignmentMixin
has_many :chargeback_rate_details, :dependent => :destroy, :autosave => true
validates :description, :presence => true, :uniqueness_when_changed => {:scope => :rate_type}
delegate :symbol, :to => :currency, :prefix => true, :allow_nil => true
scope :with_rate_type, ->(rate_type) { where(:rate_type => rate_type) }
virtual_column :assigned_to, :type => :string_set
VALID_CB_RATE_TYPES = ["Compute", "Storage"]
DATASTORE_MAPPING = {'CloudVolume' => 'Storage'}.freeze
def self.tag_class(klass)
klass = ChargebackRate::DATASTORE_MAPPING[klass] || klass
super(klass)
end
def rate_details_relevant_to(report_cols, allowed_cols)
# we can memoize, as we get the same report_cols through the life of the object
@relevant ||= chargeback_rate_details.select do |r|
r.affects_report_fields(report_cols) && allowed_cols.include?(r.metric_column_key)
end
end
def self.validate_rate_type(type)
unless VALID_CB_RATE_TYPES.include?(type.to_s.capitalize)
raise "Chargeback rate type '#{type}' is not supported"
end
end
def self.get_assignments(type)
# type = :compute || :storage
# Returns[{:cb_rate=>obj, :tag=>[Classification.entry_object, klass]} || :object=>object},...]
validate_rate_type(type)
result = []
ChargebackRate.where(:rate_type => type.to_s.capitalize).each do |rate|
assigned_tos = rate.get_assigned_tos
assigned_tos[:tags].each { |tag| result << {:cb_rate => rate, :tag => tag} }
assigned_tos[:objects].each { |object| result << {:cb_rate => rate, :object => object} }
assigned_tos[:labels].each { |label| result << {:cb_rate => rate, :label => label} }
end
result
end
def self.unassign_rate_assignments(type, cb_rates)
validate_rate_type(type)
cb_rates.each do |rate|
rate[:cb_rate].unassign_objects(rate[:object]) if rate.key?(:object)
rate[:cb_rate].unassign_tags(*rate[:tag]) if rate.key?(:tag)
rate[:cb_rate].unassign_labels(*rate[:label]) if rate.key?(:label)
end
end
def self.set_assignments(type, cb_rates)
validate_rate_type(type)
ChargebackRate.where(:rate_type => type.to_s.capitalize).each(&:remove_all_assigned_tos)
cb_rates.each do |rate|
rate[:cb_rate].assign_to_objects(rate[:object]) if rate.key?(:object)
rate[:cb_rate].assign_to_tags(*rate[:tag]) if rate.key?(:tag)
rate[:cb_rate].assign_to_labels(*rate[:label]) if rate.key?(:label)
end
end
def self.seed
fixture_file = File.join(FIXTURE_DIR, "chargeback_rates.yml")
if File.exist?(fixture_file)
fixture = YAML.load_file(fixture_file)
fix_mtime = File.mtime(fixture_file).utc
fixture.each do |cbr|
rec = find_by(:guid => cbr[:guid])
rates = cbr.delete(:rates)
rates.each do |rate_detail|
currency = Currency.find_by(:code => rate_detail.delete(:type_currency))
field = ChargeableField.find_by(:metric => rate_detail.delete(:metric))
rate_detail[:chargeable_field_id] = field.id
if currency
rate_detail[:chargeback_rate_detail_currency_id] = currency.id
end
rate_tiers = []
tiers = rate_detail.delete(:tiers)
tiers.each do |tier|
tier_start = ChargebackTier.to_float(tier.delete(:start))
tier_finish = ChargebackTier.to_float(tier.delete(:finish))
fixed_rate = tier.delete(:fixed_rate)
variable_rate = tier.delete(:variable_rate)
cbt = ChargebackTier.create(:start => tier_start, :finish => tier_finish, :fixed_rate => fixed_rate, :variable_rate => variable_rate)
rate_tiers.append(cbt)
end
rate_detail[:chargeback_tiers] = rate_tiers
end
if rec.nil?
_log.info("Creating [#{cbr[:description]}] with guid=[#{cbr[:guid]}]")
rec = create(cbr)
rec.chargeback_rate_details.create(rates)
elsif fix_mtime > rec.created_on
_log.info("Updating [#{cbr[:description]}] with guid=[#{cbr[:guid]}]")
rec.update(cbr)
rec.chargeback_rate_details.clear
rec.chargeback_rate_details.create(rates)
rec.created_on = fix_mtime
rec.save!
end
end
end
end
def assigned?
get_assigned_tos != {:objects => [], :tags => [], :labels => []}
end
def assigned_tags
get_assigned_tos[:tags].map do |x|
classification_entry_object = x.first
classification_entry_object.tag.send(:name_path)
end
end
def assigned_tags?
get_assigned_tos[:tags].present?
end
def default?
super || description == 'Default Container Image Rate'
end
def assigment_type_description(record, type)
assignment_key = if %i[object storage].include?(type)
record.kind_of?(MiqEnterprise) ? "enterprise" : record.class.table_name.singularize
elsif type == :tag
"#{record&.second}-tags"
elsif type == :label
"container_image-labels"
end
rate_type_for_tos = rate_type == "Compute" ? :chargeback_compute : :chargeback_storage
TermOfServiceHelper::ASSIGN_TOS[rate_type_for_tos][assignment_key] || raise("'#{assignment_key}' as chargeback assignment type is not supported for #{rate_type_for_tos} rate.")
end
def assigned_to
result = []
tos = get_assigned_tos
tos[:tags].each { |tag| result << {:tag => tag, :assigment_type_description => assigment_type_description(tag, :tag)} }
tos[:objects].each { |object| result << {:object => object, :assigment_type_description => assigment_type_description(object, :object)} }
tos[:labels].each { |label| result << {:label => label, :assigment_type_description => assigment_type_description(label, :label)} }
result
end
###########################################################
private
def currency
# Note that the currency should be relation to ChargebackRate, not ChargebackRateDetail. We cannot work
# with various currencies within single ChargebackRate. This is to be fixed later in series of db migrations.
chargeback_rate_details.first.try(:detail_currency)
end
def ensure_unassigned
if assigned?
errors.add(:rate, "rate is assigned and cannot be deleted")
throw :abort
end
end
def ensure_nondefault
if default?
errors.add(:rate, "default rate cannot be deleted")
throw :abort
end
end
end