foreman_bootdisk 14.0.0 → 17.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/AUTHORS +30 -0
- data/README.md +25 -0
- data/app/controllers/foreman_bootdisk/api/v2/disks_controller.rb +5 -7
- data/app/controllers/foreman_bootdisk/api/v2/subnet_disks_controller.rb +9 -4
- data/app/controllers/foreman_bootdisk/disks_controller.rb +11 -10
- data/app/helpers/concerns/foreman_bootdisk/hosts_helper_ext.rb +14 -14
- data/app/lib/foreman_bootdisk/scope/bootdisk.rb +4 -1
- data/app/lib/foreman_bootdisk/scope/full_host_bootdisk_efi.rb +15 -0
- data/app/models/concerns/foreman_bootdisk/compute_resources/vmware.rb +10 -1
- data/app/models/concerns/foreman_bootdisk/host_ext.rb +7 -10
- data/app/models/concerns/foreman_bootdisk/orchestration/compute.rb +28 -19
- data/app/models/setting/bootdisk.rb +16 -19
- data/app/services/foreman_bootdisk/iso_generator.rb +129 -52
- data/app/services/foreman_bootdisk/renderer.rb +36 -18
- data/app/views/foreman_bootdisk/generic_efi_host.erb +64 -0
- data/app/views/foreman_bootdisk/generic_static_host.erb +34 -0
- data/app/views/foreman_bootdisk/host.erb +27 -11
- data/db/seeds.d/50-bootdisk_templates.rb +15 -31
- data/lib/foreman_bootdisk/engine.rb +6 -6
- data/lib/foreman_bootdisk/version.rb +1 -1
- data/lib/tasks/bootdisk.rake +10 -6
- data/locale/action_names.rb +5 -0
- data/locale/ca/LC_MESSAGES/foreman_bootdisk.mo +0 -0
- data/locale/ca/foreman_bootdisk.po +65 -16
- data/locale/de/LC_MESSAGES/foreman_bootdisk.mo +0 -0
- data/locale/de/foreman_bootdisk.po +74 -23
- data/locale/en/LC_MESSAGES/foreman_bootdisk.mo +0 -0
- data/locale/en/foreman_bootdisk.po +58 -10
- data/locale/en_GB/LC_MESSAGES/foreman_bootdisk.mo +0 -0
- data/locale/en_GB/foreman_bootdisk.po +65 -17
- data/locale/es/LC_MESSAGES/foreman_bootdisk.mo +0 -0
- data/locale/es/foreman_bootdisk.po +82 -34
- data/locale/foreman_bootdisk.pot +124 -48
- data/locale/fr/LC_MESSAGES/foreman_bootdisk.mo +0 -0
- data/locale/fr/foreman_bootdisk.po +65 -17
- data/locale/it/LC_MESSAGES/foreman_bootdisk.mo +0 -0
- data/locale/it/foreman_bootdisk.po +63 -15
- data/locale/ja/LC_MESSAGES/foreman_bootdisk.mo +0 -0
- data/locale/ja/foreman_bootdisk.po +64 -16
- data/locale/ko/LC_MESSAGES/foreman_bootdisk.mo +0 -0
- data/locale/ko/foreman_bootdisk.po +63 -15
- data/locale/pt_BR/LC_MESSAGES/foreman_bootdisk.mo +0 -0
- data/locale/pt_BR/foreman_bootdisk.po +76 -27
- data/locale/ru/LC_MESSAGES/foreman_bootdisk.mo +0 -0
- data/locale/ru/foreman_bootdisk.po +63 -15
- data/locale/sv_SE/LC_MESSAGES/foreman_bootdisk.mo +0 -0
- data/locale/sv_SE/foreman_bootdisk.po +61 -13
- data/locale/zh_CN/LC_MESSAGES/foreman_bootdisk.mo +0 -0
- data/locale/zh_CN/foreman_bootdisk.po +79 -31
- data/locale/zh_TW/LC_MESSAGES/foreman_bootdisk.mo +0 -0
- data/locale/zh_TW/foreman_bootdisk.po +63 -15
- data/release-gem +84 -0
- data/test/functional/foreman_bootdisk/api/v2/disks_controller_test.rb +51 -17
- data/test/functional/foreman_bootdisk/api/v2/subnet_disks_controller_test.rb +23 -10
- data/test/functional/foreman_bootdisk/disks_controller_test.rb +65 -25
- data/test/test_plugin_helper.rb +23 -3
- data/test/unit/concerns/host_test.rb +12 -1
- data/test/unit/concerns/orchestration/compute_test.rb +32 -13
- data/test/unit/foreman_bootdisk/renderer_test.rb +1 -1
- data/test/unit/iso_generator_test.rb +16 -7
- metadata +65 -4
@@ -2,30 +2,27 @@
|
|
2
2
|
|
3
3
|
class Setting
|
4
4
|
class Bootdisk < ::Setting
|
5
|
-
def self.
|
6
|
-
return unless ApplicationRecord.connection.table_exists?('settings')
|
7
|
-
return unless super
|
8
|
-
|
5
|
+
def self.default_settings
|
9
6
|
ipxe = ['/usr/lib/ipxe'].find { |p| File.exist?(p) } || '/usr/share/ipxe'
|
10
7
|
isolinux = ['/usr/lib/ISOLINUX'].find { |p| File.exist?(p) } || '/usr/share/syslinux'
|
11
8
|
syslinux = ['/usr/lib/syslinux/modules/bios', '/usr/lib/syslinux'].find { |p| File.exist?(p) } || '/usr/share/syslinux'
|
9
|
+
grub2 = ['/var/lib/tftpboot/grub2'].find { |p| File.exist?(p) } || '/var/lib/foreman/bootdisk'
|
12
10
|
templates = -> { Hash[ProvisioningTemplate.where(template_kind: TemplateKind.where(name: 'Bootdisk')).map { |temp| [temp[:name], temp[:name]] }] }
|
13
11
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
true
|
12
|
+
[
|
13
|
+
set('bootdisk_ipxe_dir', N_('Path to directory containing iPXE images'), ipxe, N_('iPXE directory')),
|
14
|
+
set('bootdisk_isolinux_dir', N_('Path to directory containing isolinux images'), isolinux, N_('ISOLINUX directory')),
|
15
|
+
set('bootdisk_syslinux_dir', N_('Path to directory containing syslinux images'), syslinux, N_('SYSLINUX directory')),
|
16
|
+
set('bootdisk_grub2_dir', N_('Path to directory containing grubx64.efi and shimx64.efi'), grub2, N_('Grub2 directory')),
|
17
|
+
set('bootdisk_host_template', N_('iPXE template to use for host-specific boot disks'),
|
18
|
+
'Boot disk iPXE - host', N_('Host image template'), nil, collection: templates),
|
19
|
+
set('bootdisk_generic_host_template', N_('iPXE template to use for generic host boot disks'),
|
20
|
+
'Boot disk iPXE - generic host', N_('Generic image template'), nil, collection: templates),
|
21
|
+
set('bootdisk_generic_efi_host_template', N_('Grub2 template to use for generic EFI host boot disks'),
|
22
|
+
'Boot disk Grub2 EFI - generic host', N_('Generic Grub2 EFI image template'), nil, collection: templates),
|
23
|
+
set('bootdisk_mkiso_command', N_('Command to generate ISO image, use genisoimage or mkisofs'), 'genisoimage', N_('ISO generation command')),
|
24
|
+
set('bootdisk_cache_media', N_('Installation media files will be cached for full host images'), true, N_('Installation media caching'))
|
25
|
+
]
|
29
26
|
end
|
30
27
|
|
31
28
|
def self.humanized_category
|
@@ -11,9 +11,10 @@ require 'uri'
|
|
11
11
|
module ForemanBootdisk
|
12
12
|
class ISOGenerator
|
13
13
|
def self.generate_full_host(host, opts = {}, &block)
|
14
|
-
raise Foreman::Exception
|
14
|
+
raise Foreman::Exception.new(N_('Host is not in build mode, so the template cannot be rendered')) unless host.build?
|
15
15
|
|
16
|
-
|
16
|
+
isolinux_template = render_template(host, :PXELinux, ForemanBootdisk::Scope::FullHostBootdisk)
|
17
|
+
grub_template = render_template(host, :PXEGrub2, ForemanBootdisk::Scope::FullHostBootdiskEfi)
|
17
18
|
|
18
19
|
# pxe_files and filename conversion is utterly bizarre
|
19
20
|
# aim to convert filenames to something usable under ISO 9660, to match as rendered in the template
|
@@ -24,84 +25,145 @@ module ForemanBootdisk
|
|
24
25
|
hash[iso_filename] = host.url_for_boot(type)
|
25
26
|
end
|
26
27
|
|
27
|
-
generate(opts.merge(isolinux:
|
28
|
+
generate(opts.merge(isolinux: isolinux_template, grub: grub_template, files: files), &block)
|
29
|
+
rescue ::Foreman::Exception => e
|
30
|
+
if e.code == 'ERF42-0067'
|
31
|
+
ForemanBootdisk.logger.warn e
|
32
|
+
else
|
33
|
+
raise e
|
34
|
+
end
|
28
35
|
end
|
29
36
|
|
30
|
-
def self.
|
31
|
-
|
37
|
+
def self.render_template(host, kind, scope_class)
|
38
|
+
template = host.provisioning_template(kind: kind)
|
32
39
|
|
33
|
-
raise Foreman::Exception
|
40
|
+
raise Foreman::Exception.new(N_('Unable to generate disk template, %{kind} template not found.'), kind: kind) unless template
|
34
41
|
|
35
42
|
template = ForemanBootdisk::Renderer.new.render_template(
|
36
|
-
template:
|
43
|
+
template: template,
|
37
44
|
host: host,
|
38
|
-
scope_class:
|
45
|
+
scope_class: scope_class
|
39
46
|
)
|
40
47
|
|
41
48
|
unless template
|
42
49
|
err = host.errors.full_messages.to_sentence
|
43
|
-
raise
|
50
|
+
raise Foreman::Exception.new(N_('Unable to generate disk %{kind} template: %{error}'), kind: kind, error: err)
|
44
51
|
end
|
45
52
|
|
46
53
|
template
|
47
54
|
end
|
48
55
|
|
56
|
+
def self.system_or_exception(command, error)
|
57
|
+
unless system(command)
|
58
|
+
ForemanBootdisk.logger.debug "Bootdisk command failed: #{command}"
|
59
|
+
raise Foreman::Exception.new(N_(error))
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
49
63
|
def self.generate(opts = {})
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
64
|
+
# isolinux template not provided for generic BIOS bootdisks
|
65
|
+
if opts[:isolinux].nil? && opts[:ipxe]
|
66
|
+
opts[:isolinux] = <<~EOT
|
67
|
+
default ipxe
|
68
|
+
label ipxe
|
69
|
+
kernel /ipxe
|
70
|
+
initrd /script
|
71
|
+
EOT
|
72
|
+
end
|
56
73
|
|
57
|
-
|
58
|
-
|
74
|
+
if opts[:grub].nil? && opts[:ipxe]
|
75
|
+
opts[:grub] = <<~EOT
|
76
|
+
echo "Grub2 template not associated and/or unsupported bootdisk type."
|
77
|
+
echo "The following bootdisks are supported for EFI systems:"
|
78
|
+
echo " * FULL HOST BOOTDISK"
|
79
|
+
echo " * SUBNET GENERIC BOOTDISK"
|
80
|
+
echo "The system will poweroff in few minutes..."
|
81
|
+
sleep 500
|
82
|
+
poweroff
|
83
|
+
EOT
|
84
|
+
end
|
59
85
|
|
60
|
-
|
61
|
-
|
62
|
-
|
86
|
+
# Temporary directory cannot be cleaned inprocess due to send_file offloaded to web server
|
87
|
+
wd = Dir.mktmpdir('bootdisk-iso-')
|
88
|
+
Dir.mkdir(File.join(wd, 'build'))
|
63
89
|
|
64
|
-
|
90
|
+
if opts[:isolinux]
|
91
|
+
isolinux_source_file = File.join(Setting[:bootdisk_isolinux_dir], 'isolinux.bin')
|
92
|
+
raise Foreman::Exception.new(N_('Please ensure the isolinux/syslinux package(s) are installed.')) unless File.exist?(isolinux_source_file)
|
65
93
|
|
66
|
-
|
67
|
-
FileUtils.cp(ldlinux_source_file, File.join(wd, 'build', 'ldlinux.c32')) if File.exist?(ldlinux_source_file)
|
94
|
+
FileUtils.cp(isolinux_source_file, File.join(wd, 'build', 'isolinux.bin'))
|
68
95
|
|
69
|
-
|
70
|
-
|
71
|
-
|
96
|
+
source_files = ['ldlinux.c32', 'menu.c32', 'libutil.c32']
|
97
|
+
source_files.each do |source_file|
|
98
|
+
full_path = File.join(Setting[:bootdisk_syslinux_dir], source_file)
|
99
|
+
FileUtils.cp(full_path, File.join(wd, 'build', source_file)) if File.exist?(full_path)
|
100
|
+
end
|
101
|
+
|
102
|
+
File.open(File.join(wd, 'build', 'isolinux.cfg'), 'w') do |file|
|
103
|
+
file.write(opts[:isolinux])
|
72
104
|
end
|
105
|
+
end
|
106
|
+
|
107
|
+
if opts[:ipxe]
|
108
|
+
ipxe_source_file = File.join(Setting[:bootdisk_ipxe_dir], 'ipxe.lkrn')
|
109
|
+
raise Foreman::Exception.new(N_('Please ensure the ipxe-bootimgs package is installed.')) unless File.exist?(ipxe_source_file)
|
73
110
|
|
74
|
-
|
75
|
-
|
76
|
-
|
111
|
+
FileUtils.cp(ipxe_source_file, File.join(wd, 'build', 'ipxe'))
|
112
|
+
File.open(File.join(wd, 'build', 'script'), 'w') { |file| file.write(opts[:ipxe]) }
|
113
|
+
end
|
77
114
|
|
78
|
-
|
79
|
-
|
115
|
+
if opts[:grub]
|
116
|
+
FileUtils.mkdir_p(File.join(wd, 'build', 'EFI', 'BOOT'))
|
117
|
+
# a copy when using CDROM directly
|
118
|
+
File.open(File.join(wd, 'build', 'EFI', 'BOOT', 'grub.cfg'), 'w') { |file| file.write(opts[:grub]) }
|
119
|
+
# a copy when using USB/HDD (copied into EFI image as well)
|
120
|
+
File.open(File.join(wd, 'build', 'grub-hdd.cfg'), 'w') do |f|
|
121
|
+
# set root to (cd0) or similar when booting via disk
|
122
|
+
f.write("search --file /ISOLINUX.BIN --set root\n")
|
123
|
+
f.write(opts[:grub])
|
124
|
+
end
|
125
|
+
efibootimg = File.join(wd, 'build', 'efiboot.img')
|
126
|
+
system_or_exception("truncate -s 4M #{efibootimg}", N_('Creating new image failed, install truncate utility'))
|
127
|
+
system_or_exception("mkfs.msdos #{efibootimg}", N_('Failed to format the ESP image via mkfs.msdos'))
|
128
|
+
system_or_exception("mmd -i #{efibootimg} '::/EFI'", N_('Failed to create a directory within the ESP image'))
|
129
|
+
system_or_exception("mmd -i #{efibootimg} '::/EFI/BOOT'", N_('Failed to create a directory within the ESP image'))
|
130
|
+
{
|
131
|
+
File.join(wd, 'build', 'grub-hdd.cfg').to_s => 'GRUB.CFG',
|
132
|
+
File.join(Setting[:bootdisk_grub2_dir], 'grubx64.efi').to_s => 'GRUBX64.EFI',
|
133
|
+
File.join(Setting[:bootdisk_grub2_dir], 'shimx64.efi').to_s => 'BOOTX64.EFI',
|
134
|
+
}.each do |src, dest|
|
135
|
+
raise(Foreman::Exception.new(N_('Ensure %{path} contains grubx64.efi and shimx64.efi: install TFTP module or copy those files into /var/lib/foreman/bootdisk (Grub2 directory setting)'), path: src)) unless File.exist?(src)
|
136
|
+
raise(Foreman::Exception.new(N_('Unable to mcopy %{path}'), path: src)) unless system("mcopy -m -i #{efibootimg} '#{src}' '#{"::/EFI/BOOT/#{dest}"}'")
|
80
137
|
end
|
138
|
+
mkiso_args = "-eltorito-alt-boot -e efiboot.img -no-emul-boot"
|
139
|
+
isohybrod_args = ["--uefi"]
|
140
|
+
else
|
141
|
+
mkiso_args = ''
|
142
|
+
isohybrod_args = []
|
143
|
+
end
|
81
144
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
end
|
145
|
+
if opts[:files]
|
146
|
+
if opts[:files].respond_to?(:each)
|
147
|
+
opts[:files].each do |file, source|
|
148
|
+
fetch(File.join(wd, 'build', file), source)
|
87
149
|
end
|
88
150
|
end
|
151
|
+
end
|
89
152
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
153
|
+
iso = if opts[:dir]
|
154
|
+
Tempfile.new(['bootdisk', '.iso'], opts[:dir]).path
|
155
|
+
else
|
156
|
+
File.join(wd, 'output.iso')
|
157
|
+
end
|
158
|
+
raise Foreman::Exception.new(N_('ISO build failed')) unless system(build_mkiso_command(output_file: iso, extra_commands: mkiso_args, source_directory: File.join(wd, 'build')))
|
96
159
|
|
97
|
-
|
98
|
-
|
160
|
+
# Make the ISO bootable as a HDD/USB disk too
|
161
|
+
raise Foreman::Exception.new(N_('ISO hybrid conversion failed: %s'), $?) unless system(*["isohybrid", isohybrod_args, iso].flatten.compact)
|
99
162
|
|
100
|
-
|
101
|
-
end
|
163
|
+
yield iso
|
102
164
|
end
|
103
165
|
|
104
|
-
def self.build_mkiso_command(output_file:, source_directory:)
|
166
|
+
def self.build_mkiso_command(output_file:, source_directory:, extra_commands:)
|
105
167
|
arguments = [
|
106
168
|
"-o #{output_file}",
|
107
169
|
'-iso-level 2',
|
@@ -111,6 +173,7 @@ module ForemanBootdisk
|
|
111
173
|
'-boot-load-size 4',
|
112
174
|
'-boot-info-table'
|
113
175
|
]
|
176
|
+
arguments.push(extra_commands) unless extra_commands.nil?
|
114
177
|
[Setting[:bootdisk_mkiso_command], arguments, source_directory].flatten.join(' ')
|
115
178
|
end
|
116
179
|
|
@@ -121,7 +184,7 @@ module ForemanBootdisk
|
|
121
184
|
'_' + expiry.strftime('%Y%m%d_%H%M')
|
122
185
|
end
|
123
186
|
|
124
|
-
def self.fetch(path, uri)
|
187
|
+
def self.fetch(path, uri, limit = 10)
|
125
188
|
dir = File.dirname(path)
|
126
189
|
FileUtils.mkdir_p(dir) unless File.exist?(dir)
|
127
190
|
|
@@ -138,11 +201,22 @@ module ForemanBootdisk
|
|
138
201
|
write_cache = use_cache
|
139
202
|
uri = URI(uri)
|
140
203
|
Net::HTTP.start(uri.host, uri.port) do |http|
|
141
|
-
request = Net::HTTP::Get.new(uri.request_uri)
|
204
|
+
request = Net::HTTP::Get.new(uri.request_uri, 'Accept-Encoding' => 'plain')
|
142
205
|
|
143
206
|
http.request(request) do |response|
|
144
|
-
response
|
145
|
-
|
207
|
+
case response
|
208
|
+
when Net::HTTPSuccess then
|
209
|
+
response.read_body do |chunk|
|
210
|
+
file.write chunk
|
211
|
+
end
|
212
|
+
when Net::HTTPRedirection then
|
213
|
+
raise("Too many HTTP redirects when downloading #{uri}") if limit <= 0
|
214
|
+
|
215
|
+
fetch(path, response['location'], limit - 1)
|
216
|
+
# prevent multiple writes to the cache
|
217
|
+
write_cache = false
|
218
|
+
else
|
219
|
+
raise ::Foreman::Exception, N_(format("Unable to download boot file %{uri}, HTTP return code %{code}", uri: uri, code: response.code))
|
146
220
|
end
|
147
221
|
end
|
148
222
|
end
|
@@ -151,8 +225,11 @@ module ForemanBootdisk
|
|
151
225
|
|
152
226
|
return unless write_cache
|
153
227
|
|
228
|
+
contents = File.read(path)
|
229
|
+
return if contents.empty?
|
230
|
+
|
154
231
|
ForemanBootdisk.logger.debug("Caching contents of #{uri}")
|
155
|
-
Rails.cache.write(uri,
|
232
|
+
Rails.cache.write(uri, contents, raw: true)
|
156
233
|
end
|
157
234
|
|
158
235
|
# isolinux supports up to ISO 9660 level 2 filenames
|
@@ -4,35 +4,46 @@ require 'uri'
|
|
4
4
|
|
5
5
|
module ForemanBootdisk
|
6
6
|
class Renderer
|
7
|
-
def
|
8
|
-
host = if subnet.present?
|
9
|
-
# rendering a subnet-level bootdisk requires tricking the renderer into thinking it has a
|
10
|
-
# valid host, without a token, but with a tftp proxy
|
11
|
-
Struct.new(:token, :provision_interface).new(
|
12
|
-
nil,
|
13
|
-
Struct.new(:subnet).new(subnet)
|
14
|
-
)
|
15
|
-
else
|
16
|
-
Struct.new(:token, :subnet).new(nil, nil)
|
17
|
-
end
|
18
|
-
|
19
|
-
render_template(template: generic_host_template, host: host)
|
20
|
-
end
|
21
|
-
|
22
|
-
def render_template(template:, host:, scope_class: renderer_scope)
|
7
|
+
def render_template(template:, host:, scope_class: renderer_scope, subnet: nil)
|
23
8
|
source = Foreman::Renderer.get_source(
|
24
9
|
template: template,
|
25
|
-
host: host
|
26
10
|
)
|
27
11
|
scope = Foreman::Renderer.get_scope(
|
28
12
|
host: host,
|
29
|
-
|
13
|
+
variables: { subnet: subnet, bootdisk: true },
|
14
|
+
klass: scope_class,
|
30
15
|
)
|
31
16
|
Foreman::Renderer.render(source, scope)
|
32
17
|
end
|
33
18
|
|
19
|
+
def generic_template_render(subnet = nil)
|
20
|
+
render_template(template: generic_host_template, host: stub_host(subnet), subnet: subnet)
|
21
|
+
end
|
22
|
+
|
23
|
+
def generic_efi_template_render(subnet)
|
24
|
+
if subnet.httpboot?
|
25
|
+
render_template(template: generic_efi_host_template, host: stub_host(subnet), subnet: subnet)
|
26
|
+
else
|
27
|
+
ForemanBootdisk.logger.warn('HTTPBOOT feature is not enabled for subnet %s, UEFI may not be available for bootdisk' % subnet.name)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
34
31
|
private
|
35
32
|
|
33
|
+
def stub_host(subnet)
|
34
|
+
if subnet.present?
|
35
|
+
# rendering a subnet-level bootdisk requires tricking the renderer into thinking it has a
|
36
|
+
# valid host, without a token, but with a tftp proxy
|
37
|
+
Struct.new(:token, :provision_interface, :content_source).new(
|
38
|
+
nil,
|
39
|
+
Struct.new(:subnet).new(subnet),
|
40
|
+
nil
|
41
|
+
)
|
42
|
+
else
|
43
|
+
Struct.new(:token, :subnet, :content_source).new(nil, nil, nil)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
36
47
|
def renderer_scope
|
37
48
|
ForemanBootdisk::Scope::Bootdisk
|
38
49
|
end
|
@@ -43,5 +54,12 @@ module ForemanBootdisk
|
|
43
54
|
|
44
55
|
template
|
45
56
|
end
|
57
|
+
|
58
|
+
def generic_efi_host_template
|
59
|
+
template = ProvisioningTemplate.unscoped.find_by(name: Setting[:bootdisk_generic_efi_host_template])
|
60
|
+
raise ::Foreman::Exception.new(N_('Unable to find template specified by %s setting'), 'bootdisk_generic_efi_host_template') unless template
|
61
|
+
|
62
|
+
template
|
63
|
+
end
|
46
64
|
end
|
47
65
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
#
|
2
|
+
# Boot disk Grub2 EFI - generic host
|
3
|
+
#
|
4
|
+
#set debug="http,efinet,net"
|
5
|
+
#set debug=all
|
6
|
+
echo "Foreman Bootdisk: 'Boot disk Grub2 EFI - generic host' template"
|
7
|
+
echo
|
8
|
+
echo "********************************************************"
|
9
|
+
echo " REQUIREMENTS:"
|
10
|
+
echo " * SUBNET GENERIC IMAGE ONLY (host image not supported)"
|
11
|
+
echo " * HOST PARAM default_grub_install_entry set to efi_http"
|
12
|
+
echo " * PROXY WITH HTTPBOOT FEATURE"
|
13
|
+
echo " * HTTP UEFI BOOT ONLY (Legacy/PXE not supported)"
|
14
|
+
echo " * IPv4 ONLY (IPv6 not tested, change the template)"
|
15
|
+
echo " * HTTP ONLY (change the template for HTTPS)"
|
16
|
+
echo " * ISC DHCP (other servers not tested)"
|
17
|
+
echo " * GRUB FROM RHEL 8.3+/7.9+ (when generating the image)"
|
18
|
+
echo " * EFI HTTP or HTTPS grub entry must be selected in menu"
|
19
|
+
echo " * DNS must resolve proxy hostname via DNS proxy if set"
|
20
|
+
echo "*******************************************************"
|
21
|
+
sleep 5
|
22
|
+
<%
|
23
|
+
# possible values are: "http" or "https"
|
24
|
+
proxy_proto = "http"
|
25
|
+
|
26
|
+
@subnet || bootdisk_raise("Generic disk not supported for EFI, use subnet disk")
|
27
|
+
@subnet.template? || bootdisk_raise("Requires a proxy with template feature")
|
28
|
+
proxy_port = if proxy_proto == "http"
|
29
|
+
@subnet.httpboot.httpboot_http_port
|
30
|
+
else
|
31
|
+
@subnet.httpboot.httpboot_https_port
|
32
|
+
end
|
33
|
+
# Workaround for "no DNS server configured" https://bugzilla.redhat.com/show_bug.cgi?id=1842509
|
34
|
+
proxy_httpboot_host = dns_lookup(@subnet.httpboot.hostname)
|
35
|
+
proxy_template_host = dns_lookup(@subnet.template.hostname)
|
36
|
+
-%>
|
37
|
+
echo
|
38
|
+
net_ls_cards
|
39
|
+
echo "Configuring ALL cards via BOOTP/IPv4"
|
40
|
+
net_bootp
|
41
|
+
# uncomment here for IPv6 support (not tested)
|
42
|
+
#echo "Configuring ALL cards via BOOTP/IPv6"
|
43
|
+
#net_ipv6_autoconf
|
44
|
+
net_ls_addr
|
45
|
+
net_ls_routes
|
46
|
+
net_ls_dns
|
47
|
+
sleep 5
|
48
|
+
set root=(<%= proxy_proto %>,<%= proxy_httpboot_host %>:<%= proxy_port %>)
|
49
|
+
# The variable will not survive configfile fetch, therefore absolute path
|
50
|
+
# must be used in the chainloaded template.
|
51
|
+
# https://bugzilla.redhat.com/show_bug.cgi?id=1842893
|
52
|
+
set http_path=/httpboot/
|
53
|
+
set default=efi_<%= proxy_proto %>
|
54
|
+
<% (0..32).each do |i| -%>
|
55
|
+
echo "Trying efinet<%= i %> via <%= proxy_proto %>://<%= proxy_template_host %>:<%= proxy_port %>/unattended/PXEGrub2?mac=$net_efinet<%= i %>_dhcp_mac"
|
56
|
+
set net_default_mac=$net_efinet<%= i %>_dhcp_mac
|
57
|
+
sleep 5
|
58
|
+
configfile (<%= proxy_proto %>,<%= proxy_template_host %>:<%= proxy_port %>)/unattended/PXEGrub2?mac=$net_efinet<%= i %>_dhcp_mac
|
59
|
+
<% end -%>
|
60
|
+
|
61
|
+
echo "Could not find a host with PXEGrub2 template and one of the MAC addresses!"
|
62
|
+
echo "The system will poweroff in few minutes..."
|
63
|
+
sleep 500
|
64
|
+
poweroff
|
@@ -0,0 +1,34 @@
|
|
1
|
+
#!ipxe
|
2
|
+
#
|
3
|
+
# Generic host template with interactive static IP configuration. Tokens
|
4
|
+
# must be disabled in order to access templates via MAC addresses.
|
5
|
+
#
|
6
|
+
|
7
|
+
<% (0..32).each do |i| -%>
|
8
|
+
:net<%= i %>
|
9
|
+
isset ${net<%= i -%>/mac} || goto configure
|
10
|
+
echo Found ${net<%= i -%>/mac} as net<%= i -%> on a ${net<%= i -%>/chip}
|
11
|
+
goto net<%= i+1 %>
|
12
|
+
<% end -%>
|
13
|
+
|
14
|
+
:configure
|
15
|
+
echo -n Interface (e.g. net0): && read interface
|
16
|
+
iseq ${interface} n && goto reboot ||
|
17
|
+
iseq ${interface} N && goto reboot ||
|
18
|
+
|
19
|
+
ifopen ${interface}
|
20
|
+
echo Please enter IPv4 details for ${interface}
|
21
|
+
echo
|
22
|
+
|
23
|
+
echo -n IP address: && read ${interface}/ip
|
24
|
+
echo -n Subnet mask: && read ${interface}/netmask
|
25
|
+
echo -n Default gateway: && read ${interface}/gateway
|
26
|
+
echo -n DNS server: && read dns
|
27
|
+
|
28
|
+
chain <%= bootdisk_chain_url %>${${interface}/mac} || goto reboot
|
29
|
+
exit 0
|
30
|
+
|
31
|
+
:reboot
|
32
|
+
echo Unable to continue, rebooting...
|
33
|
+
sleep 30
|
34
|
+
exit 1
|