diff --git a/lib/task_helpers/exports/custom_buttons.rb b/lib/task_helpers/exports/custom_buttons.rb index 6e5a98c853c..3c8388237fb 100644 --- a/lib/task_helpers/exports/custom_buttons.rb +++ b/lib/task_helpers/exports/custom_buttons.rb @@ -3,11 +3,15 @@ class Exports class CustomButtons class ExportArInstances EXCLUDE_ATTRS = %w(id created_on updated_on created_at updated_at dialog_id resource_id).freeze + def self.export_object(obj, hash) class_name = obj.class.name.underscore $log.info("Exporting #{obj.class.name}: #{obj.try('name')} (ID: #{obj&.id})") - (hash[class_name] ||= []) << item = { 'attributes' => build_attr_list(obj.try(:attributes)) } + attrs = build_attr_list(obj.attributes) + # handle dialog label + attrs["dialog_label"] = obj.dialog&.label if obj.respond_to?(:dialog) + (hash[class_name] ||= []) << item = {'attributes' => attrs} create_association_list(obj, item) descendant_list(obj, item) end @@ -18,8 +22,9 @@ def self.build_attr_list(attrs) def self.create_association_list(obj, item) associations = obj.class.try(:reflections) + if associations - associations = associations.collect { |model, assoc| { model => assoc.class.to_s.demodulize } }.select { |as| as.values.first != "BelongsToReflection" && as.keys.first != "all_relationships" } + associations = associations.collect { |model, assoc| {model => assoc.class.to_s.demodulize} }.select { |as| as.values.first != "BelongsToReflection" && as.keys.first != "all_relationships" } associations.each do |assoc| assoc.each do |a| next if obj.try(a.first.to_sym).blank? @@ -36,7 +41,7 @@ def self.descendant_list(obj, item) def export(options = {}) parent_id_list = [] - objects = CustomButton.where.not(:applies_to_class => %w(ServiceTemplate GenericObject)) + objects = CustomButton.in_region(MiqRegion.my_region_number).order(:id).where.not(:applies_to_class => %w[ServiceTemplate GenericObject]) export = objects.each_with_object({}) do |obj, export_hash| if obj.try(:parent).present? diff --git a/lib/task_helpers/imports.rb b/lib/task_helpers/imports.rb index 81eef8a7762..7ffd9c2c878 100644 --- a/lib/task_helpers/imports.rb +++ b/lib/task_helpers/imports.rb @@ -5,6 +5,7 @@ def self.parse_options options = Optimist.options(EvmRakeHelper.extract_command_options) do opt :source, 'Directory or file to import from', :type => :string, :required => true opt :overwrite, 'Overwrite existing object', :type => :boolean, :default => true + opt :connect_dialog_by_name, 'for custom buttons: in case dialog with exported name exist, connect it' end error = validate_source(options[:source]) diff --git a/lib/task_helpers/imports/custom_buttons.rb b/lib/task_helpers/imports/custom_buttons.rb index 5724d51b9be..a805970d944 100644 --- a/lib/task_helpers/imports/custom_buttons.rb +++ b/lib/task_helpers/imports/custom_buttons.rb @@ -3,12 +3,13 @@ class Imports class CustomButtons def import(options) return unless options[:source] + glob = File.file?(options[:source]) ? options[:source] : "#{options[:source]}/*.yaml" Dir.glob(glob) do |filename| $log.info("Importing Custom Buttons from: #{filename}") begin - import_custom_buttons(filename) + import_custom_buttons(filename, options[:connect_dialog_by_name]) rescue StandardError raise StandardError, "Error importing #{filename} at #{$@}" end @@ -18,11 +19,12 @@ def import(options) private class ImportArInstances - def self.import(obj_hash) - new.import(obj_hash) + def self.import(obj_hash, connect_dialog_by_name) + new.import(obj_hash, connect_dialog_by_name) end - def import(obj_hash) + def import(obj_hash, connect_dialog_by_name) + @connect_dialog = connect_dialog_by_name ActiveRecord::Base.transaction { obj_hash.each { |obj_def| create_object(*obj_def) } } end @@ -52,10 +54,16 @@ def add_children(obj, new_obj) end def add_associations(obj, new_obj) - if obj['associations'].present? - obj['associations'].each do |assoc| - new_obj.send("#{assoc.first}=", create_object(*assoc).first) + return if obj['associations'].blank? + + obj['associations'].each do |assoc| + # may contain dialog_label,delete it, then find and connect dialog (optionally) + dialog_label = assoc.last.first['attributes'].delete('dialog_label') + resource_action = create_object(*assoc).first + if @connect_dialog + resource_action.dialog = Dialog.in_region(MiqRegion.my_region_number).find_by(:label => dialog_label) if dialog_label end + new_obj.send("#{assoc.first}=", resource_action) end end @@ -74,9 +82,9 @@ def check_user(new_obj) end end - def import_custom_buttons(filename) + def import_custom_buttons(filename, connect_dialog_by_name) custom_buttons = YAML.load_file(filename) - ImportArInstances.import(custom_buttons) + ImportArInstances.import(custom_buttons, connect_dialog_by_name) end end end diff --git a/spec/lib/task_helpers/imports/custom_buttons_spec.rb b/spec/lib/task_helpers/imports/custom_buttons_spec.rb index 61dc256c95e..0836c6a7088 100644 --- a/spec/lib/task_helpers/imports/custom_buttons_spec.rb +++ b/spec/lib/task_helpers/imports/custom_buttons_spec.rb @@ -5,7 +5,10 @@ let(:custom_button_set_name) { 'group1|Vm|' } let(:custom_button_set_description) { 'group1' } let(:resource_action_ae_namespace) { 'SYSTEM' } - let(:options) { {:source => source} } + let(:connect_dialog_by_name) { true } + let(:options) { {:source => source, :connect_dialog_by_name => connect_dialog_by_name} } + let!(:test_dialog) { FactoryBot.create(:dialog, :label => 'dialog') } + let!(:test_dialog_2) { FactoryBot.create(:dialog, :label => 'dialog 2') } describe "#import" do describe "when the source is a directory" do @@ -27,11 +30,10 @@ context "yaml import failure" do it 'should raise' do - file = Tempfile.new('foo.yaml', data_dir) - file.write("bad yaml here") - TaskHelpers::Imports::CustomButtons.new.import(options) - assert_raises_import_error - assert_imports_only_custom_button_set_one + Tempfile.create(%w[foo .yaml], data_dir) do |file| + file.write("bad yaml here") + assert_raises_import_error + end end end end @@ -41,32 +43,53 @@ context "without existing buttons" do context "only imports good yaml" do - it 'imports a specified file' do - TaskHelpers::Imports::CustomButtons.new.import(options) - assert_test_custom_button_set_present - assert_imports_only_custom_button_set_one + context "connect dialog flag is set" do + it 'imports a specified file' do + TaskHelpers::Imports::CustomButtons.new.import(options) + assert_test_custom_button_set_present + assert_imports_only_custom_button_set_one + assert_dialog_is_set(true) + end + end + context "connect dialog flag not set" do + let(:connect_dialog_by_name) { false } + it 'imports a specified file' do + TaskHelpers::Imports::CustomButtons.new.import(options) + assert_test_custom_button_set_present + assert_imports_only_custom_button_set_one + assert_dialog_is_set(false) + end end end + end - context "doesn't import bad yaml" do - let(:source) { "#{data_dir}/#{bad_custom_button_file}" } - it 'does not imports a specified file' do - TaskHelpers::Imports::CustomButtons.new.import(options) - assert_imports_no_custom_buttons - end + context "doesn't import bad yaml" do + let(:source) { "#{data_dir}/#{bad_custom_button_file}" } + it 'does not imports a specified file' do + TaskHelpers::Imports::CustomButtons.new.import(options) + assert_imports_no_custom_buttons end end context "with existing identical buttons" do it 'should not import anything' do TaskHelpers::Imports::CustomButtons.new.import(options) - assert_raises_import_error assert_imports_only_custom_button_set_one end end end end + def assert_dialog_is_set(connect) + btn1 = CustomButton.find_by(:name => 'button 1') + expect(btn1).to be_an(CustomButton) + if connect + expect(btn1.resource_action.dialog.id).to eq(test_dialog_2.id) + else + expect(btn1.resource_action.dialog).to be_nil + end + end + def assert_test_custom_button_set_present cbs = CustomButtonSet.find_by(:name => custom_button_set_name) expect(cbs.custom_buttons.count).to eq(3) diff --git a/spec/lib/task_helpers/imports/data/custom_buttons/CustomButtons.yaml b/spec/lib/task_helpers/imports/data/custom_buttons/CustomButtons.yaml index c8732ffa14c..7c02107ae72 100644 --- a/spec/lib/task_helpers/imports/data/custom_buttons/CustomButtons.yaml +++ b/spec/lib/task_helpers/imports/data/custom_buttons/CustomButtons.yaml @@ -57,6 +57,7 @@ custom_button_set: request: test1 configuration_template_id: configuration_template_type: + dialog_label: dialog 2 - attributes: guid: 3f50d617-851e-451f-95ae-a17fc548cb11 description: button 2 @@ -92,6 +93,7 @@ custom_button_set: request: test2 configuration_template_id: configuration_template_type: + dialog_label: - attributes: guid: d3cd608a-f476-48b7-aa25-a930ec046e00 description: multiselect @@ -132,3 +134,4 @@ custom_button_set: request: multiselect configuration_template_id: configuration_template_type: + dialog_label: