Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Export by safer element's filename or id #19702

Closed
38 changes: 27 additions & 11 deletions lib/services/dialog_import_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,35 @@ def cancel_import(import_file_upload_id)
def import_from_file(filename)
dialogs = YAML.load_file(filename)

begin
dialogs.each do |dialog|
dialog.except!(:blueprint_id, 'blueprint_id') # blueprint_id might appear in some old dialogs, but no longer exists
if dialog_with_label?(dialog["label"])
if dialogs.class == Hash
begin
dialogs.except!(:blueprint_id, 'blueprint_id') # blueprint_id might appear in some old dialogs, but no longer exists
if dialog_with_label?(dialogs["label"])
yield dialog if block_given?
else
Dialog.create(dialog.except('export_version').merge("dialog_tabs" => build_dialog_tabs(dialog, dialog['export_version'] || DEFAULT_DIALOG_VERSION)))
Dialog.create(dialogs.except(:export_version, 'export_version', :class, 'class', :id, 'id').merge("dialog_tabs" => build_dialog_tabs(dialogs, dialogs['export_version'] || DEFAULT_DIALOG_VERSION)))
end
rescue DialogFieldImporter::InvalidDialogFieldTypeError
raise
rescue
raise ParsedNonDialogYamlError
end

elsif dialogs.class == Array
begin
dialogs.each do |dialog|
dialog.except!(:blueprint_id, 'blueprint_id') # blueprint_id might appear in some old dialogs, but no longer exists
if dialog_with_label?(dialog["label"])
yield dialog if block_given?
else
Dialog.create(dialog.except(:export_version, 'export_version', :class, 'class', :id, 'id').merge("dialog_tabs" => build_dialog_tabs(dialog, dialog['export_version'] || DEFAULT_DIALOG_VERSION)))
end
end
rescue DialogFieldImporter::InvalidDialogFieldTypeError
raise
rescue
raise ParsedNonDialogYamlError
end
rescue DialogFieldImporter::InvalidDialogFieldTypeError
raise
rescue
raise ParsedNonDialogYamlError
end
end

Expand Down Expand Up @@ -68,7 +84,7 @@ def store_for_import(file_contents)
end

def build_dialog_tabs(dialog, export_version = CURRENT_DIALOG_VERSION)
dialog["dialog_tabs"].collect do |dialog_tab|
dialog[:dialog_tabs].collect do |dialog_tab|
DialogTab.create(dialog_tab.merge("dialog_groups" => build_dialog_groups(dialog_tab, export_version)))
end
end
Expand Down Expand Up @@ -100,7 +116,7 @@ def check_field_associations(fields)

def import(dialog)
@dialog_import_validator.determine_dialog_validity(dialog)
new_dialog = Dialog.create(dialog.except('dialog_tabs', 'export_version'))
new_dialog = Dialog.create(dialog.except(:dialog_tabs, 'dialog_tabs', :export_version, 'export_version', :class, 'class', :id, 'id'))
association_list = build_association_list(dialog)
new_dialog.update!(dialog.merge('dialog_tabs' => build_dialog_tabs(dialog, dialog['export_version'] || DEFAULT_DIALOG_VERSION)))
build_associations(new_dialog, association_list)
Expand Down
50 changes: 47 additions & 3 deletions lib/task_helpers/exports.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,51 @@
module TaskHelpers
class Exports
def self.safe_filename(filename, keep_spaces = false)
new_filename = keep_spaces ? filename : filename.gsub(%r{[ ]}, '_')
new_filename.gsub(%r{[|/]}, '/' => 'slash', '|' => 'pipe')
def self.get_tmp_filename(my_object)
# Description: This method is used to generate a legacy, error-prone filename based on selected string fields.
# There is no handling of CustomButtons because safe_filename is not called.
# Build Arrays for plain classes where filenames are either set by name or description
description_types = [MiqAlert, MiqAlertSet, MiqPolicy, MiqPolicySet, Classification, MiqWidget]
names_types = [GenericObjectDefinition, MiqReport, ScanItemSet, MiqSchedule]
tmp_filename = ''
if names_types.include?(my_object.class)
tmp_filename = my_object.name
elsif description_types.include?(my_object.class)
tmp_filename = my_object.description
# Handle specifically crafted Hashes
elsif my_object.class == Hash
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we tend to prefer is_a? or kind_of?

# CustomizationTemplate Hash
if my_object[:class].include?("CustomizationTemplate")
image_type_name = my_object.fetch_path(:pxe_image_type, :name) || "Examples"
tmp_filename = "#{image_type_name}-#{my_object[:name]}"
# Provisioning Dialog Hash
elsif my_object[:class].include?("MiqDialog")
tmp_filename = "#{my_object[:dialog_type]}-#{my_object[:name]}"
# Role Hash
elsif my_object[:class].include?("MiqUserRole")
tmp_filename = role_hash[:name]
# Service Dialog Hash
elsif my_object[:class].include?("Dialog")
tmp_filename = my_object[:label]
end
end
tmp_filename
end

