Full stack

Como testar um AWS Lambda na sua máquina com Python e Localstack

Neste artigo, quero compartilhar como aprendi a usar o Localstack com Node.js para testar funções sem servidor e outros serviços da Amazon Web Services. Se você desenvolve aplicativos na AWS, primeiro aprender a testar serviços como SQS, S3 ou Lambda em sua máquina é uma boa estratégia para acelerar o processo de desenvolvimento.

Testei recentemente um projeto em que estou trabalhando na AWS, e enquanto separei meus ambientes (dev, stage e prd), se você considerar que o dólar na hora de escrever está acima de 5,10 reais, imagine só olha minha cara triste quando vejo Billing on AWS, é simplesmente bobo.

Este artigo foi escrito com exemplos de comandos Node.js e AWS CLI, caso tenha alguma dificuldade de compreensão, deixe um comentário explicando seu problema e eu te ajudo.

Setup:

Ubuntu 20.04 LTS;

IDE: PyCharm Professional;

Python 3.8;

Docker;

AWS SAM CLI: é necessário para IDE funcionar com AWS Services;

AWS CLI: você pode usar suas credenciais reais (conforme descrito aqui) ou criar uma fictícia. Localstack verifica se as credenciais existem em vez de serem válidas;

Serverless framework;

configuração

AWS CLI

Em relação à AWS CLI, você pode visualizar os materiais para instalação no site da AWS.

AWS SAM CLI

Para instalar o AWS SAM CLI, a documentação da AWS informa que ele será instalado pelo Homebrew, mas em alguns casos é difícil instalar desta forma, com isso em mente, aqui está outra forma de instalar o AWS SAM CLI, também disponível no Github AWS SAM Código-fonte CLI.

$ git clone https://github.com/awslabs/aws-sam-cli.git

$ cd aws-sam-cli

$ sudo python3.8 ./setup.py build install

$ sam --version

A saída final:

SAM CLI, version 0.47.0

Localstack Docker

Neste ponto, um “docker-compose.yaml” deve ser criado no diretório raiz do projeto para que o localstack do contêiner docker possa ser executado.

$ touch docker-compose.yml

docker-compose.yml

version: '2.1'

services:

 localstack:

 image: localstack/localstack

 ports:

 - "4567-4597:4567-4597"

 - "${PORT_WEB_UI-8080}:${PORT_WEB_UI-8080}"

 environment:

 - SERVICES=${SERVICES- }

 - DEBUG=${DEBUG- }

 - DATA_DIR=${DATA_DIR- }

 - PORT_WEB_UI=${PORT_WEB_UI- }

 - LAMBDA_EXECUTOR=${LAMBDA_EXECUTOR- }

 - KINESIS_ERROR_PROBABILITY=${KINESIS_ERROR_PROBABILITY- }

 - DOCKER_HOST=unix:///var/run/docker.sock

 volumes:

 - "${TMPDIR:-/tmp/localstack}:/tmp/localstack"

 - "/var/run/docker.sock:/var/run/docker.sock"

E agora vamos rodar o “docker-compose” com o seguinte comando:

$ docker-compose up

A partir de agora, diferentes serviços da AWS podem ser acessados ​​por diferentes portas no servidor local.

Vamos testar o serviço do AWS S3.

$ curl -v http://localhost:4572

Parte da saída:

<ListAllMyBucketsResult xmlns="http://s3.amazonaws.com/doc/2006-03-01">

<Owner><ID>bcaf1ffd86f41161ca5fb16fd081034f</ID>

<DisplayName>webfile</DisplayName></Owner><Buckets></Buckets>

</ListAllMyBucketsResult>

Este teste também pode ser realizado no navegador. Basta copiar o endereço e colá-lo na url do seu navegador.

Algumas portas de serviço da AWS com Localstack

S3: 4572

DynamoDB: 4570

CloudFormation: 4581

Elasticsearch: 4571

ES: 4578

SNS: 4575

SQS: 4576

Lambda: 4574

Kinesis: 4568

AWS Lambda com Python PyCharm

