foreman_bootdisk 13.0.0 → 16.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/AUTHORS +29 -0
  3. data/CHANGES.md +4 -0
  4. data/README.md +19 -2
  5. data/app/controllers/foreman_bootdisk/api/v2/disks_controller.rb +11 -9
  6. data/app/controllers/foreman_bootdisk/api/v2/subnet_disks_controller.rb +37 -31
  7. data/app/controllers/foreman_bootdisk/disks_controller.rb +20 -19
  8. data/app/helpers/concerns/foreman_bootdisk/hosts_helper_ext.rb +86 -45
  9. data/app/lib/foreman_bootdisk/scope/bootdisk.rb +2 -0
  10. data/app/lib/foreman_bootdisk/scope/full_host_bootdisk.rb +15 -0
  11. data/app/models/concerns/foreman_bootdisk/compute_resources/vmware.rb +4 -2
  12. data/app/models/concerns/foreman_bootdisk/host_ext.rb +42 -30
  13. data/app/models/concerns/foreman_bootdisk/orchestration/compute.rb +14 -10
  14. data/app/models/setting/bootdisk.rb +21 -23
  15. data/app/services/foreman_bootdisk/iso_generator.rb +144 -104
  16. data/app/services/foreman_bootdisk/renderer.rb +17 -13
  17. data/app/views/foreman_bootdisk/generic_static_host.erb +34 -0
  18. data/app/views/foreman_bootdisk/host.erb +27 -11
  19. data/config/routes.rb +15 -13
  20. data/config/routes/mount_engine.rb +3 -1
  21. data/db/migrate/20130914211030_create_host_bootdisk_template.rb +4 -4
  22. data/db/migrate/20130915104500_edit_host_bootdisk_template_multinic.rb +4 -4
  23. data/db/migrate/20130915133321_create_kickstart_bootdisk_template.rb +4 -4
  24. data/db/migrate/20130915201457_create_generic_host_bootdisk_template.rb +4 -4
  25. data/db/migrate/20131021095100_edit_host_bootdisk_template_dns_secondary.rb +4 -4
  26. data/db/migrate/20140522185700_change_templatekind_to_bootdisk.rb +16 -14
  27. data/db/migrate/20171009225200_remove_duplicate_bootdisk_templates.rb +4 -2
  28. data/db/seeds.d/50-bootdisk_templates.rb +21 -36
  29. data/lib/foreman_bootdisk.rb +2 -0
  30. data/lib/foreman_bootdisk/engine.rb +26 -37
  31. data/lib/foreman_bootdisk/version.rb +3 -1
  32. data/lib/tasks/bootdisk.rake +34 -17
  33. data/locale/ca/LC_MESSAGES/foreman_bootdisk.mo +0 -0
  34. data/locale/ca/foreman_bootdisk.po +31 -15
  35. data/locale/de/LC_MESSAGES/foreman_bootdisk.mo +0 -0
  36. data/locale/de/foreman_bootdisk.po +39 -21
  37. data/locale/en/LC_MESSAGES/foreman_bootdisk.mo +0 -0
  38. data/locale/en/foreman_bootdisk.po +24 -9
  39. data/locale/en_GB/LC_MESSAGES/foreman_bootdisk.mo +0 -0
  40. data/locale/en_GB/foreman_bootdisk.po +30 -15
  41. data/locale/es/LC_MESSAGES/foreman_bootdisk.mo +0 -0
  42. data/locale/es/foreman_bootdisk.po +48 -33
  43. data/locale/foreman_bootdisk.pot +80 -52
  44. data/locale/fr/LC_MESSAGES/foreman_bootdisk.mo +0 -0
  45. data/locale/fr/foreman_bootdisk.po +30 -15
  46. data/locale/gemspec.rb +3 -1
  47. data/locale/it/LC_MESSAGES/foreman_bootdisk.mo +0 -0
  48. data/locale/it/foreman_bootdisk.po +28 -13
  49. data/locale/ja/LC_MESSAGES/foreman_bootdisk.mo +0 -0
  50. data/locale/ja/foreman_bootdisk.po +29 -14
  51. data/locale/ko/LC_MESSAGES/foreman_bootdisk.mo +0 -0
  52. data/locale/ko/foreman_bootdisk.po +28 -13
  53. data/locale/pt_BR/LC_MESSAGES/foreman_bootdisk.mo +0 -0
  54. data/locale/pt_BR/foreman_bootdisk.po +42 -26
  55. data/locale/ru/LC_MESSAGES/foreman_bootdisk.mo +0 -0
  56. data/locale/ru/foreman_bootdisk.po +28 -13
  57. data/locale/sv_SE/LC_MESSAGES/foreman_bootdisk.mo +0 -0
  58. data/locale/sv_SE/foreman_bootdisk.po +26 -11
  59. data/locale/zh_CN/LC_MESSAGES/foreman_bootdisk.mo +0 -0
  60. data/locale/zh_CN/foreman_bootdisk.po +46 -31
  61. data/locale/zh_TW/LC_MESSAGES/foreman_bootdisk.mo +0 -0
  62. data/locale/zh_TW/foreman_bootdisk.po +28 -13
  63. data/release-gem +84 -0
  64. data/test/functional/foreman_bootdisk/api/v2/disks_controller_test.rb +35 -33
  65. data/test/functional/foreman_bootdisk/api/v2/subnet_disks_controller_test.rb +9 -7
  66. data/test/functional/foreman_bootdisk/disks_controller_test.rb +27 -25
  67. data/test/models/host/managed_test.rb +17 -13
  68. data/test/test_plugin_helper.rb +11 -7
  69. data/test/unit/access_permissions_test.rb +2 -0
  70. data/test/unit/concerns/compute_resources/vmware_test.rb +67 -63
  71. data/test/unit/concerns/host_test.rb +64 -53
  72. data/test/unit/concerns/orchestration/compute_test.rb +41 -39
  73. data/test/unit/foreman_bootdisk/renderer_test.rb +3 -1
  74. data/test/unit/foreman_bootdisk/scope/bootdisk_test.rb +3 -1
  75. data/test/unit/foreman_bootdisk/scope/full_host_bootdisk_test.rb +30 -0
  76. data/test/unit/iso_generator_test.rb +67 -40
  77. metadata +65 -5
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ForemanBootdisk
2
4
  module Scope
