diff --git a/Dockerfile b/Dockerfile index 542c3098a6..05e92dae85 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,6 +9,8 @@ RUN dnf -y install https://yum.osc.edu/ondemand/latest/ondemand-release-web-late # install all the dependencies RUN dnf -y update && \ + dnf install -y dnf-utils && \ + dnf config-manager --set-enabled powertools && \ dnf -y module enable nodejs:12 ruby:2.7 && \ dnf install -y \ file \ @@ -18,6 +20,7 @@ RUN dnf -y update && \ gcc-c++ \ git \ patch \ + lua-posix \ ondemand-gems \ ondemand-runtime \ ondemand-build \ diff --git a/Dockerfile.dev b/Dockerfile.dev index 0aeb5c0606..f1a231b878 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -5,8 +5,9 @@ ARG UID=1000 ARG GID=1000 RUN dnf reinstall -y httpd-tools && \ + dnf install -y epel-release && \ dnf install -y \ - strace && \ + strace lua && \ dnf clean all && rm -rf /var/cache/dnf/* RUN groupadd -g $GID $USER && \ diff --git a/mod_ood_proxy/lib/ood/nginx_stage.lua b/mod_ood_proxy/lib/ood/nginx_stage.lua index 3a2ba82d89..c8da3aa7b9 100644 --- a/mod_ood_proxy/lib/ood/nginx_stage.lua +++ b/mod_ood_proxy/lib/ood/nginx_stage.lua @@ -13,9 +13,9 @@ function pun(r, bin, user, app_init_url, exports, pre_hook_root_cmd) end if pre_hook_root_cmd then - local stdin = parse_exports(r, exports) + local env_table = exports_to_table(r, exports) cmd = cmd .. " -P '" .. r:escape(pre_hook_root_cmd) .. "'" - err = capture2e_with_stdin(cmd, stdin) + err = fork_and_exec(cmd, env_table) else err = capture2e(cmd) end @@ -90,50 +90,71 @@ function capture2e(cmd) end --[[ - capture2e_with_stdin + fork_and_exec - Give a command and some standard in, get a string for merged stdout and stderr + fork this process, modify the environment of the child and execute the + command. This returns a string that is the stdout & stderr combined. --]] -function capture2e_with_stdin(cmd, stdin) - local output_file = os.tmpname() - local redir_cmd = cmd .. " > " .. output_file .. " 2>&1" +function fork_and_exec(cmd, env_table) + local posix = require 'posix' - local stdin_handle = io.popen(redir_cmd, "w") - stdin_handle:write(stdin) - output = stdin_handle:close() + local read_pipe, write_pipe = posix.pipe() + local childpid, errmsg = posix.fork() - local output_handle = io.open(output_file, "r") - output = output_handle:read("*all") - output_handle:close() + if childpid == nil then + return "failed to fork " .. cmd .. " with error message: '" .. errmsg .. "'" - os.remove(output_file) + -- child pid + elseif childpid == 0 then + posix.close(read_pipe) - return output + for key,value in pairs(env_table) do + posix.setenv("OOD_" .. key, value) -- sudo rules allow for OOD_* env vars + end + + local output = capture2e(cmd) + posix.write(write_pipe, output) + posix.close(write_pipe) + os.exit(0) + + -- child pid + else + posix.close(write_pipe) + + posix.wait(childpid) + + -- FIXME: probably a better way than to read byte by byte + local output = "" + local b = posix.read(read_pipe, 1) + while #b == 1 do + output = output .. b + b = posix.read(read_pipe, 1) + end + + posix.close(read_pipe) + return output + end end --[[ - parse_exports - + export_table Given exports to be a comma seperated list of environment variable names: split that string, extract the variable values from the request's - environment and return a string of key=value pairs seperated by newlines - like "KEY=VALUE\nNEXT=THEOTHER\n". + environment and return a table of the environment variable key:value pairs --]] -function parse_exports(r, exports) - if exports then - environment = "" - - for key in string.gmatch(exports, '([^,]+)') do - value = r.subprocess_env[key] - if value then - environment = environment .. key .. "=" .. value .. "\n" - end - end +function exports_to_table(r, exports) + local export_table = {} - return environment - else - return "" + if exports then + for key in string.gmatch(exports, '([^,]+)') do + value = r.subprocess_env[key] + if value then + export_table[key] = value + end + end end + + return export_table end return { diff --git a/nginx_stage/lib/nginx_stage/generators/pun_config_generator.rb b/nginx_stage/lib/nginx_stage/generators/pun_config_generator.rb index 617d641435..3813c0e302 100644 --- a/nginx_stage/lib/nginx_stage/generators/pun_config_generator.rb +++ b/nginx_stage/lib/nginx_stage/generators/pun_config_generator.rb @@ -115,21 +115,12 @@ class PunConfigGenerator < Generator add_hook :exec_pre_hook do unless pre_hook_root_cmd.nil? args = ["--user", user.to_s] - env = {} log = Syslog::Logger.new 'ood_nginx_stage' - unless STDIN.tty? - STDIN.each_line do |line| - key_values = line.split('=') - env[key_values[0]] = key_values[1].to_s.chomp if key_values.size == 2 - end - end - begin - _, err, s = Open3.capture3(env, pre_hook_root_cmd, *args) + _, err, s = Open3.capture3(pre_hook_root_cmd, *args) log.error "#{pre_hook_root_cmd} exited with #{s.exitstatus} for user #{user}. stderr was '#{err}'" unless s.success? rescue StandardError => e - log = Syslog::Logger.new 'ood_nginx_stage' log.error "#{pre_hook_root_cmd} threw exception '#{e.message}' for #{user}" end end diff --git a/packaging/ondemand.spec b/packaging/ondemand.spec index c5040e64f9..d98b008a42 100644 --- a/packaging/ondemand.spec +++ b/packaging/ondemand.spec @@ -62,7 +62,7 @@ BuildRequires: ondemand-nodejs >= %{runtime_version}, ondemand-nodejs < %{next BuildRequires: rsync BuildRequires: git Requires: git -Requires: sudo, lsof, cronie, wget, curl, make, rsync, file, libxml2, libxslt, zlib +Requires: sudo, lsof, cronie, wget, curl, make, rsync, file, libxml2, libxslt, zlib, lua-posix Requires: ondemand-apache >= %{runtime_version}, ondemand-apache < %{next_major_version}, ondemand-apache < %{next_minor_version} Requires: ondemand-nginx = 1.18.0 Requires: ondemand-passenger = 6.0.7