diff --git a/app/models/chargeable_field.rb b/app/models/chargeable_field.rb index c9ad44fb774..2c702faf8ad 100644 --- a/app/models/chargeable_field.rb +++ b/app/models/chargeable_field.rb @@ -44,7 +44,7 @@ def showback_dimension def measure(consumption, options, sub_metric = nil) return consumption.consumed_hours_in_interval if metering? return 1.0 if fixed? - return 0 if consumption.none?(metric) + return 0 if options.method_for_allocated_metrics != :current_value && consumption.none?(metric) return consumption.send(options.method_for_allocated_metrics, metric, sub_metric) if allocated? return consumption.avg(metric) if used? end diff --git a/app/models/chargeback/consumption_with_rollups.rb b/app/models/chargeback/consumption_with_rollups.rb index e6ca3f7d4e6..1762ddb9a08 100644 --- a/app/models/chargeback/consumption_with_rollups.rb +++ b/app/models/chargeback/consumption_with_rollups.rb @@ -40,6 +40,15 @@ def avg(metric, sub_metric = nil) 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' # 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) values(metric).empty? end diff --git a/app/models/chargeback/rates_cache.rb b/app/models/chargeback/rates_cache.rb index b66f0484bc7..41755ab6396 100644 --- a/app/models/chargeback/rates_cache.rb +++ b/app/models/chargeback/rates_cache.rb @@ -24,7 +24,7 @@ def rates(consumption) :tag_list => consumption.tag_list_with_prefix, :parents => consumption.parents_determining_rate) - if consumption.resource_type == Container.name && rates.empty? + if consumption.resource.kind_of?(Container) && rates.empty? rates = [ChargebackRate.find_by(:description => "Default Container Image Rate", :rate_type => "Compute")] end diff --git a/app/models/chargeback/report_options.rb b/app/models/chargeback/report_options.rb index fc916b7f802..f1964b7d520 100644 --- a/app/models/chargeback/report_options.rb +++ b/app/models/chargeback/report_options.rb @@ -23,7 +23,7 @@ def self.new_from_h(hash) new(*hash.values_at(*members)) end - ALLOCATED_METHODS_WHITELIST = %i(max avg).freeze + ALLOCATED_METHODS_WHITELIST = %i(max avg current_value).freeze def method_for_allocated_metrics method = self[:method_for_allocated_metrics] || :max diff --git a/app/models/chargeback_container_image.rb b/app/models/chargeback_container_image.rb index 2b8be86e7a4..da760f7570b 100644 --- a/app/models/chargeback_container_image.rb +++ b/app/models/chargeback_container_image.rb @@ -1,22 +1,25 @@ class ChargebackContainerImage < Chargeback set_columns_hash( - :project_name => :string, - :image_name => :string, - :project_uid => :string, - :provider_name => :string, - :provider_uid => :string, - :archived => :string, - :cpu_cores_used_cost => :float, - :cpu_cores_used_metric => :float, - :fixed_compute_1_cost => :float, - :fixed_compute_2_cost => :float, - :fixed_2_cost => :float, - :fixed_cost => :float, - :memory_used_cost => :float, - :memory_used_metric => :float, - :net_io_used_cost => :float, - :net_io_used_metric => :float, - :total_cost => :float, + :project_name => :string, + :image_name => :string, + :project_uid => :string, + :provider_name => :string, + :provider_uid => :string, + :archived => :string, + :cpu_cores_used_cost => :float, + :cpu_cores_used_metric => :float, + :cpu_cores_allocated_metric => :float, + :cpu_cores_allocated_cost => :float, + :fixed_compute_1_cost => :float, + :fixed_compute_2_cost => :float, + :fixed_cost => :float, + :memory_used_cost => :float, + :memory_used_metric => :float, + :memory_allocated_cost => :float, + :memory_allocated_metric => :float, + :net_io_used_cost => :float, + :net_io_used_metric => :float, + :total_cost => :float, ) def self.build_results_for_report_ChargebackContainerImage(options) @@ -48,6 +51,7 @@ def self.build_results_for_report_ChargebackContainerImage(options) @unknown_image ||= OpenStruct.new(:id => 0, :full_name => _('Unknown Image')) load_custom_attribute_groupby(options[:groupby_label]) if options[:groupby_label].present? + options[:method_for_allocated_metrics] = :current_value build_results_for_report_chargeback(options) ensure @data_index = @containers = nil @@ -89,19 +93,23 @@ def self.report_static_cols def self.report_col_options { - "cpu_cores_used_cost" => {:grouping => [:total]}, - "cpu_cores_used_metric" => {:grouping => [:total]}, - "fixed_compute_metric" => {:grouping => [:total]}, - "fixed_compute_1_cost" => {:grouping => [:total]}, - "fixed_compute_2_cost" => {:grouping => [:total]}, - "fixed_cost" => {:grouping => [:total]}, - "memory_used_cost" => {:grouping => [:total]}, - "memory_used_metric" => {:grouping => [:total]}, - "metering_used_metric" => {:grouping => [:total]}, - "metering_used_cost" => {:grouping => [:total]}, - "net_io_used_cost" => {:grouping => [:total]}, - "net_io_used_metric" => {:grouping => [:total]}, - "total_cost" => {:grouping => [:total]} + "cpu_cores_used_cost" => {:grouping => [:total]}, + "cpu_cores_used_metric" => {:grouping => [:total]}, + "cpu_cores_allocated_metric" => {:grouping => [:total]}, + "cpu_cores_allocated_cost" => {:grouping => [:total]}, + "fixed_compute_metric" => {:grouping => [:total]}, + "fixed_compute_1_cost" => {:grouping => [:total]}, + "fixed_compute_2_cost" => {:grouping => [:total]}, + "fixed_cost" => {:grouping => [:total]}, + "memory_used_cost" => {:grouping => [:total]}, + "memory_used_metric" => {:grouping => [:total]}, + "metering_used_metric" => {:grouping => [:total]}, + "metering_used_cost" => {:grouping => [:total]}, + "memory_allocated_cost" => {:grouping => [:total]}, + "memory_allocated_metric" => {:grouping => [:total]}, + "net_io_used_cost" => {:grouping => [:total]}, + "net_io_used_metric" => {:grouping => [:total]}, + "total_cost" => {:grouping => [:total]} } end diff --git a/db/fixtures/chargeable_fields.yml b/db/fixtures/chargeable_fields.yml index e9b93ba687c..7118707e8b5 100644 --- a/db/fixtures/chargeable_fields.yml +++ b/db/fixtures/chargeable_fields.yml @@ -12,6 +12,10 @@ :description: Allocated CPU Count :group: cpu :source: allocated +- :metric: derived_vm_numvcpu_cores + :description: Allocated CPU Cores + :group: cpu_cores + :source: allocated - :metric: derived_memory_used :description: Used Memory :group: memory diff --git a/db/fixtures/chargeback_rates.yml b/db/fixtures/chargeback_rates.yml index d4200ac60b2..0eaad4ab04c 100644 --- a/db/fixtures/chargeback_rates.yml +++ b/db/fixtures/chargeback_rates.yml @@ -34,6 +34,16 @@ :finish: Infinity :fixed_rate: 1.0 :variable_rate: 0.0 + - :description: Allocated CPU Cores + :metric: derived_vm_numvcpu_cores + :per_time: hourly + :per_unit: cpu core + :type_currency: Dollars + :tiers: + - :start: 0 + :finish: Infinity + :fixed_rate: 1.0 + :variable_rate: 0.0 - :description: Used Memory :metric: derived_memory_used :per_time: hourly @@ -184,6 +194,16 @@ :finish: Infinity :fixed_rate: 1.0 :variable_rate: 0.0 + - :description: Allocated CPU Cores + :metric: derived_vm_numvcpu_cores + :per_time: hourly + :per_unit: cpu core + :type_currency: Dollars + :tiers: + - :start: 0 + :finish: Infinity + :fixed_rate: 1.0 + :variable_rate: 0.0 - :description: Used Memory :metric: derived_memory_used :per_time: hourly diff --git a/db/fixtures/miq_report_formats.yml b/db/fixtures/miq_report_formats.yml index ad1c08c179c..a14f0d62ccb 100644 --- a/db/fixtures/miq_report_formats.yml +++ b/db/fixtures/miq_report_formats.yml @@ -44,6 +44,8 @@ :cpu_cores_used_cost: :currency_precision_2 :cpu_allocated_cost: :currency_precision_2 :cpu_allocated_metric: :general_number_precision_0 + :cpu_cores_allocated_cost: :currency_precision_2 + :cpu_cores_allocated_metric: :general_number_precision_0 :cpu_cost: :currency_precision_2 :memory_used_cost: :currency_precision_2 :memory_allocated_cost: :currency_precision_2 diff --git a/spec/factories/chargeable_field.rb b/spec/factories/chargeable_field.rb index ea7a7135c6c..cc9ea37cacc 100644 --- a/spec/factories/chargeable_field.rb +++ b/spec/factories/chargeable_field.rb @@ -51,6 +51,13 @@ source 'used' end + factory :chargeable_field_cpu_cores_allocated, :parent => :chargeable_field do + description 'Allocated CPU in Cores' + metric 'derived_vm_numvcpu_cores' + group 'cpu_cores' + source 'allocated' + end + factory :chargeable_field_memory_used, :parent => :chargeable_field do description 'Used Memory in MB' metric 'derived_memory_used' diff --git a/spec/factories/chargeback_rate_detail.rb b/spec/factories/chargeback_rate_detail.rb index 3c8566c3408..e9b7c9445b4 100644 --- a/spec/factories/chargeback_rate_detail.rb +++ b/spec/factories/chargeback_rate_detail.rb @@ -60,6 +60,11 @@ chargeable_field { FactoryGirl.build(:chargeable_field_cpu_cores_used) } end + factory :chargeback_rate_detail_cpu_cores_allocated, :parent => :chargeback_rate_detail do + per_unit "cores" + chargeable_field { FactoryGirl.build(:chargeable_field_cpu_cores_allocated) } + end + factory :chargeback_rate_detail_cpu_allocated, :traits => [:daily], :parent => :chargeback_rate_detail do per_unit "cpu" diff --git a/spec/models/chargeback_container_image_spec.rb b/spec/models/chargeback_container_image_spec.rb index 873b5cbaf61..a50649beb62 100644 --- a/spec/models/chargeback_container_image_spec.rb +++ b/spec/models/chargeback_container_image_spec.rb @@ -4,6 +4,7 @@ let(:base_options) { {:interval_size => 2, :end_interval_offset => 0, :ext_options => {:tz => 'UTC'} } } let(:hourly_rate) { 0.01 } + let(:count_hourly_rate) { 1.00 } let(:starting_date) { Time.parse('2012-09-01 23:59:59Z').utc } let(:ts) { starting_date.in_time_zone(Metric::Helper.get_time_zone(options[:ext_options])) } let(:report_run_time) { month_end } @@ -13,11 +14,14 @@ let(:ems) { FactoryGirl.create(:ems_openshift) } let(:hourly_variable_tier_rate) { {:variable_rate => hourly_rate.to_s} } + let(:count_hourly_variable_tier_rate) { {:variable_rate => count_hourly_rate.to_s} } let(:detail_params) do { - :chargeback_rate_detail_fixed_compute_cost => {:tiers => [hourly_variable_tier_rate]}, - :chargeback_rate_detail_metering_used => {:tiers => [hourly_variable_tier_rate]} + :chargeback_rate_detail_fixed_compute_cost => {:tiers => [hourly_variable_tier_rate]}, + :chargeback_rate_detail_metering_used => {:tiers => [hourly_variable_tier_rate]}, + :chargeback_rate_detail_cpu_cores_allocated => {:tiers => [count_hourly_variable_tier_rate]}, + :chargeback_rate_detail_memory_allocated => {:tiers => [hourly_variable_tier_rate]} } end @@ -40,7 +44,8 @@ @project = FactoryGirl.create(:container_project, :name => "my project", :ext_management_system => ems) @group = FactoryGirl.create(:container_group, :ext_management_system => ems, :container_project => @project, :container_node => @node) - @container = FactoryGirl.create(:kubernetes_container, :container_group => @group, :container_image => @image) + @container = FactoryGirl.create(:kubernetes_container, :container_group => @group, :container_image => @image, + :limit_memory_bytes => 1.megabytes, :limit_cpu_cores => 1.0) cat = FactoryGirl.create(:classification, :description => "Environment", :name => "environment", :single_value => true, :show => true) c = FactoryGirl.create(:classification, :name => "prod", :description => "Production", :parent_id => cat.id) ChargebackRate.set_assignments(:compute, [{ :cb_rate => chargeback_rate, :tag => [c, "container_image"] }]) @@ -92,6 +97,14 @@ expect(subject.metering_used_metric).to eq(hours_in_day) expect(subject.metering_used_cost).to eq(hours_in_day * hourly_rate) end + + it "allocated fields" do + skip('this feature needs to be added to new chargeback rating') if Settings.new_chargeback + expect(subject.cpu_cores_allocated_cost).to eq(@container.limit_cpu_cores * count_hourly_rate * hours_in_day) + expect(subject.cpu_cores_allocated_metric).to eq(@container.limit_cpu_cores) + expect(subject.cpu_cores_allocated_cost).to eq(@container.limit_memory_bytes / 1.megabytes * count_hourly_rate * hours_in_day) + expect(subject.cpu_cores_allocated_metric).to eq(@container.limit_memory_bytes / 1.megabytes) + end end context "Monthly" do @@ -117,6 +130,14 @@ expect(subject.metering_used_metric).to eq(hours_in_month) expect(subject.metering_used_cost).to eq(hours_in_month * hourly_rate) end + + it "allocated fields" do + skip('this feature needs to be added to new chargeback rating') if Settings.new_chargeback + expect(subject.cpu_cores_allocated_cost).to eq(@container.limit_cpu_cores * count_hourly_rate * hours_in_month) + expect(subject.cpu_cores_allocated_metric).to eq(@container.limit_cpu_cores) + expect(subject.cpu_cores_allocated_cost).to eq(@container.limit_memory_bytes / 1.megabytes * count_hourly_rate * hours_in_month) + expect(subject.cpu_cores_allocated_metric).to eq(@container.limit_memory_bytes / 1.megabytes) + end end context "Label" do diff --git a/spec/models/chargeback_rate_detail_spec.rb b/spec/models/chargeback_rate_detail_spec.rb index e399c41467b..8df4a445262 100644 --- a/spec/models/chargeback_rate_detail_spec.rb +++ b/spec/models/chargeback_rate_detail_spec.rb @@ -21,6 +21,7 @@ rates = ChargebackRateDetail.default_rate_details_for('Compute') expected_metrics = %w( derived_vm_numvcpus + derived_vm_numvcpu_cores cpu_usagemhz_rate_average v_derived_cpu_total_cores_used disk_usage_rate_average