无法从python aws lambda函数中运行二进制文件

时间:2017-01-14 14:37:26

标签: python python-2.7 amazon-web-services aws-lambda pyinstaller

我正在尝试在lambda函数中运行此工具:https://github.com/nicolas-f/7DTD-leaflet

该工具依赖于Pillow,它依赖于AWS​​ lambda容器中不可用的映像库。为了试图绕过这个我运行pyinstaller来创建一个我希望可以执行的二进制文件。此文件名为map_reader,位于lambda zip包的顶层。

以下是我用来尝试运行该工具的代码:

command = 'chmod 755 map_reader'
args = shlex.split(command)
print subprocess.Popen(args)

command = './map_reader -g "{}" -t "{}"'.format('/tmp/mapFiles', '/tmp/tiles')
args = shlex.split(command)
print subprocess.Popen(args)

这是错误,发生在第二次subprocess.Popen电话:

<subprocess.Popen object at 0x7f08fa100d10>
[Errno 13] Permission denied: OSError

如何正确运行?

6 个答案:

答案 0 :(得分:5)

你可能被误导了问题实际上是什么。

我不认为第一个Popen成功跑了。我认为它只是在标准错误中抛出了一条消息,而你却没有看到它。它可能会说那个

<form action="" method="get">
    {{ filter.form.as_p }}
    <input type="submit" />
</form>

我建议您可以尝试以下两种方法之一:

  1. 将包中的map_reader提取到/ tmp中。然后使用chmod: map_reader: No such file or directory
  2. 引用它
  3. 按照AWS Lambda总经理Tim Wagner的建议执行此操作,他在文章Running Arbitrary Executables in AWS Lambda中说了以下内容:
  4.   

    包含您自己的可执行文件很容易;只需将它们打包到您上传的ZIP文件中,然后在从Node.js或之前启动的其他进程中调用它们时引用它们(包括您创建的ZIP文件中的相对路径)。确保在功能代码的开头包含以下内容

    /tmp/map_reader

    以上代码适用于Node JS,但对于Python,它类似于以下

    process.env[‘PATH’] = process.env[‘PATH’] + ‘:’ + process.env[‘LAMBDA_TASK_ROOT’]

    这应该使命令import os os.environ['PATH']起作用。

    如果他们仍然无法工作,您也可以考虑在创建包并上传之前运行command = './map_reader <arguments> (按照建议in this other question)。

答案 1 :(得分:4)

我知道我有点迟到但是如果你想要一个更通用的方法(例如,如果你有很多二进制文件并且可能不会全部使用它们),我就这样做,<如果您将所有二进制文件放在py文件旁边的bin文件夹中,以及lib文件夹中的所有库:

import shutil
import time
import os
import subprocess

LAMBDA_TASK_ROOT = os.environ.get('LAMBDA_TASK_ROOT', os.path.dirname(os.path.abspath(__file__)))
CURR_BIN_DIR = os.path.join(LAMBDA_TASK_ROOT, 'bin')
LIB_DIR = os.path.join(LAMBDA_TASK_ROOT, 'lib')
### In order to get permissions right, we have to copy them to /tmp
BIN_DIR = '/tmp/bin'

# This is necessary as we don't have permissions in /var/tasks/bin where the lambda function is running
def _init_bin(executable_name):
    start = time.clock()
    if not os.path.exists(BIN_DIR):
        print("Creating bin folder")
        os.makedirs(BIN_DIR)
    print("Copying binaries for "+executable_name+" in /tmp/bin")
    currfile = os.path.join(CURR_BIN_DIR, executable_name)
    newfile  = os.path.join(BIN_DIR, executable_name)
    shutil.copy2(currfile, newfile)
    print("Giving new binaries permissions for lambda")
    os.chmod(newfile, 0775)
    elapsed = (time.clock() - start)
    print(executable_name+" ready in "+str(elapsed)+'s.')

# then if you're going to call a binary in a cmd, for instance pdftotext :

_init_bin('pdftotext')
cmdline = [os.path.join(BIN_DIR, 'pdftotext'), '-nopgbrk', '/tmp/test.pdf']
subprocess.check_call(cmdline, shell=False, stderr=subprocess.STDOUT)

答案 2 :(得分:2)

这里有两个问题。首先,根据Jeshan的回答,我必须先将二进制文件移动到/ tmp才能正确访问它。

另一个问题是我在ubuntu上运行了pyinstaller,创建了一个文件。我在其他地方看到了一些关于确保在与lambda容器运行相同的架构上进行编译的注释。因此,我基于Amazon Linux AMI在ec2上运行了pyinstaller。输出是多个.os文件,当移动到tmp时,按预期工作。

答案 3 :(得分:1)

copyfile('/var/task/yourbinary', '/tmp/yourbinary')
os.chmod('/tmp/yourbinary', 0555)

将二进制文件移动到/tmp并使其可执行为我工作

答案 4 :(得分:0)

无需复制文件/tmp。您可以只使用ld-linux执行任何文件,包括那些未标记为可执行文件的文件。

因此,要在AWS Lambda上运行不可执行程序,请使用以下命令:

/lib64/ld-linux-x86-64.so.2 /opt/map_reader

P.S。在Lambda层中添加map_reader二进制文件或任何其他静态文件,从而在/opt文件夹中,将更有意义。

答案 5 :(得分:0)

Like the docs mention for Node.js,您需要更新SELECT customerID, SUM(sales_volume), SUM(returned_volume), (SUM(returned_volume) / SUM(sales_volume)) AS return_rate FROM (SELECT s.*, ROW_NUMBER() OVER (PARTITION BY customerID ORDER BY order_date DESC) as seqnum FROM sales s ) s WHERE seqnum <= 3 GROUP BY 1; ,否则在尝试运行在Lambda软件包根目录中添加的可执行文件时会得到$PATH。在Node.js中,就是:

command not found

现在,在Python中是同一件事:

process.env['PATH'] = process.env['PATH'] + ':' + process.env['LAMBDA_TASK_ROOT']

在Python 3.8上测试正常。

(作为奖励,这里还有更多env variables used by Lambda。)