diff --git a/lib/proxy/archive_extract.rb b/lib/proxy/archive_extract.rb new file mode 100644 index 000000000..baae09735 --- /dev/null +++ b/lib/proxy/archive_extract.rb @@ -0,0 +1,21 @@ +module Proxy + class ArchiveExtract < Proxy::Util::CommandTask + include Util + + def initialize(src, dst, skip_existing = true) + + args = [which('7z')] + + # extract command + args << "x" + # source file + args << src.to_s + # skip existing files + args << "-aos" if skip_existing + # destination directory + args << "-o#{dst}" + + super(args) + end + end +end diff --git a/lib/proxy/filesystem_permission.rb b/lib/proxy/filesystem_permission.rb new file mode 100644 index 000000000..b45e4f5a2 --- /dev/null +++ b/lib/proxy/filesystem_permission.rb @@ -0,0 +1,19 @@ +module Proxy + class FilesystemPermission < Proxy::Util::CommandTask + include Util + + def initialize(dst, permission, include_subfolders = false) + + args = [which('chmod')] + + # include subfolders + args << "-R" if include_subfolders + # new permission (format: rwxrwxrwx [owner,group,others], for example 755) + args << permission.to_s + # destination directory/file + args << dst.to_s + + super(args) + end + end +end diff --git a/lib/smart_proxy_main.rb b/lib/smart_proxy_main.rb index 0ebc22b2c..577265f5c 100644 --- a/lib/smart_proxy_main.rb +++ b/lib/smart_proxy_main.rb @@ -14,6 +14,8 @@ require 'proxy/dependency_injection' require 'proxy/util' require 'proxy/http_download' +require 'proxy/archive_extract' +require 'proxy/filesystem_permission' require 'proxy/helpers' require 'proxy/memory_store' require 'proxy/plugin_validators' diff --git a/modules/tftp/server.rb b/modules/tftp/server.rb index eba4e5e4a..18ef6dc94 100644 --- a/modules/tftp/server.rb +++ b/modules/tftp/server.rb @@ -150,6 +150,22 @@ def pxeconfig_file(mac) end end + def self.fetch_boot_image(dst, src) + + # Verify dst is a valid directory + dst_file = Pathname.new(dst).cleanpath + dst_path = Pathname.new(dst.delete_suffix(".iso")) + + FileUtils.mkdir_p dst_path.parent + choose_protocol_and_fetch(src, dst_file).join + # extract iso + extract_task = ::Proxy::ArchiveExtract.new(dst_file, dst_path).start + raise "TFTP image extraction error" unless extract_task.join == 0 + # adapt extracted file permission + permission_task = ::Proxy::FilesystemPermission.new(dst_path, "755", true).start + raise "TFTP image extracted file permission error" unless permission_task.join == 0 + end + def self.fetch_boot_file(dst, src) filename = boot_filename(dst, src) destination = Pathname.new(File.expand_path(filename, Proxy::TFTP::Plugin.settings.tftproot)).cleanpath diff --git a/modules/tftp/tftp_api.rb b/modules/tftp/tftp_api.rb index 1bc6276c7..6ad0bd44c 100644 --- a/modules/tftp/tftp_api.rb +++ b/modules/tftp/tftp_api.rb @@ -34,6 +34,10 @@ def create_default(variant) end end + post "/fetch_boot_image" do + log_halt(400, "TFTP: Failed to fetch boot file: ") { Proxy::TFTP.fetch_boot_image(params[:path], params[:url]) } + end + post "/fetch_boot_file" do log_halt(400, "TFTP: Failed to fetch boot file: ") { Proxy::TFTP.fetch_boot_file(params[:prefix], params[:path]) } end diff --git a/test/tftp/tftp_api_test.rb b/test/tftp/tftp_api_test.rb index 3ffcfb0cb..9e9270ada 100644 --- a/test/tftp/tftp_api_test.rb +++ b/test/tftp/tftp_api_test.rb @@ -111,7 +111,13 @@ def test_api_can_fetch_boot_file assert last_response.ok? end - def test_api_can_get_servername + def test_api_can_fetch_boot_image + Proxy::TFTP.expects(:fetch_boot_image).with('some/image.iso', 'http://localhost/file.iso').returns(true) + post "/fetch_boot_image", :path => 'some/image.iso', :url => 'http://localhost/file.iso' + assert last_response.ok? + end + + def test_api_can_get_servername Proxy::TFTP::Plugin.settings.stubs(:tftp_servername).returns("servername") result = get "/serverName" assert_match /servername/, result.body diff --git a/test/tftp/tftp_test.rb b/test/tftp/tftp_test.rb index 11dc6e204..874eb68e8 100644 --- a/test/tftp/tftp_test.rb +++ b/test/tftp/tftp_test.rb @@ -5,7 +5,8 @@ class TftpTest < Test::Unit::TestCase def setup @tftp = Proxy::TFTP::Server.new - Proxy::TFTP::Plugin.load_test_settings(:tftproot => "/some/root") + Proxy::TFTP::Plugin.load_test_settings(:tftproot => "/some/root", + :tftp_image_path => "/another/root") end def test_should_have_a_logger