Lev Lev - 2 months ago 22
Python Question

AWS Lambda subprocess OSError: [Errno 2] No such file or directory

I'm trying to create a lambda function that makes collection of thumbnails from a video on amazon s3 using ffmpeg. ffmpeg binary is included into fuction package.

function code:

# -*- coding: utf-8 -*-

import stat
import shutil
import boto3
import logging
import subprocess as sp
import os
import threading

thumbnail_prefix = 'thumb_'
thumbnail_ext = '.jpg'
time_delta = 1
video_frames_path = 'media/videos/frames'

print('Loading function')
logger = logging.getLogger()
logger.setLevel(logging.INFO)

lambda_tmp_dir = '/tmp' # Lambda fuction can use this directory.

# ffmpeg is stored with this script.
# When executing ffmpeg, execute permission is requierd.
# But Lambda source directory do not have permission to change it.
# So move ffmpeg binary to `/tmp` and add permission.
ffmpeg_bin = "{0}/ffmpeg.linux64".format(lambda_tmp_dir)
shutil.copyfile('/var/task/ffmpeg.linux64', ffmpeg_bin)

os.chmod(ffmpeg_bin, 777)

# tried also:
# os.chmod(ffmpeg_bin, os.stat(ffmpeg_bin).st_mode | stat.S_IEXEC)

s3 = boto3.client('s3')


def get_thumb_filename(num):
return '{prefix}{num:03d}{ext}'.format(prefix=thumbnail_prefix, num=num, ext=thumbnail_ext)


def create_thumbnails(video_url):
i = 1
filenames_list = []
filename = None
while i == 1 or os.path.isfile(os.path.join(os.getcwd(), get_thumb_filename(i-1))):
if filename:
filenames_list.append(filename)
time = time_delta * (i - 1)
filename = get_thumb_filename(i)
print(ffmpeg_bin)
if os.path.isfile(ffmpeg_bin):
print('ok')
sp.call(['sudo',
ffmpeg_bin,
'-ss',
str(time),
'-i',
video_url,
'-frames:v',
'1',
get_thumb_filename(i)])
i += 1
print(filenames_list)
return filenames_list


def s3_upload_file(file_path, key, bucket, acl, content_type):
file = open(file_path, 'r')
s3.put_object(
Bucket=bucket,
ACL=acl,
Body=file,
Key=key,
ContentType=content_type
)
logger.info("file {0} moved to {1}/{2}".format(file_path, bucket, key))


def s3_upload_files_in_threads(filenames_list, dir_path, bucket, s3path, acl, content_type):
for filename in filenames_list:
if os.path.isfile(os.path.join(dir_path, filename)):
print(os.path.join(dir_path, filename))
t = threading.Thread(target=s3_upload_file,
args=(os.path.join(dir_path, filename),
'{0}/{1}'.format(s3path, filename),
bucket,
acl,
content_type)).start()


def lambda_handler(event, context):
bucket = event['Records'][0]['s3']['bucket']['name']
video_key = event['Records'][0]['s3']['object']['key']
video_name = video_key.split('/')[-1].split('.')[0]
video_url = 'http://{0}/{1}'.format(bucket, video_key)
filenames_list = create_thumbnails(video_url)
s3_upload_files_in_threads(filenames_list,
os.getcwd(),
bucket,
'{0}/{1}'.format(video_frames_path, video_name),
'public-read',
'image/jpeg')
return


during the execution I get following logs:

Loading function

/tmp/ffmpeg.linux64

ok

[Errno 2] No such file or directory: OSError
Traceback (most recent call last):
File "/var/task/lambda_function.py", line 112, in lambda_handler
filenames_list = create_thumbnails(video_url)
File "/var/task/lambda_function.py", line 77, in create_thumbnails
get_thumb_filename(i)])
File "/usr/lib64/python2.7/subprocess.py", line 522, in call
return Popen(*popenargs, **kwargs).wait()
File "/usr/lib64/python2.7/subprocess.py", line 710, in __init__
errread, errwrite)
File "/usr/lib64/python2.7/subprocess.py", line 1335, in _execute_child
raise child_exception
OSError: [Errno 2] No such file or directory


When I use the same sp.call() with the same ffmpeg binary on my ec2 instance it works fine.

Answer

The problem is not because of ffmpeg. The error is for sudo not found. Lambda instances do not come with sudo. Why do you need sudo? Can you print whatever you pass to sp.call()?

Comments