Paweł Łukasiewicz
2022-04-15
Paweł Łukasiewicz
2022-04-15
Udostępnij Udostępnij Kontakt
Wprowadzenie

Jak już doskonale wiecie, S3 używane jest do przechowywania plików. W tym wpisie utworzymy funkcję Lambda reagującą na zdarzenia zachodzące na S3, np. dodanie nowego pliku do naszego kubełka.

W tym celu wykorzystamy handler funkcji, który jest punktem startowym posiadającym szczegóły dotyczące zdarzenia do jakiego doszło. W tym wpisie przejdziemy przez proces konfiguracji S3, dodanie wyzwalacza Lambdy oraz zapisanie logów potwierdzających przesłanie plików do S3.

Kolejne kroki, które wykonamy w ramach tego wpisu:

  1. Utworzymy kubełek S3;
  2. Utworzymy rolę, która ma uprawnienia do działania z S3 oraz Lambdą;
  3. Utworzymy funkcję Lambda i dodamy S3 jako wyzwalacz.

Dokładny opis działania

Zanim przejdziemy do właściwej implementacji poświęcimy kilka chwil na omówienie powyższych kroków w nieco bardziej szczegółowy sposób skupiając się na podstawowej interakcji pomiędzy S3 i Lambdą:

  • W pierwszym kroku użytkownik dodaje nowy plik do kubełka S3;
  • Dodanie pliku do S3 spowoduje uruchomienie w tle funkcji Lambda, która wyświetli informacje w postaci komunikatu na konsoli o tym, że plik został przesłany. W tym celu wykorzystam oczywiście handler funkcji co zobaczycie w szczegółach w dalszej części wpisu;
  • Użytkownik będzie mógł zobaczyć wspomniany powyżej komunikat w logach CloudWatch.

Spójrzcie jeszcze jak prezentuje się "architektura" takiej aplikacji: AWS: diagram architektury funkcji lambda z S3

Tworzenie S3

Spójrzcie na poniższą listę kroków:

  1. Przechodzimy pod adres https://console.aws.amazon.com/s3/home lub wykorzystujemy wyszukiwarkę usług: S3: wyszukiwarka usług
  2. W kolejnym kroku klikamy przycisk Create bucket.
  3. Przechodzimy do okna konfiguracyjnego na którym podajemy nazwę naszego ‘kubełka’ – resztę pól możemy pozostawić z domyślnymi wartościami: S3: konfiguracja
  4. Klikamy przycisk Create bucket znajdujący się na dole ekranu. Dostaniemy informację zwrotną o poprawnym utworzeniu kubełka: S3: tworzenie kubełka

Tworzenie roli dla S3 i Lambda

Korzystając z wyszukiwarki usług przechodzimy do Identity and Access Management (IAM) wybierając z panelu nawigacyjnego po lewej stronie Roles: S3: przygotowanie roli

Klikamy przycisk Create role a następnie wybieramy Lambdę jako usługę, która będzie korzystać z tej roli. Klikamy Next: Permissions: S3: role

Z poziomu widoku dostępnych polityk wybieramy: AmazonS3FullAccess, AmazonLambda_FullAccess oraz CloudWatchFullAccess. Kilikamy przycisk Next: Tags oraz od razu robimy Review: S3: sprawdzenie roli

Ostatni krok w tym punkcie to sprawdzenie czy trzy powyższe polityki zostały przypisane do roli, następnie zdefiniowane nazwy dla roli oraz kliknięcie przycisku Create role: S3: tworzenie roli z politykami

Lambda z wyzwalaczem na S3

W tej części wpisu dodamy Lambdę a następnie ustawimy na niej wyzwalacz (trigger) na S3.

Powoli będę ograniczał podstawowe kroki ponieważ omówiliśmy je dokładnie w poprzednim cyklu. Pierwszy krok to dodanie nowej Lambdy z poziomu konsoli AWS, określnie nazwy funkcji oraz przypisanie polityki, którą utworzyliśmy w poprzednim kroku: AWS Lambda: tworzenie roli

Po pomyślnym utworzeniu funkcji klikamy przycisk Add trigger dostępny z poziomu widoku szczegółowego danej lambdy i dokonujemy poniższej konfiguracji: AWS Lambda: dodawanie wyzwalacza

Klikamy przycisk Add. Na poniższym zrzucie ekranu możecie zobaczyć, że nasza Lambda będzie reagować na dodanie obiektu do S3: AWS Lambda: wyzwalacz dodany