3
5
  class Bootdisk < ::Foreman::Renderer::Scope::Provisioning
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ForemanBootdisk
4
+ module Scope
5
+ class FullHostBootdisk < Bootdisk
6
+ def kernel(medium_provider)
7
+ ForemanBootdisk::ISOGenerator.iso9660_filename(super)
8
+ end
9
+
10
+ def initrd(medium_provider)
11
+ ForemanBootdisk::ISOGenerator.iso9660_filename(super)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ForemanBootdisk
2
4
  module ComputeResources
3
5
  module Vmware
@@ -6,10 +8,10 @@ module ForemanBootdisk
6
8
  end
7
9
 
8
10
  def parse_args(args = {})
9
- args = super
11
+ args = super(args)
10
12
  if args[:provision_method] == 'bootdisk'
11
13
  args[:cdroms] = [new_cdrom]
12
- args[:boot_order] = ['cdrom', 'disk']
14
+ args[:boot_order] = %w[cdrom disk]
13
15
  args[:boot_retry] = 10
14
16
  end
15
17
  args
@@ -1,35 +1,47 @@
1
- require 'uri'
2
-
3
- module ForemanBootdisk::HostExt
4
- def bootdisk_template
5
- ProvisioningTemplate.unscoped.find_by_name(Setting[:bootdisk_host_template]) || raise(::Foreman::Exception.new(N_('Unable to find template specified by %s setting'), 'bootdisk_host_template'))
6
- end
7
-
8
- def bootdisk_template_render
9
- ForemanBootdisk::Renderer.new.render_template(template: bootdisk_template, host: self)
10
- end
11
-
12
- def bootdisk_build?
13
- provision_method == 'bootdisk'
14
- end
1
+ # frozen_string_literal: true
15
2
 