def self.safe_filename(my_object, keep_spaces = false, super_safe_filename = false)
# Description: generate a safe filename either by some string fields or by object id's.
# We expect parameter object to be a crafted hash or a miq class suitable for export.

new_filename = ''
# Generate filename by id. Hashes and Miq classes must be handled.
if super_safe_filename
new_filename = my_object.class == Hash ? my_object[:id] : my_object.id
# Generate filename by not so safe strings.
else
tmp_filename = Exports.get_tmp_filename(my_object)
new_filename = keep_spaces ? tmp_filename : tmp_filename.gsub(%r{[ ]}, '_')
new_filename.gsub(%r{[|/]}, '/' => 'slash', '|' => 'pipe')
end
new_filename
end

def self.parse_options
Expand All @@ -11,6 +54,7 @@ def self.parse_options
opt :keep_spaces, 'Keep spaces in filenames', :type => :boolean, :short => 's', :default => false
opt :directory, 'Directory to place exported files in', :type => :string, :required => true
opt :all, 'Export read-only objects', :type => :boolean, :default => false
opt :super_safe_filename, 'Filenames are generated by object id', :type => :boolean, :default => true
end

error = validate_directory(options[:directory])
Expand Down
2 changes: 1 addition & 1 deletion lib/task_helpers/exports/alert_sets.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ def export(options = {})
MiqAlertSet.order(:id).all.each do |alert_set|
$log.info("Exporting Alert Profile: #{alert_set.description} (ID: #{alert_set.id})")

filename = Exports.safe_filename(alert_set.description, options[:keep_spaces])
filename = Exports.safe_filename(alert_set.description, options[:keep_spaces], options[:super_safe_filename])
File.write("#{export_dir}/#{filename}.yaml", alert_set.export_to_yaml)
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/task_helpers/exports/alerts.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ def export(options = {})
MiqAlert.order(:id).all.each do |alert|
$log.info("Exporting Alert: #{alert.description} (ID: #{alert.id})")

filename = Exports.safe_filename(alert.description, options[:keep_spaces])
filename = Exports.safe_filename(alert.description, options[:keep_spaces], options[:super_safe_filename])
File.write("#{export_dir}/#{filename}.yaml", alert.export_to_yaml)
end
end
Expand Down
5 changes: 2 additions & 3 deletions lib/task_helpers/exports/customization_templates.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module TaskHelpers
class Exports
class CustomizationTemplates
EXCLUDE_ATTRS = %i(created_at updated_at id pxe_image_type_id class).freeze
EXCLUDE_ATTRS = %i(created_at updated_at pxe_image_type_id).freeze
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change makes me think that this maybe isn't the right way to do this.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you elaborate your thoughts? Whats the point in removing these attributes anyway? You can still throw them away while importing.

def export(options = {})
export_dir = options[:directory]

Expand All @@ -13,8 +13,7 @@ def export(options = {})
ct_hash = Exports.exclude_attributes(customization_template.to_model_hash, EXCLUDE_ATTRS)
ct_hash.merge!(pxe_image_type_hash(customization_template.pxe_image_type))

image_type_name = ct_hash.fetch_path(:pxe_image_type, :name) || "Examples"
filename = Exports.safe_filename("#{image_type_name}-#{ct_hash[:name]}", options[:keep_spaces])
filename = Exports.safe_filename(ct_hash, options[:keep_spaces], options[:super_safe_filename])
File.write("#{export_dir}/#{filename}.yaml", ct_hash.to_yaml)
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/task_helpers/exports/generic_object_definitions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ class GenericObjectDefinitions
def export(options = {})
export_dir = options[:directory]
GenericObjectDefinition.all.each do |god|
filename = Exports.safe_filename(god.name, options[:keep_spaces])
filename = Exports.safe_filename(god.name, options[:keep_spaces], options[:super_safe_filename])
File.write("#{export_dir}/#{filename}.yaml", god.export_to_array.to_yaml)
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/task_helpers/exports/policies.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ def export(options = {})
policies.order(:id).each do |policy|
$log.info("Exporting Policy: #{policy.description} (ID: #{policy.id})")

filename = Exports.safe_filename(policy.description, options[:keep_spaces])
filename = Exports.safe_filename(policy.description, options[:keep_spaces], options[:super_safe_filename])
File.write("#{export_dir}/#{filename}.yaml", policy.export_to_yaml)
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/task_helpers/exports/policy_sets.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ def export(options = {})
policy_sets.order(:id).each do |policy_set|
$log.info("Exporting Policy Profile: #{policy_set.description} (ID: #{policy_set.id})")

filename = Exports.safe_filename(policy_set.description, options[:keep_spaces])
filename = Exports.safe_filename(policy_set.description, options[:keep_spaces], options[:super_safe_filename])
File.write("#{export_dir}/#{filename}.yaml", policy_set.export_to_yaml)
end
end
Expand Down
4 changes: 2 additions & 2 deletions lib/task_helpers/exports/provision_dialogs.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module TaskHelpers
class Exports
class ProvisionDialogs
EXCLUDE_ATTRS = %i(file_mtime created_at updated_at id class).freeze
EXCLUDE_ATTRS = %i(file_mtime created_at updated_at).freeze
def export(options = {})
export_dir = options[:directory]