Pora na modyfikację kodu naszej funkcji w celu wyświetlenia informacji dotyczącej akcji przeprowadzonej na S3. W tym celu wykorzystamy parameter event, który ma w sobie szczegóły zdarzenia związanego z akcją na S3. Dokonamy również logowania informacji dotyczącej nazwy kubełka oraz samego pliku, który został dodany. Spójrzcie na poniższy kod:

using System;
using System.Threading.Tasks;

using Amazon.Lambda.Core;
using Amazon.Lambda.S3Events;
using Amazon.S3;

// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace AWSLambda4
{
	public class Function
    {
        IAmazonS3 S3Client { get; set; }
        public Function()
		{
            S3Client = new AmazonS3Client();
        }
        
        /// <summary>
        /// A simple function that takes a string and does a ToUpper
        /// </summary>
        /// <param name="input"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public async Task<string> FunctionHandler(S3Event @event, ILambdaContext context)
        {
            var s3Event = @event.Records?[0].S3;

            if(s3Event == null)
			{
                return null;
			}

			try
			{
                var bucketName = s3Event.Bucket.Name;
                var fileName = s3Event.Object.Key;

                var response = await this.S3Client.GetObjectMetadataAsync(s3Event.Bucket.Name, s3Event.Object.Key);

                var message = $"Dodano plik do: {bucketName} -> {fileName}";
                context.Logger.LogLine(message);

                return response.Headers.ContentType;

            }
			catch (Exception ex)
			{
                context.Logger.LogLine($"Error getting object {s3Event.Object.Key} from bucket {s3Event.Bucket.Name}. Make sure they exist and your bucket is in the same region as this function.");
                context.Logger.LogLine(ex.Message);
                context.Logger.LogLine(ex.StackTrace);
                throw;
            }
        }
    }
}
Powyższy kod napisałem wykorzystując Visual Studio 2019 dodając nowy projekt w dokładnie ten sam sposób jak w poprzednim wpisie. Modyfikacje polegają na dołączeniu odpowiednich paczek oraz napisaniu prostego kodu spełniającego nasze założenia.

Co dalej? W momencie przygotowywania tego wpisu AWS nie obsługuje środowiska .NET Core 3.1 z poziomu konsoli – nie możemy wkleić kodu tak jak w poprzednim wpisie. Z drugiej strony dodaliśmy już nasza funkcję wraz z wyzwalaczem więc szkoda byłoby ponawiać te kroki i tworzyć od nowa funkcję. Wyjściem z tej sytuacji jest nieznaczna modyfikacja naszego projektu z VS mająca na celu zmianę pliku aws-lambda-tools-defaults.json w poniższy sposób w celu automatycznej publikacji z poziomu naszego środowiska:

{
    "Information" : [
        "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.",
        "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.",
        "dotnet lambda help",
        "All the command line options for the Lambda command can be specified in this file."
    ],
    "profile"     : "default",
    "region"      : "us-east-1",
    "configuration" : "Release",
    "framework"     : "netcoreapp3.1",
    "function-runtime" : "dotnetcore3.1",
    "function-memory-size" : 512,
    "function-timeout"     : 15,
    "function-handler"     : "AWSLambda4::AWSLambda4.Function::FunctionHandler",
    "function-name"        : "lambdaWithS3",
    "function-description" : "",
    "package-type"         : "Zip",
    "function-role"        : "arn:aws:iam::689983305523:role/LambdaWithS3Service",
    "tracing-mode"         : "PassThrough",
    "environment-variables" : "",
    "image-tag"             : ""
}

Zwróćcie uwagę na nazwę funkcji (function-name), która jest zgodna z funkcją dodaną z poziomu konsoli AWS. AWSLambda4 to nazwa projektu, który utworzyłem. Pozostałe parametry to zdefiniowanie handlera oraz roli, która jest przypisana do danej funkcji. Nie musicie tego robić ręcznie – korzystając z wtyczki AWS plik ten zostanie automatycznie zmodyfikowany na bazie waszych ustawień.

Testy

W tym momencie możemy dodać pliczek do S3, przejść następnie do CloudWatch i z poziomu LogGroups przejrzeć dziennik zdarzeń naszej funkcji Lambda. Powinniście zobaczyć log dotyczący zdarzenia do którego doszło: AWS Lambda: cloudwatch

Możecie poeksperytmentować z powyższym kodem, zobaczyć jakie dodatkowe informacje niesie event, wyświetlić szczegółowe informacje w dzienniku zdarzeń, itd. W następnym wpisie wykorzystamy bazę danych DynamoDB - wraz z dodaniem danych do tabeli dojdzie do uruchomienia funkcji Lambda, która wykorzystując usługę AWS SNS wyśle wiadomość do obiorcy informując o tym jakie dane zostały dodane.