16
- def bootdisk?
17
- managed? && bootdisk_build? && SETTINGS[:unattended]
18
- end
19
-
20
- def bootdisk_downloadable?
21
- architecture.blank? || intel_arch?
22
- end
23
-
24
- def intel_arch?
25
- /i.86|x86[_-]64/ =~ architecture.name
26
- end
3
+ require 'uri'
27
4
 
28
- def validate_media?
29
- super || (managed && bootdisk_build? && build?)
5
+ module ForemanBootdisk
6
+ module HostExt
7
+ def bootdisk_template
8
+ template = ProvisioningTemplate.unscoped.find_by(
9
+ name: Setting[:bootdisk_host_template]
10
+ )
11
+ unless template
12
+ raise ::Foreman::Exception.new(
13
+ N_('Unable to find template specified by %s setting'), 'bootdisk_host_template'
14
+ )
15
+ end
16
+ template
17
+ end
18
+
19
+ def bootdisk_template_render
20
+ ForemanBootdisk::Renderer.new.render_template(template: bootdisk_template, host: self)
21
+ end
22
+
23
+ def bootdisk_build?
24
+ provision_method == 'bootdisk'
25
+ end
26
+
27
+ def bootdisk?
28
+ managed? && bootdisk_build? && SETTINGS[:unattended]
29
+ end
30
+
31
+ def bootdisk_downloadable?
32
+ architecture.blank? || intel_arch?
33
+ end
34
+
35
+ def intel_arch?
36
+ /i.86|x86[_-]64/ =~ architecture.name
37
+ end
38
+
39
+ def can_be_built?
40
+ super || (managed? && SETTINGS[:unattended] && bootdisk_build? && !build?)
41
+ end
30
42
  end
43
+ end
31
44
 
32
- def can_be_built?
33
- super || (managed? and SETTINGS[:unattended] and bootdisk_build? and !build?)
34
- end
45
+ class Host::Managed::Jail < Safemode::Jail
46
+ allow :bootdisk_build?
35
47
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'tmpdir'
2
4
 
3
5
  module ForemanBootdisk
@@ -21,6 +23,7 @@ module ForemanBootdisk
21
23
  def queue_bootdisk_compute
22
24
  return unless compute? && errors.empty? && new_record?
23
25
  return unless provision_method == 'bootdisk'
26
+
24
27
  queue.create(name: _('Generating ISO image for %s') % self, priority: 5,
25
28
  action: [self, :setGenerateIsoImage])