Assim que o “docker-compose” estiver funcionando, é hora de criar o projeto.

Neste ponto, vamos criar um novo projeto no PyCharm:

Criando um no projeto

É muito importante verificar se “SAM CLI” é reconhecido automaticamente.

Criando o arquivo principal

Chegou a hora de criar o lambda_function.py, na raíz do projeto.

import urllib.parse

import boto3

import json

# print('Loading function')

HOST = "http://[YOUR_IP]"

# Get the service resource

# To production it's not necessary inform the "endpoint_url" and "region_name"

s3 = boto3.client('s3',

                  endpoint_url= HOST + ":4572",

                  region_name="us-east-1")

sqs = boto3.client('sqs',

                    endpoint_url= HOST + ":4576",

                    region_name="us-east-1")

def lambda_handler(event, context):

    # print("Received event: " + json.dumps(event, indent=2))

    # Get the object from the event and show its content type

    bucket = event['Records'][0]['s3']['bucket']['name']

    key = urllib.parse.unquote_plus(event['Records'][0]['s3']['object'] ['key'],     encoding='utf-8')

    url_queue = HOST + ":4576/queue/lambda-tutorial"

try:

    response = s3.get_object(Bucket=bucket, Key=key)

    deb = {

        "request_id": response['ResponseMetadata']['RequestId'],

        "queue_url": url_queue,

        "key": key,

        "bucket": bucket,

        "message": "aws lambda with localstack..."

    }

    print("#########################################################")

    print("Send Message")

    #Send message to SQS queue

    response = sqs.send_message(

    QueueUrl=deb["queue_url"],

        MessageBody=json.dumps(deb)

    )

    print("response: {}".format(response))




    print("#########################################################")

    print("Receive 10 Messages From SQS Queue")

    response = sqs.receive_message(

        QueueUrl=deb["queue_url"],

        MaxNumberOfMessages=10,

        VisibilityTimeout=0,

        WaitTimeSeconds=0

    )




    print("#########################################################")

    print("Read All Messages From Response")

    messages = response['Messages']

    for message in messages:

        print("Message: {}".format(message))




    print("Final Output: {}".format(json.dumps(response)))

    return json.dumps(response)




    except Exception as e:

        print(e)

        raise e

Se o “boto3” não estiver instalado a IDE irá notificar, assim sendo, abra o terminal e execute o seguinte comando:




$ pip3.8 install boto3

Criando os arquivos que darão suporte ao projeto

Neste ponto serão criadas algumas pastas e arquivos que conterão os arquivos usados ​​no teste.

Vamos criar as pastas “test/files” na raíz do projeto e então criar os arquivo para rodar o projeto.

aws-lambda-localstack

|test/

|- file/

|- - test_file.log

|- - input-event-test.json

|requirements.txt

test_file.log: Este arquivo será usado como exemplo vindo do bucket. Pode ser um arquivo vazio.

requirements.txt: Este arquivo é exigido pelo “SAM CLI”.

input-event-test.json: Este arquivo será executado para rodar o projeto. Ele contém as informações do bucket.

{

 "Records": [

 {

 "eventVersion": "2.0",

 "eventSource": "aws:s3",

 "awsRegion": "us-east-1",

 "eventTime": "1970-01-01T00:00:00.000Z",

 "eventName": "ObjectCreated:Put",

 "userIdentity": {

 "principalId": "EXAMPLE"

 },

 "requestParameters": {

 "sourceIPAddress": "127.0.0.1"

 },

 "responseElements": {

 "x-amz-request-id": "EXAMPLE123456789",

 "x-amz-id-2":

"EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH"

 },

 "s3": {

 "s3SchemaVersion": "1.0",

 "configurationId": "testConfigRule",

 "bucket": {

 "name": "tutorial",

 "ownerIdentity": {

 "principalId": "EXAMPLE"

 },

 "arn": "arn:aws:s3:::example-bucket"

 },

 "object": {

 "key": "lambda/test_file.log",

 "size": 1024,

 "eTag": "0123456789abcdef0123456789abcdef",

 "sequencer": "0A1B2C3D4E5F678901"

    }

   }

  }

 ]

}

