in core/actionProxy/actionproxy.py [0:0]
def run(self, args, env):
def error(msg):
# fall through (exception and else case are handled the same way)
sys.stdout.write('%s\n' % msg)
return (502, {'error': 'The action did not return a dictionary or array.'})
try:
input = json.dumps(args)
if len(input) > 131071: # MAX_ARG_STRLEN (131071) linux/binfmts.h
# pass argument via stdin
p = subprocess.Popen(
[self.binary],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=env)
else:
# pass argument via stdin and command parameter
p = subprocess.Popen(
[self.binary, input],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=env)
# run the process and wait until it completes.
# stdout/stderr will always be set because we passed PIPEs to Popen
(o, e) = p.communicate(input=input.encode())
except Exception as e:
return error(e)
# stdout/stderr may be either text or bytes, depending on Python
# version, so if bytes, decode to text. Note that in Python 2
# a string will match both types; so also skip decoding in that case
if isinstance(o, bytes) and not isinstance(o, str):
o = o.decode('utf-8')
if isinstance(e, bytes) and not isinstance(e, str):
e = e.decode('utf-8')
# get the last line of stdout, even if empty
lastNewLine = o.rfind('\n', 0, len(o)-1)
if lastNewLine != -1:
# this is the result string to JSON parse
lastLine = o[lastNewLine+1:].strip()
# emit the rest as logs to stdout (including last new line)
sys.stdout.write(o[:lastNewLine+1])
else:
# either o is empty or it is the result string
lastLine = o.strip()
if e:
sys.stderr.write(e)
try:
json_output = json.loads(lastLine)
if isinstance(json_output, dict) or isinstance(json_output, list):
return (200, json_output)
else:
return error(lastLine)
except Exception:
return error(lastLine)