26
29
  queue.create(name: _('Upload ISO image to datastore for %s') % self, priority: 6,
@@ -44,10 +47,10 @@ module ForemanBootdisk
44
47
  end
45
48
 
46
49
  def setGenerateIsoImage
47
- logger.info 'Generating ISO image for %s' % name
50
+ logger.info format('Generating ISO image for %s', name)
48
51
  bootdisk_generate_iso_image
49
- rescue => e
50
- failure _('Failed to generate ISO image for instance %{name}: %{message}') % { name: name, message: e.message }, e
52
+ rescue StandardError => e
53
+ failure format(_('Failed to generate ISO image for instance %{name}: %{message}'), name: name, message: e.message), e
51
54
  end
52
55
 
53
56
  def delGenerateIsoImage; end
@@ -55,29 +58,30 @@ module ForemanBootdisk
55
58
  def setIsoImage
56
59
  logger.info "Uploading ISO image #{bootdisk_isofile} for #{name}"
57
60
  bootdisk_upload_iso
58
- rescue => e
59
- failure _('Failed to upload ISO image for instance %{name}: %{message}') % { name: name, message: e.message }, e
61
+ rescue StandardError => e
62
+ failure format(_('Failed to upload ISO image for instance %{name}: %{message}'), name: name, message: e.message), e
60
63
  end
61
64
 
62
65
  def delIsoImage; end
63
66
 
64
67
  def setAttachIsoImage
65
- logger.info 'Attaching ISO image to CDROM drive for %s' % name
68
+ logger.info format('Attaching ISO image to CDROM drive for %s', name)
66
69
  bootdisk_attach_iso
67
- rescue => e
68
- failure _('Failed to attach ISO image to CDROM drive of instance %{name}: %{message}') % { name: name, message: e.message }, e
70
+ rescue StandardError => e
71
+ failure format(_('Failed to attach ISO image to CDROM drive of instance %{name}: %{message}'), name: name, message: e.message), e
69
72
  end
70
73
 
71
74
  def delAttachIsoImage; end
72
75
 
73
76
  def rebuild_with_bootdisk
74
77
  return true unless bootdisk?
78
+
75
79
  begin
76
80
  bootdisk_generate_iso_image
77
81
  bootdisk_upload_iso
78
82
  bootdisk_attach_iso
79
- rescue => e
80
- Foreman::Logging.exception "Failed to rebuild Bootdisk image for #{name}", e, :level => :error
83
+ rescue StandardError => e
84
+ Foreman::Logging.exception "Failed to rebuild Bootdisk image for #{name}", e, level: :error
81
85
  return false
82
86
  end
83
87
  end
@@ -1,30 +1,28 @@
1
- class Setting::Bootdisk< ::Setting
2
- def self.load_defaults
3
- return unless ApplicationRecord.connection.table_exists?('settings')
4
- return unless super
1
+ # frozen_string_literal: true
5
2
 
6
- ipxe = ['/usr/lib/ipxe'].find { |p| File.exist?(p) } || '/usr/share/ipxe'
7
- isolinux = ['/usr/lib/ISOLINUX'].find { |p| File.exist?(p) } || '/usr/share/syslinux'
8
- syslinux = ['/usr/lib/syslinux/modules/bios', '/usr/lib/syslinux'].find { |p| File.exist?(p) } || '/usr/share/syslinux'
9
- templates = -> { Hash[ProvisioningTemplate.where(:template_kind => TemplateKind.where(:name => 'Bootdisk')).map{|temp| [temp[:name], temp[:name]]}] }
3
+ class Setting
4
+ class Bootdisk < ::Setting
5
+ def self.default_settings
6
+ ipxe = ['/usr/lib/ipxe'].find { |p| File.exist?(p) } || '/usr/share/ipxe'
7
+ isolinux = ['/usr/lib/ISOLINUX'].find { |p| File.exist?(p) } || '/usr/share/syslinux'
8
+ syslinux = ['/usr/lib/syslinux/modules/bios', '/usr/lib/syslinux'].find { |p| File.exist?(p) } || '/usr/share/syslinux'
9
+ templates = -> { Hash[ProvisioningTemplate.where(template_kind: TemplateKind.where(name: 'Bootdisk')).map { |temp| [temp[:name], temp[:name]] }] }
10
10
 
11
- Setting.transaction do
12
11
  [
13
- self.set('bootdisk_ipxe_dir', N_('Path to directory containing iPXE images'), ipxe, N_('iPXE directory')),
14
- self.set('bootdisk_isolinux_dir', N_('Path to directory containing isolinux images'), isolinux, N_('ISOLINUX directory')),
15
- self.set('bootdisk_syslinux_dir', N_('Path to directory containing syslinux images'), syslinux, N_('SYSLINUX directory')),
16
- self.set('bootdisk_host_template', N_('iPXE template to use for host-specific boot disks'), 'Boot disk iPXE - host', N_('Host image template'), nil, :collection => templates),
17
- self.set('bootdisk_generic_host_template', N_('iPXE template to use for generic host boot disks'), 'Boot disk iPXE - generic host', N_('Generic image template'), nil, :collection => templates),
18
- self.set('bootdisk_mkiso_command', N_('Command to generate ISO image, use genisoimage or mkisofs'), 'genisoimage', N_('ISO generation command')),
19
- self.set('bootdisk_cache_media', N_('Installation media files will be cached for full host images'), true, N_('Installation media caching')),
20
- ].compact.each { |s| self.create s.update(:category => "Setting::Bootdisk") }
12
+ set('bootdisk_ipxe_dir', N_('Path to directory containing iPXE images'), ipxe, N_('iPXE directory')),
13
+ set('bootdisk_isolinux_dir', N_('Path to directory containing isolinux images'), isolinux, N_('ISOLINUX directory')),
14
+ set('bootdisk_syslinux_dir', N_('Path to directory containing syslinux images'), syslinux, N_('SYSLINUX directory')),
15
+ set('bootdisk_host_template', N_('iPXE template to use for host-specific boot disks'),
16
+ 'Boot disk iPXE - host', N_('Host image template'), nil, collection: templates),
17
+ set('bootdisk_generic_host_template', N_('iPXE template to use for generic host boot disks'),
18
+ 'Boot disk iPXE - generic host', N_('Generic image template'), nil, collection: templates),
19
+ set('bootdisk_mkiso_command', N_('Command to generate ISO image, use genisoimage or mkisofs'), 'genisoimage', N_('ISO generation command')),
20
+ set('bootdisk_cache_media', N_('Installation media files will be cached for full host images'), true, N_('Installation media caching'))
21
+ ]
21
22
  end
