Не удается запустить двоичный файл из лямбда-функции python aws

Я пытаюсь запустить этот инструмент в лямбда-функции: https://github.com/nicolas-f/7DTD-leaflet

Инструмент зависит от Pillow, которая зависит от библиотек изображений, недоступных в лямбда-контейнере AWS. Чтобы попытаться обойти это, я запустил pyinstaller, чтобы создать двоичный файл, который я надеюсь выполнить. Этот файл называется map_reader и находится на верхнем уровне 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

Как я могу это правильно запустить?


person stevepkr84    schedule 14.01.2017    source источник
comment
Я предполагаю, что среда, в которой вы работаете, не позволяет вам сделать локальные файлы исполняемыми. Отказано в разрешении может означать именно то, что написано.   -  person Blckknght    schedule 14.01.2017


Ответы (6)


Возможно, вас ввели в заблуждение, в чем на самом деле проблема.

Не думаю, что первый Popen прошел успешно. Я думаю, что он просто сбросил сообщение стандартной ошибки, а вы его не видите. Наверное, это говорит о том, что

chmod: map_reader: No such file or directory

Я предлагаю вам попробовать любой из этих 2:

  1. Извлеките map_reader из пакета в / tmp. Затем укажите на него /tmp/map_reader.
  2. Сделайте это в соответствии с рекомендациями Тима Вагнера, генерального директора AWS Lambda, который сказал следующее в статье Запуск произвольных исполняемых файлов в AWS Lambda:

Включение собственных исполняемых файлов очень просто; просто упакуйте их в загружаемый вами ZIP-файл, а затем укажите на них ссылку (включая относительный путь в созданном ZIP-файле), когда вы вызываете их из Node.js или из других процессов, которые вы ранее запустили. Убедитесь, что вы включили следующее в начало кода функции:

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

Приведенный выше код предназначен для Node JS, но для Python он выглядит следующим образом

import os os.environ['PATH']

Это должно заставить команду command = './map_reader <arguments> работать.

Если они по-прежнему не работают, вы также можете рассмотреть возможность запуска chmod 755 map_reader перед созданием пакета и его загрузкой (как предлагается в этот другой вопрос).

person Jeshan    schedule 16.01.2017
comment
Пометка как правильная, хотя для меня это не было полным решением. Я отправлю еще один ответ по другой проблеме. Важнейшим моментом здесь было перемещение двоичного файла в / tmp, чтобы я мог с ним действовать. - person stevepkr84; 16.01.2017
comment
Я забыл упомянуть, что вы скомпилировали для Amazon Linux. Я предполагал, что вы позаботились об этом. Я рада, что ты это понял. - person Jeshan; 16.01.2017
comment
разве добавление LAMBDA_TASK_ROOT к вашему пути не сработало для вас? - person Jeshan; 16.01.2017
comment
К сожалению, нет, я все еще получал ошибку Permission Denied. - person stevepkr84; 23.01.2017

Я знаю, что немного опоздал с этим, но если вам нужен более общий способ сделать это (например, если у вас много двоичных файлов и вы можете не использовать их все), вот как я это делаю, предоставил вам поместите все свои двоичные файлы в папку bin рядом с файлом py и все библиотеки в папку 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)
person zoubida13    schedule 01.03.2017

Здесь было две проблемы. Во-первых, согласно ответу Джешана, мне пришлось переместить двоичный файл в / tmp, прежде чем я смогу правильно получить к нему доступ.

Другая проблема заключалась в том, что я запустил pyinstaller на ubuntu, создав один файл. Я видел в другом месте некоторые комментарии об обязательной компиляции на той же архитектуре, что и лямбда-контейнер. Поэтому я запустил pyinstaller на ec2 на основе AMI Amazon Linux. На выходе было несколько файлов .os, которые при перемещении в tmp работали, как ожидалось.

person stevepkr84    schedule 16.01.2017

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

Перемещение двоичного файла в /tmp и его выполнение сработало для меня

person Carlos Rendon    schedule 22.01.2017

Нет необходимости копировать файлы /tmp. Вы можете просто использовать ld-linux для выполнения любого файла, в том числе не отмечен исполняемый файл.

Итак, для запуска неисполняемого файла на AWS Lambda вы используете следующую команду:

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

P.S. Было бы разумнее добавить двоичный файл map_reader или любые другие статические файлы в слой лямбда, таким образом, папку /opt.

person supersan    schedule 18.10.2019

Как и в документации, упомянутой для Node.js, вам необходимо обновить $PATH, иначе вы получите command not found при попытке запустить исполняемые файлы, которые вы добавили в корень вашего пакета Lambda. В Node.js это:

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

Теперь то же самое в Python:

import os

# Make the path stored in $LAMBDA_TASK_ROOT available to $PATH, so that we
# can run the executables we added at the root of our package.
os.environ["PATH"] += os.pathsep + os.environ['LAMBDA_TASK_ROOT']

Протестировано нормально с Python 3.8.

(В качестве бонуса вот еще несколько переменных окружения, используемых Lambda.)

person Fabien Snauwaert    schedule 17.08.2020