Skip to content

Commit

Permalink
use lua-posix to fork and set the environment in the pun_pre_hook
Browse files Browse the repository at this point in the history
  • Loading branch information
johrstrom committed May 4, 2021
1 parent 1aa0622 commit 59b07b2
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 44 deletions.
3 changes: 3 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand All @@ -18,6 +20,7 @@ RUN dnf -y update && \
gcc-c++ \
git \
patch \
lua-posix \
ondemand-gems \
ondemand-runtime \
ondemand-build \
Expand Down
3 changes: 2 additions & 1 deletion Dockerfile.dev
Original file line number Diff line number Diff line change
Expand Up @@ -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 && \
Expand Down
85 changes: 53 additions & 32 deletions mod_ood_proxy/lib/ood/nginx_stage.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down
11 changes: 1 addition & 10 deletions nginx_stage/lib/nginx_stage/generators/pun_config_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion packaging/ondemand.spec
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 59b07b2

Please sign in to comment.