22
23
 
23
- true
24
-
25
- end
26
-
27
- def self.humanized_category
28
- N_('Boot disk')
24
+ def self.humanized_category
25
+ N_('Boot disk')
26
+ end
29
27
  end
30
28
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'net/http'
2
4
  require 'tempfile'
3
5
  require 'tmpdir'
@@ -6,137 +8,175 @@ require 'uri'
6
8
  # Generates an iPXE ISO hybrid image
7
9
  #
8
10
  # requires syslinux, ipxe/ipxe-bootimgs, genisoimage, isohybrid
9
- class ForemanBootdisk::ISOGenerator
10
- def self.generate_full_host(host, opts = {}, &block)
11
- raise ::Foreman::Exception.new(N_('Host is not in build mode, so the template cannot be rendered')) unless host.build?
12
-
13
- tmpl = host.send(:generate_pxe_template, :PXELinux)
14
- unless tmpl
15
- err = host.errors.full_messages.to_sentence
16
- raise ::Foreman::Exception.new(N_('Unable to generate disk template, PXELinux template not found or: %s'), err)
11
+ module ForemanBootdisk
12
+ class ISOGenerator
13
+ def self.generate_full_host(host, opts = {}, &block)
14
+ raise(Foreman::Exception, N_('Host is not in build mode, so the template cannot be rendered')) unless host.build?
15
+
16
+ tmpl = render_pxelinux_template(host)
17
+
18
+ # pxe_files and filename conversion is utterly bizarre
19
+ # aim to convert filenames to something usable under ISO 9660, to match as rendered in the template
20
+ # and then still ensure that the fetch() process stores them under the same name
21
+ files = host.operatingsystem.family.constantize::PXEFILES.keys.each_with_object({}) do |type, hash|
22
+ filename = host.operatingsystem.bootfile(host.medium_provider, type)
23
+ iso_filename = iso9660_filename(filename)
24
+ hash[iso_filename] = host.url_for_boot(type)
25
+ end
26
+
27
+ generate(opts.merge(isolinux: tmpl, files: files), &block)
17
28
  end
18
29
 
