diff --git a/app/models/mixins/custom_attribute_mixin.rb b/app/models/mixins/custom_attribute_mixin.rb index a3b52a9a815..243ede40b29 100644 --- a/app/models/mixins/custom_attribute_mixin.rb +++ b/app/models/mixins/custom_attribute_mixin.rb @@ -27,7 +27,10 @@ module CustomAttributeMixin end def self.custom_keys - CustomAttribute.where(:resource_type => base_class).distinct.pluck(:name).compact + custom_attr_scope = CustomAttribute.where(:resource_type => base_class).where.not(:name => nil).distinct.pluck(:name, :section) + custom_attr_scope.map do |x| + "#{x[0]}#{x[1] ? SECTION_SEPARATOR + x[1] : ''}" + end end def self.load_custom_attributes_for(cols) @@ -41,8 +44,14 @@ def self.add_custom_attribute(custom_attribute) virtual_column(custom_attribute.to_sym, :type => :string, :uses => :custom_attributes) define_method(custom_attribute.to_sym) do - custom_attribute_without_prefix = custom_attribute.sub(CUSTOM_ATTRIBUTES_PREFIX, "") - custom_attributes.detect { |x| custom_attribute_without_prefix == x.name }.try(:value) + custom_attribute_without_prefix = custom_attribute.sub(CUSTOM_ATTRIBUTES_PREFIX, "") + custom_attribute_without_section, section = custom_attribute_without_prefix.split(SECTION_SEPARATOR) + + where_args = {} + where_args[:name] = custom_attribute_without_section + where_args[:section] = section if section + + custom_attributes.find_by(where_args).try(:value) end end end diff --git a/lib/miq_expression/field.rb b/lib/miq_expression/field.rb index 5293f1d06ef..0bc08498e17 100644 --- a/lib/miq_expression/field.rb +++ b/lib/miq_expression/field.rb @@ -5,7 +5,7 @@ class MiqExpression::Field < MiqExpression::Target \.?(?[a-z][0-9a-z_\.]+)? - (?: - (?#{CustomAttributeMixin::CUSTOM_ATTRIBUTES_PREFIX}[a-z]+[_\-.\/[:alnum:]]*)| + (?#{CustomAttributeMixin::CUSTOM_ATTRIBUTES_PREFIX}[a-z]+[:_\-.\/[:alnum:]]*)| (?[a-z]+(_[[:alnum:]]+)*) ) /x diff --git a/spec/lib/miq_expression_spec.rb b/spec/lib/miq_expression_spec.rb index ea84b414b68..5b3ee41260c 100644 --- a/spec/lib/miq_expression_spec.rb +++ b/spec/lib/miq_expression_spec.rb @@ -1919,6 +1919,27 @@ it "ignores custom_attibutes with a nil name" do expect(MiqExpression._custom_details_for("Vm", {})).to eq([["Custom Attribute: CATTR_1", "Vm-virtual_custom_attribute_CATTR_1"]]) end + + let(:conatiner_image) { FactoryGirl.create(:container_image) } + + let!(:custom_attribute_with_section_1) do + FactoryGirl.create(:custom_attribute, :resource => conatiner_image, :name => 'CATTR_3', :value => "Value 3", + :section => 'section_3') + end + + let!(:custom_attribute_with_section_2) do + FactoryGirl.create(:custom_attribute, :resource => conatiner_image, :name => 'CATTR_3', :value => "Value 3", + :section => 'docker_labels') + end + + it "returns human names of custom attributes with sections" do + expected_result = [ + ['Docker Labels: CATTR_3', 'ContainerImage-virtual_custom_attribute_CATTR_3:SECTION:docker_labels'], + ['Section 3: CATTR_3', 'ContainerImage-virtual_custom_attribute_CATTR_3:SECTION:section_3'] + ] + + expect(MiqExpression._custom_details_for("ContainerImage", {})).to match_array(expected_result) + end end context ".build_relats" do diff --git a/spec/models/miq_report_spec.rb b/spec/models/miq_report_spec.rb index 01babdd9743..80d7e075384 100644 --- a/spec/models/miq_report_spec.rb +++ b/spec/models/miq_report_spec.rb @@ -119,6 +119,55 @@ ) end + context 'with container images' do + let(:report) do + MiqReport.new( + :name => "Custom VM report", :title => "Custom VM report", :rpt_group => "Custom", :rpt_type => "Custom", + :db => "ContainerImage", + :cols => ['name', + "virtual_custom_attribute_CATTR#{CustomAttributeMixin::SECTION_SEPARATOR}docker_labels", + "virtual_custom_attribute_CATTR#{CustomAttributeMixin::SECTION_SEPARATOR}labels"], + :include => {:custom_attributes => {}}, + :col_order => %w(name CATTR), + :headers => ["Name", custom_column_key_1, custom_column_key_1], + :order => "Ascending" + ) + end + + let!(:container_image) do + FactoryGirl.create(:container_image, :name => "test_container_images") + end + + let!(:custom_attribute_1) do + FactoryGirl.create(:custom_attribute, :resource => container_image, :name => 'CATTR', :value => 'any_value', + :section => 'docker_labels') + end + + let!(:custom_attribute_2) do + FactoryGirl.create(:custom_attribute, :resource => container_image, :name => 'CATTR', :value => 'other_value', + :section => 'labels') + end + + it "generates report with dynamic custom attributes" do + report.queue_generate_table(:userid => user.userid) + report._async_generate_table(miq_task.id, :userid => user.userid, :mode => "async", + :report_source => "Requested by user") + + report_result = report.table.data.map do |x| + x.data.delete("id") + x.data + end + + expected_results = [ + {"name" => "test_container_images", + "virtual_custom_attribute_CATTR#{CustomAttributeMixin::SECTION_SEPARATOR}docker_labels" => "any_value", + "virtual_custom_attribute_CATTR#{CustomAttributeMixin::SECTION_SEPARATOR}labels" => "other_value"} + ] + + expect(report_result).to match_array(expected_results) + end + end + it "generates report with dynamic custom attributes" do report.queue_generate_table(:userid => user.userid) report._async_generate_table(miq_task.id, :userid => user.userid, :mode => "async", diff --git a/spec/models/mixins/custom_attribute_mixin_spec.rb b/spec/models/mixins/custom_attribute_mixin_spec.rb index 131e36c4540..8cf75ecee30 100644 --- a/spec/models/mixins/custom_attribute_mixin_spec.rb +++ b/spec/models/mixins/custom_attribute_mixin_spec.rb @@ -28,6 +28,21 @@ def self.name; "TestClass"; end end end + describe '#custom_keys' do + let!(:custom_attribute) { FactoryGirl.create(:custom_attribute, :name => "attr_1", :value => 'value') } + let!(:custom_attribute_with_section) do + FactoryGirl.create(:custom_attribute, :name => "attr_2", :value => 'value', :section => 'labels') + end + + let!(:vm) do + FactoryGirl.create(:vm_redhat, :custom_attributes => [custom_attribute, custom_attribute_with_section]) + end + + it 'returns human form of virtual custom attribute with sections' do + expect(vm.class.custom_keys).to match_array(["attr_1", "attr_2#{described_class::SECTION_SEPARATOR}labels"]) + end + end + it "defines #miq_custom_keys" do expect(test_class.new).to respond_to(:miq_custom_keys) end