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!