19
- # pxe_files and filename conversion is utterly bizarre
20
- # aim to convert filenames to something usable under ISO 9660, update the template to match
21
- # and then still ensure that the fetch() process stores them under the same name
22
- files = host.operatingsystem.pxe_files(host.medium, host.architecture, host)
23
- files.map! do |bootfile_info|
24
- bootfile_info.map do |f|
25
- suffix = f[1].split('/').last
26
- iso_f0 = iso9660_filename(f[0].to_s + '_' + suffix)
27
- tmpl.gsub!(f[0].to_s + '-' + suffix, iso_f0)
28
- ForemanBootdisk.logger.debug("Boot file #{iso_f0}, source #{f[1]}")
29
- [iso_f0, f[1]]
30
+ def self.render_pxelinux_template(host)
31
+ pxelinux_template = host.provisioning_template(kind: :PXELinux)
32
+
33
+ raise(Foreman::Exception, N_('Unable to generate disk template, PXELinux template not found.')) unless pxelinux_template
34
+
35
+ template = ForemanBootdisk::Renderer.new.render_template(
36
+ template: pxelinux_template,
37
+ host: host,
38
+ scope_class: ForemanBootdisk::Scope::FullHostBootdisk
39
+ )
40
+
41
+ unless template
42
+ err = host.errors.full_messages.to_sentence
43
+ raise(::Foreman::Exception.new(N_('Unable to generate disk PXELinux template: %s'), err))
30
44
  end
45
+
46
+ template
31
47
  end
32
48
 
33
- generate(opts.merge(:isolinux => tmpl, :files => files), &block)
34
- end
49
+ def self.generate(opts = {})
50
+ opts[:isolinux] = <<~ISOLINUX if opts[:isolinux].nil? && opts[:ipxe]
51
+ default ipxe
52
+ label ipxe
53
+ kernel /ipxe
54
+ initrd /script
55
+ ISOLINUX
35
56
 
36
- def self.generate(opts = {}, &block)
37
- opts[:isolinux] = <<-EOS if opts[:isolinux].nil? && opts[:ipxe]
38
- default ipxe
39
- label ipxe
40
- kernel /ipxe
41
- initrd /script
42
- EOS
57
+ Dir.mktmpdir('bootdisk') do |wd|
58
+ Dir.mkdir(File.join(wd, 'build'))
43
59
 
44
- Dir.mktmpdir('bootdisk') do |wd|
45
- Dir.mkdir(File.join(wd, 'build'))
60
+ if opts[:isolinux]
61
+ isolinux_source_file = File.join(Setting[:bootdisk_isolinux_dir], 'isolinux.bin')
62
+ raise(Foreman::Exception, N_('Please ensure the isolinux/syslinux package(s) are installed.')) unless File.exist?(isolinux_source_file)
46
63
 
47
- if opts[:isolinux]
48
- unless File.exists?(File.join(Setting[:bootdisk_isolinux_dir], 'isolinux.bin'))
49
- raise ::Foreman::Exception.new(N_("Please ensure the isolinux/syslinux package(s) are installed."))
50
- end
51
- FileUtils.cp(File.join(Setting[:bootdisk_isolinux_dir], 'isolinux.bin'), File.join(wd, 'build', 'isolinux.bin'))
52
- if File.exist?(File.join(Setting[:bootdisk_syslinux_dir], 'ldlinux.c32'))
53
- FileUtils.cp(File.join(Setting[:bootdisk_syslinux_dir], 'ldlinux.c32'), File.join(wd, 'build', 'ldlinux.c32'))
54
- end
55
- File.open(File.join(wd, 'build', 'isolinux.cfg'), 'w') do |file|
56
- file.write(opts[:isolinux])
64
+ FileUtils.cp(isolinux_source_file, File.join(wd, 'build', 'isolinux.bin'))
65
+
66
+ source_files = ['ldlinux.c32', 'menu.c32']
67
+ source_files.each do |source_file|
68
+ full_path = File.join(Setting[:bootdisk_syslinux_dir], source_file)
69
+ FileUtils.cp(full_path, File.join(wd, 'build', source_file)) if File.exist?(full_path)
70
+ end
71
+
72
+ File.open(File.join(wd, 'build', 'isolinux.cfg'), 'w') do |file|
73
+ file.write(opts[:isolinux])
74
+ end
57
75
  end
58
- end
59
76
 