Expand All @@ -12,7 +12,7 @@ def export(options = {})

dialog_hash = Exports.exclude_attributes(dialog.to_model_hash, EXCLUDE_ATTRS)

filename = Exports.safe_filename("#{dialog_hash[:dialog_type]}-#{dialog_hash[:name]}", options[:keep_spaces])
filename = Exports.safe_filename(dialog_hash, options[:keep_spaces], options[:super_safe_filename])
File.write("#{export_dir}/#{filename}.yaml", dialog_hash.to_yaml)
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/task_helpers/exports/reports.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ def export(options = {})
custom_reports = options[:all] ? MiqReport.all : MiqReport.where(:rpt_type => "Custom")

custom_reports.each do |report|
filename = Exports.safe_filename(report.name, options[:keep_spaces])
filename = Exports.safe_filename(report.name, options[:keep_spaces], options[:super_safe_filename])
File.write("#{export_dir}/#{filename}.yaml", report.export_to_array.to_yaml)
end
end
Expand Down
7 changes: 4 additions & 3 deletions lib/task_helpers/exports/roles.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module TaskHelpers
class Exports
class Roles
EXCLUDE_ATTRS = %w(created_at updated_at id).freeze
EXCLUDE_ATTRS = %w(created_at updated_at).freeze
def export(options = {})
export_dir = options[:directory]

Expand All @@ -11,8 +11,9 @@ def export(options = {})
$log.info("Exporting Role: #{role.name} (ID: #{role.id})")

role_hash = Exports.exclude_attributes(role.attributes, EXCLUDE_ATTRS).merge('feature_identifiers' => role.feature_identifiers.sort)

filename = Exports.safe_filename(role_hash['name'], options[:keep_spaces])
role_hash["class"] = role.class.to_s
role_hash = role_hash.symbolize_keys
filename = Exports.safe_filename(role_hash, options[:keep_spaces], options[:super_safe_filename])
File.write("#{export_dir}/#{filename}.yaml", [role_hash].to_yaml)
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/task_helpers/exports/scan_profiles.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def export(options = {})

scan_profile = profile.to_yaml

filename = Exports.safe_filename(scan_item_set.name, options[:keep_spaces])
filename = Exports.safe_filename(scan_item_set.name, options[:keep_spaces], options[:super_safe_filename])
File.write("#{export_dir}/#{filename}.yaml", scan_profile)
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/task_helpers/exports/schedules.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ def export(options = {})
schedules = options[:all] ? MiqSchedule.all : MiqSchedule.where(:userid => 'system', :prod_default => 'system')

schedules.each do |schedule|
filename = Exports.safe_filename(schedule.name, options[:keep_spaces])
filename = Exports.safe_filename(schedule.name, options[:keep_spaces], options[:super_safe_filename])
File.write("#{export_dir}/#{filename}.yaml", MiqSchedule.export_to_yaml([schedule], MiqSchedule))
end
end
Expand Down
7 changes: 5 additions & 2 deletions lib/task_helpers/exports/service_dialogs.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ def export(options = {})
dialogs.each do |dialog|
$log.info("Exporting Service Dialog: #{dialog.name} (ID: #{dialog.id})")

dialog_hash = DialogSerializer.new.serialize([dialog])
dialog_hash = DialogSerializer.new.serialize([dialog]).first
dialog_hash["id"] = dialog.id
dialog_hash["class"] = dialog.class.to_s
dialog_hash = dialog_hash.symbolize_keys

filename = Exports.safe_filename(dialog_hash.first['label'], options[:keep_spaces])
filename = Exports.safe_filename(dialog_hash, options[:keep_spaces], options[:super_safe_filename])
File.write("#{export_dir}/#{filename}.yaml", dialog_hash.to_yaml)
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/task_helpers/exports/tags.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def export(options = {})
category_array = category.export_to_array
category_array.first["ns"] = category.ns unless category.ns == '/managed'

filename = Exports.safe_filename(category.description, options[:keep_spaces])
filename = Exports.safe_filename(category.description, options[:keep_spaces], options[:super_safe_filename])
File.write("#{export_dir}/#{filename}.yaml", category_array.to_yaml)
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/task_helpers/exports/widgets.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ def export(options = {})
widgets = options[:all] ? MiqWidget.all : MiqWidget.where(:read_only => false)

widgets.each do |widget|
filename = Exports.safe_filename(widget.description, options[:keep_spaces])
filename = Exports.safe_filename(widget.description, options[:keep_spaces], options[:super_safe_filename])
File.write("#{export_dir}/#{filename}.yaml", MiqWidget.export_to_yaml([widget.id], MiqWidget))
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/task_helpers/imports/service_dialogs.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def import(options = {})
Dir.glob(glob) do |filename|
$log.info("Importing Service Dialogs from: #{filename}")

DialogImportService.new.import_all_service_dialogs_from_yaml_file(filename)
DialogImportService.new.import_from_file(filename)
end
end
end
Expand Down