Résumé des épisodes précédents
Pour ceux qui ont raté le début, RDV sur la première partie !
Objectifs
Le but du jeu de ce nouvel article est le suivant :
- pousser une photo dans un bucket S3
- récupérer dans un autre bucket S3 une miniature de cette photo
Pour ce faire, nous allons utiliser des tableaux croisés dynamiques dans Excel, avec des macros VisualBasic dans Access. ...
... Mais bien sûr... Non ! Nous allons utiliser Lambda ! (petite forme ce matin le rédacteur...)
Pas à pas
Environnement de travail
Comme nous l'avons vu dans la première partie, les fonctions Lambda sont des fonctions JavaScript exécutées par Node.js. (scoop : une version Java de Lambda est en préparation...).
Afin de développer notre fonction lambda, il nous faut donc Node.js.
Sous Ubuntu :
sudo apt-add-repository ppa:chris-lea/node.js
sudo apt-get install nodejs npm
Plaçons nous maintenant là où nous souhaitons écrire notre fonction, et installons deux modules Nodes.js :
mkdir ~/lambda
cd ~/lambda
npm install async gm
vim CreateThumbnail.js
Fonction Lambda
Nous allons donc maintenant écrire notre fonction Lambda :
// Chargement des modules Node.js
var async = require('async') ;
var AWS = require('aws-sdk') ;
var util = require('util');
// Chargement de ImageMagick, outil qui permet de traiter des images
var gm = require('gm').subClass({ imageMagick: true }) ;
// Constantes
var MAX_WIDTH = 100 ;
var MAX_HEIGHT = 100 ;
// Client S3
var s3 = new AWS.S3() ;
// Fonction Lambda
exports.handler = function(event, context)
{
// Lecture des parametres passés à l'évenement
console.log("Reading options from event:\n", util.inspect(event, {depth: 5})) ;
// Bucket S3 source
var srcBucket = event.Records[0].s3.bucket.name ;
// Si l'ojbjet (fichiet) comporte des espaces ou des caracteres spéciaux
var srcKey = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, " ")) ;
// Bucket S3 de destination
var dstBucket = srcBucket + "resized" ;
// Objet de destination
var dstKey = "resized-" + srcKey ;
// Sanity check: On vérifie que la source et la destination ne sont pas identiques
if (srcBucket == dstBucket)
{
console.error("Destination bucket must not match source bucket.") ;
return ;
}
// On vérifie qu'on a bien affaire a une image jpg ou png
var typeMatch = srcKey.match(/\.([^.]*)$/) ;
if (!typeMatch)
{
console.error('unable to infer image type for key ' + srcKey);
return;
}
var imageType = typeMatch[1];
if (imageType != "jpg" && imageType != "png")
{
console.log('skipping non-image ' + srcKey);
return;
}
// Récupération de la photo originale, transformation et upload vers un autre bucket S3
async.waterfall(
[
function download(next)
{
// Téléchargement de l'image depuis S3
s3.getObject({ Bucket: srcBucket, Key: srcKey }, next) ;
},
function tranform(response, next)
{
gm(response.Body).size(function(err, size)
{
// Calcul du ratio de mise à l'échelle
var scalingFactor = Math.min(MAX_WIDTH / size.width, MAX_HEIGHT / size.height);
var width = scalingFactor * size.width;
var height = scalingFactor * size.height;
// Transformation de l'image
this.resize(width, height).toBuffer(imageType, function(err, buffer)
{
if (err)
{
next(err);
}
else
{
next(null, response.ContentType, buffer);
}
});
});
},
function upload(contentType, data, next)
{
// Upload de l'image dans un autre bucket S3
s3.putObject({ Bucket: dstBucket, Key: dstKey, Body: data, ContentType: contentType }, next);
}
],
function (err)
{
if (err)
{
console.error('Impossible de traiter '
+ srcBucket +'/'+ srcKey+' et ou de l\'envoyer vers '
+ dstBucket+ '/'+ dstKey+' a cause de l\'erreur : ' + err);
}
else
{
console.log('Image traitée ! ' + srcBucket + '/' + srcKey +' envoyée dans ' + dstBucket + '/' + dstKey);
}
context.done();
});
};
Remarques importantes :
- Le bucket source doit exister
- Le bucket de destination doit exister. Si le source s'appelle
toto
, celui de destination doit s'appelertotoresized
.
Envoi du code dans Lambda
On considère que le rôle IAM a bien été créé (cf. première partie). On peut donc envoyer notre fonction lambda.
Mais avant, il faut créer notre package sous forme de zip :
zip -r CreateThumbnail.zip ./*
Puis on l'envoie dans Lambda :
aws lambda create-function \
--region eu-west-1 \
--function-name CreateThumbnail \
--zip-file fileb://CreateThumbnail.zip \
--role role-arn arn:aws:iam::397960517128:role/lambda-exec \
--handler CreateThumbnail.handler \
--runtime nodejs \
--profile adminuser \
--timeout 10 \
--memory-size 1024
Configuration de S3 pour interagir avec Lambda
On commence par autoriser le bucket S3 a déclencher la fonction Lambda
aws lambda add-permission \
--function-name CreateThumbnail \
--region eu-west-1 \
--statement-id Id-x \
--action "lambda:InvokeFunction" \
--principal s3.amazonaws.com \
--source-arn arn:aws:s3:::agh-osones \
--source-account 397960517128 \
--profile adminuser
Puis, on configure les notifications au niveau du bucket. Ceci se fait via la console. Cf. http://docs.aws.amazon.com/AmazonS3/latest/UG/SettingBucketNotifications.html
Test grandeur nature
Maintenant, si vous envoyez des photos dans le premier bucket, alors, quelques secondes après, vous aurez la version miniature dans le second bucket.
Magique non ?
Alexis GÜNST
Encore un peu de temps ? Lisez nos autres articles :
- On a testé Amazon Elastic File System (EFS).
- Container as a Service avec Amazon EC2 Container Service (ECS).
Vous avez des projets sur AWS ? N'hésitez pas à visiter notre site internet.
Vous avez des questions ? Rejoignez la discussion sur le groupe LinkedIn des Utilisateurs Francophones d'Amazon Web Services (AWS).
Découvrez les derniers articles d'alter way
- : Prowler : L'outil de sécurité multi-cloud indispensable pour renforcer votre infrastructure
- : Kubernetes : plateforme "star" de l'IT et levier d'innovation des entreprises
- AI_dev2024
- : DirectPV : Avoir du stockage bloc distribué facilement dans kubernetes
- : Simple comme GitOps : kluctl
- Conférence Wax 2024 @thecamp