60
- if opts[:ipxe]
61
- unless File.exists?(File.join(Setting[:bootdisk_ipxe_dir], 'ipxe.lkrn'))
62
- raise ::Foreman::Exception.new(N_("Please ensure the ipxe-bootimgs package is installed."))
77
+ if opts[:ipxe]
78
+ ipxe_source_file = File.join(Setting[:bootdisk_ipxe_dir], 'ipxe.lkrn')
79
+ raise(Foreman::Exception, N_('Please ensure the ipxe-bootimgs package is installed.')) unless File.exist?(ipxe_source_file)
80
+
81
+ FileUtils.cp(ipxe_source_file, File.join(wd, 'build', 'ipxe'))
82
+ File.open(File.join(wd, 'build', 'script'), 'w') { |file| file.write(opts[:ipxe]) }
63
83
  end
64
- FileUtils.cp(File.join(Setting[:bootdisk_ipxe_dir], 'ipxe.lkrn'), File.join(wd, 'build', 'ipxe'))
65
- File.open(File.join(wd, 'build', 'script'), 'w') { |file| file.write(opts[:ipxe]) }
66
- end
67
84
 
68
- if opts[:files]
69
- opts[:files].each do |bootfile_info|
70
- for file, source in bootfile_info do
71
- fetch(File.join(wd, 'build', file), source)
85
+ if opts[:files]
86
+ if opts[:files].respond_to?(:each)
87
+ opts[:files].each do |file, source|
88
+ fetch(File.join(wd, 'build', file), source)
89
+ end
72
90
  end
73
- end if opts[:files].respond_to? :each
74
- end
91
+ end
75
92
 
76
- iso = if opts[:dir]
77
- Tempfile.new(['bootdisk', '.iso'], opts[:dir]).path
78
- else
79
- File.join(wd, 'output.iso')
80
- end
81
- unless system("#{Setting[:bootdisk_mkiso_command]} -o #{iso} -iso-level 2 -b isolinux.bin -c boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table #{File.join(wd, 'build')}")
82
- raise ::Foreman::Exception.new(N_("ISO build failed"))
83
- end
93
+ iso = if opts[:dir]
94
+ Tempfile.new(['bootdisk', '.iso'], opts[:dir]).path
95
+ else
96
+ File.join(wd, 'output.iso')
97
+ end
98
+ raise(Foreman::Exception, N_('ISO build failed')) unless system(build_mkiso_command(output_file: iso, source_directory: File.join(wd, 'build')))
99
+
100
+ # Make the ISO bootable as a HDD/USB disk too
101
+ raise(Foreman::Exception, N_('ISO hybrid conversion failed')) unless system('isohybrid', iso)
84
102
 
85
- # Make the ISO bootable as a HDD/USB disk too
86
- unless system("isohybrid", iso)
87
- raise ::Foreman::Exception.new(N_("ISO hybrid conversion failed"))
103
+ yield iso
88
104
  end
105
+ end
89
106
 
90
- yield iso
107
+ def self.build_mkiso_command(output_file:, source_directory:)
108
+ arguments = [
109
+ "-o #{output_file}",
110
+ '-iso-level 2',
111
+ '-b isolinux.bin',
112
+ '-c boot.cat',
113
+ '-no-emul-boot',
114
+ '-boot-load-size 4',
115
+ '-boot-info-table'
116
+ ]
117
+ [Setting[:bootdisk_mkiso_command], arguments, source_directory].flatten.join(' ')
91
118
  end
92
- end
93
119
 
94
- def self.token_expiry(host)
95
- expiry = host.token.try(:expires)
96
- return '' if Setting[:token_duration] == 0 || expiry.blank?
97
- '_' + expiry.strftime('%Y%m%d_%H%M')
98
- end
120
+ def self.token_expiry(host)
121
+ expiry = host.token.try(:expires)
122
+ return '' if Setting[:token_duration].zero? || expiry.blank?
123
+
124
+ '_' + expiry.strftime('%Y%m%d_%H%M')
125
+ end
99
126
 