Após concluir as etapas anteriores, a próxima etapa será configurar a configuração de execução.

Agora a configuração de IDE está feita, hora de configurar as entradas.

Para configurar as entradas é obrigatório rodar alguns comando para criar os arquivos no S3 e criar a fila no SQS.

1 – Criando o bucket no S3: o bucket será nomeado como “tutorial”

$ aws --endpoint-url=http://localhost:4572 s3 mb s3://tutorial

2 – Criando a pasta no S3: será criada uma pasta chamada “lambda”

$ aws --endpoint-url=http://localhost:4572 s3api put-object --bucket tutorial --

key lambda

O Response será alguma como:

{

 "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\""

}

3 – Copiando arquivos para o bucket: copiando os arquivos de “test/files” para “s3://tutorial/lambda/”

$ aws --endpoint-url=http://localhost:4572 s3 cp ./test/files/

s3://tutorial/lambda/ --recursive

Você precisa verificar se o bucket foi criado. Copie o valor de “endpoint-url” e execute “curl” ou cole no seu navegador, por exemplo:

$ curl -v http://localhost:4572/tutorial

A saída será algo como:

<?xml version="1.0" encoding="UTF-8"?>

<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">

 <Name>tutorial</Name>

 <MaxKeys>1000</MaxKeys>

 <Delimiter>None</Delimiter>

 <IsTruncated>false</IsTruncated>

 <Contents>

 <Key>lambda</Key>

 <LastModified>2020-04-28T01:36:04.128Z</LastModified>

 <ETag>"d41d8cd98f00b204e9800998ecf8427e"</ETag>

 <Size>0</Size>

 <StorageClass>STANDARD</StorageClass>

 <Owner>




<ID>75aa57f09aa0c8caeab4f8c24e99d10f8e7faeebf76c078efc7c6caea54ba06a</ID>

 <DisplayName>webfile</DisplayName>

  </Owner>

 </Contents>

 <Contents>

 <Key>lambda/input-event-test.json</Key>

 <LastModified>2020-04-28T01:40:27.882Z</LastModified>

 <ETag>"4e114da7aa17878f62bf4485a90a97a2"</ETag>

 <Size>1011</Size>

 <StorageClass>STANDARD</StorageClass>

 <Owner>




<ID>75aa57f09aa0c8caeab4f8c24e99d10f8e7faeebf76c078efc7c6caea54ba06a</ID>

 <DisplayName>webfile</DisplayName>

 </Owner>

 </Contents>

 <Contents>

 <Key>lambda/test_file.log</Key>

 <LastModified>2020-04-28T01:40:27.883Z</LastModified>

 <ETag>"4ac646c9537443757aff7ebd0df4f448"</ETag>

 <Size>29</Size>

 <StorageClass>STANDARD</StorageClass>

 <Owner>




<ID>75aa57f09aa0c8caeab4f8c24e99d10f8e7faeebf76c078efc7c6caea54ba06a</ID>

 <DisplayName>webfile</DisplayName>

 </Owner>

 </Contents>

</ListBucketResult>

4 – Criando um fila no SQS

$ aws --endpoint-url=http://localhost:4576 sqs create-queue --queue-name

lambda-tutorial

O retorno será algo como:

{

 "QueueUrl": "http://localhost:4576/queue/lambda-tutorial"

}

Depois que tudo estiver pronto e toda a saída estiver OK, é hora de executar o projeto.

Observe que a entrada e a saída desse texto estão em código.

Portanto, para executar o projeto, clique no botão “Executar ‘[Local] lambda_function.lambda_handler'”.

Depois disso, você pode ver a saída do processo no console.

As entradas serão exibidas e, eventualmente, 10 mensagens serão recuperadas da fila e exibidas no console.

Concluído!

Isso pode ser apenas um ponto de partida, e espero que este artigo o ajude a testar seu serviço AWS Lambda com Python.

Espero que todos alcancem seus objetivos.

Obrigado por ler até o final!