amazon-web-servicesamazon-s3pre-signed-urlaws-device-farm

Upload file using S3 presigned-url to device farm


Trying to upload a .apk to my device farm project without success. I have created this code to perform the task:

CLIENT = boto3.client("devicefarm", region_name="us-west-2")

def create_upload(project_arn, file_name, type):
    response = CLIENT.create_upload(
        projectArn=project_arn,
        name=file_name,
        type=type,
        contentType="application/octet-stream"
    )
    print(response)

    try:
        payload = {
            "file": open("app-release-04.apk", "rb")
        }
        header = {
            "contentType": "application/octet-stream"
        }
        app_arn = response["upload"]["arn"]
        signed_url = response["upload"]["url"]

        time.sleep(10)
        status = CLIENT.get_upload(arn=app_arn)
        print(status)

        api_response = requests.put(url=signed_url, files=payload, headers=header)
        print(api_response)
    except KeyError:
        raise KeyError(f"Upload failed! With project_arn: {project_arn},"
                    f"file_name: {file_name} and type: {type}: {response}")

    return app_arn

It works but and the api_response return <Response [200]>. However, I can't see the file anywhere in device farm. What am I doing wrong in my python code?

If I use the cli + curl then it works:

aws devicefarm create-upload --project-arn <PROJECT_ARN> --name app-release-04.apk --type ANDROID_APP --region us-west-2

curl -T app-release-04.apk <SIGNED_URL>

Solution

  • Turns out the issue was first the wrong header format "contentType" instead of "content-type". Then I changed the payload to look like this:

    data = open(f"{file_path}/{file_name}", 'rb')
    requests.put(url=signed_url, data=data, headers=header)
    

    Hence, use data instead of files in the put request.