Skip to content

Commit 3a4bdf8

Browse files
author
Bastian Schmidt
committed
Enable boot image download for iso images
* Implement fetch and extract boot image * Apply correct file permissions * Introduce and add tests for fetch_boot_image * Implement class for file extraction
1 parent 9268440 commit 3a4bdf8

File tree

7 files changed

+75
-5
lines changed

7 files changed

+75
-5
lines changed

lib/proxy/archive_extract.rb

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
module Proxy
2+
class ArchiveExtract < Proxy::Util::CommandTask
3+
include Util
4+
5+
def initialize(image_path, file_in_image, dst_path)
6+
7+
args = [which('isoinfo')]
8+
9+
# read the file
10+
args << "-R"
11+
# set image path
12+
args += ["-i", image_path.to_s]
13+
# set file path within the image
14+
args += ["-x", file_in_image.to_s]
15+
16+
super(args, input=nil, output=dst_path)
17+
end
18+
19+
def start
20+
lock = Proxy::FileLock.try_locking(File.join(File.dirname(@output), ".#{File.basename(@output)}.lock"))
21+
if lock.nil?
22+
false
23+
else
24+
super do
25+
Proxy::FileLock.unlock(lock)
26+
File.unlink(lock)
27+
end
28+
end
29+
end
30+
end
31+
end

lib/proxy/util.rb

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ class CommandTask
1313
# stderr is redirected to proxy error log, stdout to proxy debug log
1414
# command can be either string or array (command + arguments)
1515
# input is passed into STDIN and must be string
16-
def initialize(command, input = nil)
16+
def initialize(command, input = nil, output = nil)
1717
@command = command
1818
@input = input
19+
@output = output
1920
end
2021

2122
def start(&ensured_block)
@@ -27,8 +28,13 @@ def start(&ensured_block)
2728
logger.info "[#{thr.pid}] Started task #{cmdline_string}"
2829
stdin.write(input) if input
2930
stdin.close
30-
stdout.each do |line|
31-
logger.debug "[#{thr.pid}] #{line}"
31+
unless @output.nil?
32+
File.binwrite(@output, stdout.read)
33+
stdout.close
34+
else
35+
stdout.each do |line|
36+
logger.debug "[#{thr.pid}] #{line}"
37+
end
3238
end
3339
stderr.each do |line|
3440
logger.warn "[#{thr.pid}] #{line}"

lib/smart_proxy_main.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
require 'proxy/dependency_injection'
1515
require 'proxy/util'
1616
require 'proxy/http_download'
17+
require 'proxy/archive_extract'
1718
require 'proxy/helpers'
1819
require 'proxy/memory_store'
1920
require 'proxy/plugin_validators'

modules/tftp/server.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,27 @@ def pxeconfig_file(mac)
150150
end
151151
end
152152

153+
def self.fetch_boot_image(image_dst, url, files)
154+
155+
# Verify dst is a valid directory
156+
image_path = Pathname.new(image_dst).cleanpath
157+
extr_image_dir = Pathname.new(image_dst.delete_suffix(".iso"))
158+
159+
FileUtils.mkdir_p image_path.parent
160+
choose_protocol_and_fetch(url, image_path).join
161+
162+
files.each do |file|
163+
file_path = Pathname.new file
164+
extr_file_path = Pathname.new(File.join(extr_image_dir, file_path)).cleanpath
165+
166+
# Create destination directory
167+
FileUtils.mkdir_p extr_file_path.parent
168+
# extract iso
169+
extract_task = ::Proxy::ArchiveExtract.new(image_path, file_path, extr_file_path).start
170+
raise "TFTP image file extraction error: #{file_path}" unless extract_task.join == 0
171+
end
172+
end
173+
153174
def self.fetch_boot_file(dst, src)
154175
filename = boot_filename(dst, src)
155176
destination = Pathname.new(File.expand_path(filename, Proxy::TFTP::Plugin.settings.tftproot)).cleanpath

modules/tftp/tftp_api.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ def create_default(variant)
3434
end
3535
end
3636

37+
post "/fetch_boot_image" do
38+
log_halt(400, "TFTP: Failed to fetch boot file: ") { Proxy::TFTP.fetch_boot_image(params[:path], params[:url], params[:files]) }
39+
end
40+
3741
post "/fetch_boot_file" do
3842
log_halt(400, "TFTP: Failed to fetch boot file: ") { Proxy::TFTP.fetch_boot_file(params[:prefix], params[:path]) }
3943
end

test/tftp/tftp_api_test.rb

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,13 @@ def test_api_can_fetch_boot_file
111111
assert last_response.ok?
112112
end
113113

114-
def test_api_can_get_servername
114+
def test_api_can_fetch_boot_image
115+
Proxy::TFTP.expects(:fetch_boot_image).with('some/image.iso', 'http://localhost/file.iso').returns(true)
116+
post "/fetch_boot_image", :path => 'some/image.iso', :url => 'http://localhost/file.iso'
117+
assert last_response.ok?
118+
end
119+
120+
def test_api_can_get_servername
115121
Proxy::TFTP::Plugin.settings.stubs(:tftp_servername).returns("servername")
116122
result = get "/serverName"
117123
assert_match /servername/, result.body

test/tftp/tftp_test.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
class TftpTest < Test::Unit::TestCase
66
def setup
77
@tftp = Proxy::TFTP::Server.new
8-
Proxy::TFTP::Plugin.load_test_settings(:tftproot => "/some/root")
8+
Proxy::TFTP::Plugin.load_test_settings(:tftproot => "/some/root",
9+
:tftp_image_path => "/another/root")
910
end
1011

1112
def test_should_have_a_logger

0 commit comments

Comments
 (0)