100
- private
101
-
102
- def self.fetch(path, uri)
103
- dir = File.dirname(path)
104
- FileUtils.mkdir_p(dir) unless File.exist?(dir)
105
-
106
- use_cache = !!Setting[:bootdisk_cache_media]
107
- write_cache = false
108
- File.open(path, 'w') do |file|
109
- file.binmode
110
-
111
- if use_cache && !(contents = Rails.cache.fetch(uri, :raw => true)).nil?
112
- ForemanBootdisk.logger.info("Retrieved #{uri} from local cache (use foreman-rake tmp:cache:clear to empty)")
113
- file.write(contents)
114
- else
115
- ForemanBootdisk.logger.info("Fetching #{uri}")
116
- write_cache = use_cache
117
- uri = URI(uri)
118
- Net::HTTP.start(uri.host, uri.port) do |http|
119
- request = Net::HTTP::Get.new uri.request_uri
120
-
121
- http.request request do |response|
122
- response.read_body do |chunk|
123
- file.write chunk
127
+ def self.fetch(path, uri, limit = 10)
128
+ dir = File.dirname(path)
129
+ FileUtils.mkdir_p(dir) unless File.exist?(dir)
130
+
131
+ use_cache = !!Setting[:bootdisk_cache_media]
132
+ write_cache = false
133
+ File.open(path, 'w') do |file|
134
+ file.binmode
135
+
136
+ if use_cache && !(contents = Rails.cache.fetch(uri, raw: true)).nil?
137
+ ForemanBootdisk.logger.info("Retrieved #{uri} from local cache (use foreman-rake tmp:cache:clear to empty)")
138
+ file.write(contents)
139
+ else
140
+ ForemanBootdisk.logger.info("Fetching #{uri}")
141
+ write_cache = use_cache
142
+ uri = URI(uri)
143
+ Net::HTTP.start(uri.host, uri.port) do |http|
144
+ request = Net::HTTP::Get.new(uri.request_uri, 'Accept-Encoding' => 'plain')
145
+
146
+ http.request(request) do |response|
147
+ case response
148
+ when Net::HTTPSuccess then
149
+ response.read_body do |chunk|
150
+ file.write chunk
151
+ end
152
+ when Net::HTTPRedirection then
153
+ raise("Too many HTTP redirects when downloading #{uri}") if limit <= 0
154
+
155
+ fetch(path, response['location'], limit - 1)
156
+ # prevent multiple writes to the cache
157
+ write_cache = false
158
+ else
159
+ raise ::Foreman::Exception, N_(format("Unable to download boot file %{uri}, HTTP return code %{code}", uri: uri, code: response.code))
160
+ end
124
161
  end
125
162
  end
126
163
  end
127
164
  end
128
- end
129
165
 
130
- if write_cache
166
+ return unless write_cache
167
+
168
+ contents = File.read(path)
169
+ return if contents.empty?
170
+
131
171
  ForemanBootdisk.logger.debug("Caching contents of #{uri}")
132
- Rails.cache.write(uri, File.read(path), :raw => true)
172
+ Rails.cache.write(uri, contents, raw: true)
133
173
  end
134
- end
135
174
 
136
- # isolinux supports up to ISO 9660 level 2 filenames
137
- def self.iso9660_filename(name)
138
- dir = File.dirname(name)
139
- file = File.basename(name).upcase.tr_s('^A-Z0-9_', '_').last(28)
140
- dir == '.' ? file : File.join(dir.upcase.tr_s('^A-Z0-9_', '_').last(28), file)
175
+ # isolinux supports up to ISO 9660 level 2 filenames
176
+ def self.iso9660_filename(name)
177
+ dir = File.dirname(name)
178
+ file = File.basename(name).upcase.tr_s('^A-Z0-9_', '_').last(28)
179
+ dir == '.' ? file : File.join(dir.upcase.tr_s('^A-Z0-9_', '_').last(28), file)
180
+ end
141
181
  end
142
182
  end