Operational Serverless
Vicenç García Altés
@vgaltes
info@vgaltes.com
https://vgaltes.com





What's serverless?


Title Text

BIASES



MORE BIASES




The three ways
- Principles of flow
- Principles of feedback
- Principles of continuous learning and investigation
TECHNICAL PRACTICES OF FLOW

FAST AND RELIABLE TESTING

ENABLE AND PRACTICE CONTINUOUS INTEGRATION

CREATE THE FOUNDATIONS OF OUR DEPLOYMENT PIPELINE

FOUNDATIONS OF THE DEPLOYMENT PIPELINE
- Enable on-demand creation of Dev, Test and Prod environments.
- Create our single repository of truth for the entire system.
- Make our infrastructure easier to rebuild than to repair.
- Modify our definition of development done to include running in production-like environments.

CLOUDFORMATION
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "The AWS CloudFormation template for this Serverless application",
"Resources": {
"ServerlessDeploymentBucket": {
"Type": "AWS::S3::Bucket"
},
"ServiceDashaLogGroup": {
"Type": "AWS::Logs::LogGroup",
"Properties": {
"LogGroupName": "/aws/lambda/serverless-observability-dev-service-a"
}
},
"ServiceDashbLogGroup": {
"Type": "AWS::Logs::LogGroup",
"Properties": {
"LogGroupName": "/aws/lambda/serverless-observability-dev-service-b"
}
},
"ServiceDashcLogGroup": {
"Type": "AWS::Logs::LogGroup",
"Properties": {
"LogGroupName": "/aws/lambda/serverless-observability-dev-service-c"
}
},
"ServiceDashreadDashsnsLogGroup": {
"Type": "AWS::Logs::LogGroup",
"Properties": {
"LogGroupName": "/aws/lambda/serverless-observability-dev-service-read-sns"
}
},
"ServiceDashreadDashdynamoLogGroup": {
"Type": "AWS::Logs::LogGroup",
"Properties": {
"LogGroupName": "/aws/lambda/serverless-observability-dev-service-read-dynamo"
}
},
"ServiceDashreadDashs3LogGroup": {
"Type": "AWS::Logs::LogGroup",
"Properties": {
"LogGroupName": "/aws/lambda/serverless-observability-dev-service-read-s3"
}
},
"TimeoutLogGroup": {
"Type": "AWS::Logs::LogGroup",
"Properties": {
"LogGroupName": "/aws/lambda/serverless-observability-dev-timeout"
}
},
"ErrorLogGroup": {
"Type": "AWS::Logs::LogGroup",
"Properties": {
"LogGroupName": "/aws/lambda/serverless-observability-dev-error"
}
},
"SnsLogGroup": {
"Type": "AWS::Logs::LogGroup",
"Properties": {
"LogGroupName": "/aws/lambda/serverless-observability-dev-sns"
}
},
"IamRoleLambdaExecution": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"lambda.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Policies": [
{
"PolicyName": {
"Fn::Join": [
"-",
[
"dev",
"serverless-observability",
"lambda"
]
]
},
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogStream"
],
"Resource": [
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-service-a:*"
},
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-service-b:*"
},
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-service-c:*"
},
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-service-read-sns:*"
},
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-service-read-dynamo:*"
},
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-service-read-s3:*"
},
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-timeout:*"
},
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-error:*"
},
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-sns:*"
}
]
},
{
"Effect": "Allow",
"Action": [
"logs:PutLogEvents"
],
"Resource": [
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-service-a:*:*"
},
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-service-b:*:*"
},
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-service-c:*:*"
},
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-service-read-sns:*:*"
},
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-service-read-dynamo:*:*"
},
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-service-read-s3:*:*"
},
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-timeout:*:*"
},
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-error:*:*"
},
{
"Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/serverless-observability-dev-sns:*:*"
}
]
},
{
"Effect": "Allow",
"Action": [
"dynamodb:PutItem",
"dynamodb:GetItem",
"dynamodb:DescribeStream",
"dynamodb:GetRecords",
"dynamodb:GetShardIterator",
"dynamodb:ListStreams"
],
"Resource": [
{
"Fn::Sub": "arn:aws:dynamodb:${AWS::Region}:*:table/serverless-observability-dev"
}
]
},
{
"Effect": "Allow",
"Action": [
"s3:GetObject*",
"s3:PutObject*",
"s3:ListBucket*",
"s3:PutBucketNotification"
],
"Resource": [
{
"Fn::Sub": "arn:aws:s3:::serverless-observability-dev-${AWS::Region}-${AWS::AccountId}"
},
{
"Fn::Sub": "arn:aws:s3:::serverless-observability-dev-${AWS::Region}-${AWS::AccountId}/*"
}
]
},
{
"Effect": "Allow",
"Action": [
"sns:Publish",
"sns:Subscribe"
],
"Resource": [
{
"Fn::Sub": "arn:aws:sns:${AWS::Region}:*:serverless-observability-dev"
}
]
},
{
"Effect": "Allow",
"Action": [
"lambda:InvokeFunction"
],
"Resource": [
{
"Fn::Sub": "arn:aws:lambda:${AWS::Region}:*:function:serverless-observability-dev-*"
}
]
},
{
"Effect": "Allow",
"Action": [
"dynamodb:GetRecords",
"dynamodb:GetShardIterator",
"dynamodb:DescribeStream",
"dynamodb:ListStreams"
],
"Resource": [
{
"Fn::GetAtt": [
"DynamoDB",
"StreamArn"
]
}
]
}
]
}
}
],
"Path": "/",
"RoleName": {
"Fn::Join": [
"-",
[
"serverless-observability",
"dev",
{
"Fn::Sub": "${AWS::Region}"
},
"lambdaRole"
]
]
}
}
},
"ServiceDashaLambdaFunction": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": {
"Ref": "ServerlessDeploymentBucket"
},
"S3Key": "serverless/serverless-observability/dev/1536766420565-2018-09-12T15:33:40.565Z/serverless-observability.zip"
},
"FunctionName": "serverless-observability-dev-service-a",
"Handler": "functions/service-a.handler",
"MemorySize": 1024,
"Role": {
"Fn::GetAtt": [
"IamRoleLambdaExecution",
"Arn"
]
},
"Runtime": "nodejs8.10",
"Timeout": 10,
"Environment": {
"Variables": {
"stage": "dev",
"service": "serverless-observability",
"accountId": {
"Ref": "AWS::AccountId"
},
"thundra_api_key": "33acec61-a6c1-49ad-96ad-2ad513a64dab",
"BUCKET_NAME": {
"Fn::Sub": "serverless-observability-dev-${AWS::Region}-${AWS::AccountId}"
}
}
}
},
"DependsOn": [
"ServiceDashaLogGroup",
"IamRoleLambdaExecution"
]
},
"ServiceDashbLambdaFunction": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": {
"Ref": "ServerlessDeploymentBucket"
},
"S3Key": "serverless/serverless-observability/dev/1536766420565-2018-09-12T15:33:40.565Z/serverless-observability.zip"
},
"FunctionName": "serverless-observability-dev-service-b",
"Handler": "functions/service-b.handler",
"MemorySize": 1024,
"Role": {
"Fn::GetAtt": [
"IamRoleLambdaExecution",
"Arn"
]
},
"Runtime": "nodejs8.10",
"Timeout": 6,
"Environment": {
"Variables": {
"stage": "dev",
"service": "serverless-observability",
"accountId": {
"Ref": "AWS::AccountId"
},
"thundra_api_key": "33acec61-a6c1-49ad-96ad-2ad513a64dab"
}
}
},
"DependsOn": [
"ServiceDashbLogGroup",
"IamRoleLambdaExecution"
]
},
"ServiceDashcLambdaFunction": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": {
"Ref": "ServerlessDeploymentBucket"
},
"S3Key": "serverless/serverless-observability/dev/1536766420565-2018-09-12T15:33:40.565Z/serverless-observability.zip"
},
"FunctionName": "serverless-observability-dev-service-c",
"Handler": "functions/service-c.handler",
"MemorySize": 1024,
"Role": {
"Fn::GetAtt": [
"IamRoleLambdaExecution",
"Arn"
]
},
"Runtime": "nodejs8.10",
"Timeout": 6,
"Environment": {
"Variables": {
"stage": "dev",
"service": "serverless-observability",
"accountId": {
"Ref": "AWS::AccountId"
},
"thundra_api_key": "33acec61-a6c1-49ad-96ad-2ad513a64dab"
}
}
},
"DependsOn": [
"ServiceDashcLogGroup",
"IamRoleLambdaExecution"
]
},
"ServiceDashreadDashsnsLambdaFunction": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": {
"Ref": "ServerlessDeploymentBucket"
},
"S3Key": "serverless/serverless-observability/dev/1536766420565-2018-09-12T15:33:40.565Z/serverless-observability.zip"
},
"FunctionName": "serverless-observability-dev-service-read-sns",
"Handler": "functions/service-read-sns.handler",
"MemorySize": 1024,
"Role": {
"Fn::GetAtt": [
"IamRoleLambdaExecution",
"Arn"
]
},
"Runtime": "nodejs8.10",
"Timeout": 6,
"Environment": {
"Variables": {
"stage": "dev",
"service": "serverless-observability",
"accountId": {
"Ref": "AWS::AccountId"
},
"thundra_api_key": "33acec61-a6c1-49ad-96ad-2ad513a64dab"
}
}
},
"DependsOn": [
"ServiceDashreadDashsnsLogGroup",
"IamRoleLambdaExecution"
]
},
"ServiceDashreadDashdynamoLambdaFunction": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": {
"Ref": "ServerlessDeploymentBucket"
},
"S3Key": "serverless/serverless-observability/dev/1536766420565-2018-09-12T15:33:40.565Z/serverless-observability.zip"
},
"FunctionName": "serverless-observability-dev-service-read-dynamo",
"Handler": "functions/service-read-dynamo.handler",
"MemorySize": 1024,
"Role": {
"Fn::GetAtt": [
"IamRoleLambdaExecution",
"Arn"
]
},
"Runtime": "nodejs8.10",
"Timeout": 6,
"Environment": {
"Variables": {
"stage": "dev",
"service": "serverless-observability",
"accountId": {
"Ref": "AWS::AccountId"
},
"thundra_api_key": "33acec61-a6c1-49ad-96ad-2ad513a64dab"
}
}
},
"DependsOn": [
"ServiceDashreadDashdynamoLogGroup",
"IamRoleLambdaExecution"
]
},
"ServiceDashreadDashs3LambdaFunction": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": {
"Ref": "ServerlessDeploymentBucket"
},
"S3Key": "serverless/serverless-observability/dev/1536766420565-2018-09-12T15:33:40.565Z/serverless-observability.zip"
},
"FunctionName": "serverless-observability-dev-service-read-s3",
"Handler": "functions/service-read-s3.handler",
"MemorySize": 1024,
"Role": {
"Fn::GetAtt": [
"IamRoleLambdaExecution",
"Arn"
]
},
"Runtime": "nodejs8.10",
"Timeout": 6,
"Environment": {
"Variables": {
"stage": "dev",
"service": "serverless-observability",
"accountId": {
"Ref": "AWS::AccountId"
},
"thundra_api_key": "33acec61-a6c1-49ad-96ad-2ad513a64dab"
}
}
},
"DependsOn": [
"ServiceDashreadDashs3LogGroup",
"IamRoleLambdaExecution"
]
},
"TimeoutLambdaFunction": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": {
"Ref": "ServerlessDeploymentBucket"
},
"S3Key": "serverless/serverless-observability/dev/1536766420565-2018-09-12T15:33:40.565Z/serverless-observability.zip"
},
"FunctionName": "serverless-observability-dev-timeout",
"Handler": "functions/timeout.handler",
"MemorySize": 1024,
"Role": {
"Fn::GetAtt": [
"IamRoleLambdaExecution",
"Arn"
]
},
"Runtime": "nodejs8.10",
"Timeout": 1,
"Environment": {
"Variables": {
"stage": "dev",
"service": "serverless-observability",
"accountId": {
"Ref": "AWS::AccountId"
},
"thundra_api_key": "33acec61-a6c1-49ad-96ad-2ad513a64dab"
}
}
},
"DependsOn": [
"TimeoutLogGroup",
"IamRoleLambdaExecution"
]
},
"ErrorLambdaFunction": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": {
"Ref": "ServerlessDeploymentBucket"
},
"S3Key": "serverless/serverless-observability/dev/1536766420565-2018-09-12T15:33:40.565Z/serverless-observability.zip"
},
"FunctionName": "serverless-observability-dev-error",
"Handler": "functions/error.handler",
"MemorySize": 1024,
"Role": {
"Fn::GetAtt": [
"IamRoleLambdaExecution",
"Arn"
]
},
"Runtime": "nodejs8.10",
"Timeout": 6,
"Environment": {
"Variables": {
"stage": "dev",
"service": "serverless-observability",
"accountId": {
"Ref": "AWS::AccountId"
},
"thundra_api_key": "33acec61-a6c1-49ad-96ad-2ad513a64dab"
}
}
},
"DependsOn": [
"ErrorLogGroup",
"IamRoleLambdaExecution"
]
},
"SnsLambdaFunction": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": {
"Ref": "ServerlessDeploymentBucket"
},
"S3Key": "serverless/serverless-observability/dev/1536766420565-2018-09-12T15:33:40.565Z/serverless-observability.zip"
},
"FunctionName": "serverless-observability-dev-sns",
"Handler": "functions/sns.handler",
"MemorySize": 1024,
"Role": {
"Fn::GetAtt": [
"IamRoleLambdaExecution",
"Arn"
]
},
"Runtime": "nodejs8.10",
"Timeout": 6,
"Environment": {
"Variables": {
"stage": "dev",
"service": "serverless-observability",
"accountId": {
"Ref": "AWS::AccountId"
},
"thundra_api_key": "33acec61-a6c1-49ad-96ad-2ad513a64dab"
}
}
},
"DependsOn": [
"SnsLogGroup",
"IamRoleLambdaExecution"
]
},
"S3BucketServerlessobservabilitydevAWSRegionAWSAccountId": {
"Type": "AWS::S3::Bucket",
"Properties": {
"BucketName": {
"Fn::Sub": "serverless-observability-dev-${AWS::Region}-${AWS::AccountId}"
},
"NotificationConfiguration": {
"LambdaConfigurations": [
{
"Event": "s3:ObjectCreated:*",
"Function": {
"Fn::GetAtt": [
"ServiceDashreadDashs3LambdaFunction",
"Arn"
]
}
}
]
}
},
"DependsOn": [
"ServiceDashreadDashs3LambdaPermissionServerlessobservabilitydevAWSRegionAWSAccountIdS3"
]
},
"ServiceDashreadDashs3LambdaPermissionServerlessobservabilitydevAWSRegionAWSAccountIdS3": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"FunctionName": {
"Fn::GetAtt": [
"ServiceDashreadDashs3LambdaFunction",
"Arn"
]
},
"Action": "lambda:InvokeFunction",
"Principal": {
"Fn::Join": [
"",
[
"s3.",
{
"Ref": "AWS::URLSuffix"
}
]
]
},
"SourceArn": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
{
"Fn::Sub": ":s3:::serverless-observability-dev-${AWS::Region}-${AWS::AccountId}"
}
]
]
}
}
},
"ApiGatewayRestApi": {
"Type": "AWS::ApiGateway::RestApi",
"Properties": {
"Name": "dev-serverless-observability",
"EndpointConfiguration": {
"Types": [
"EDGE"
]
}
}
},
"ApiGatewayResourceDemo": {
"Type": "AWS::ApiGateway::Resource",
"Properties": {
"ParentId": {
"Fn::GetAtt": [
"ApiGatewayRestApi",
"RootResourceId"
]
},
"PathPart": "demo",
"RestApiId": {
"Ref": "ApiGatewayRestApi"
}
}
},
"ApiGatewayResourceDemoServiceDasha": {
"Type": "AWS::ApiGateway::Resource",
"Properties": {
"ParentId": {
"Ref": "ApiGatewayResourceDemo"
},
"PathPart": "service-a",
"RestApiId": {
"Ref": "ApiGatewayRestApi"
}
}
},
"ApiGatewayResourceDemoServiceDashb": {
"Type": "AWS::ApiGateway::Resource",
"Properties": {
"ParentId": {
"Ref": "ApiGatewayResourceDemo"
},
"PathPart": "service-b",
"RestApiId": {
"Ref": "ApiGatewayRestApi"
}
}
},
"ApiGatewayResourceDemoTimeout": {
"Type": "AWS::ApiGateway::Resource",
"Properties": {
"ParentId": {
"Ref": "ApiGatewayResourceDemo"
},
"PathPart": "timeout",
"RestApiId": {
"Ref": "ApiGatewayRestApi"
}
}
},
"ApiGatewayResourceDemoError": {
"Type": "AWS::ApiGateway::Resource",
"Properties": {
"ParentId": {
"Ref": "ApiGatewayResourceDemo"
},
"PathPart": "error",
"RestApiId": {
"Ref": "ApiGatewayRestApi"
}
}
},
"ApiGatewayMethodDemoServiceDashaGet": {
"Type": "AWS::ApiGateway::Method",
"Properties": {
"HttpMethod": "GET",
"RequestParameters": {
"method.request.querystring.n": true
},
"ResourceId": {
"Ref": "ApiGatewayResourceDemoServiceDasha"
},
"RestApiId": {
"Ref": "ApiGatewayRestApi"
},
"ApiKeyRequired": false,
"AuthorizationType": "NONE",
"Integration": {
"IntegrationHttpMethod": "POST",
"Type": "AWS_PROXY",
"Uri": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":apigateway:",
{
"Ref": "AWS::Region"
},
":lambda:path/2015-03-31/functions/",
{
"Fn::GetAtt": [
"ServiceDashaLambdaFunction",
"Arn"
]
},
"/invocations"
]
]
}
},
"MethodResponses": []
}
},
"ApiGatewayMethodDemoServiceDashbGet": {
"Type": "AWS::ApiGateway::Method",
"Properties": {
"HttpMethod": "GET",
"RequestParameters": {},
"ResourceId": {
"Ref": "ApiGatewayResourceDemoServiceDashb"
},
"RestApiId": {
"Ref": "ApiGatewayRestApi"
},
"ApiKeyRequired": false,
"AuthorizationType": "NONE",
"Integration": {
"IntegrationHttpMethod": "POST",
"Type": "AWS_PROXY",
"Uri": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":apigateway:",
{
"Ref": "AWS::Region"
},
":lambda:path/2015-03-31/functions/",
{
"Fn::GetAtt": [
"ServiceDashbLambdaFunction",
"Arn"
]
},
"/invocations"
]
]
}
},
"MethodResponses": []
}
},
"ApiGatewayMethodDemoTimeoutGet": {
"Type": "AWS::ApiGateway::Method",
"Properties": {
"HttpMethod": "GET",
"RequestParameters": {},
"ResourceId": {
"Ref": "ApiGatewayResourceDemoTimeout"
},
"RestApiId": {
"Ref": "ApiGatewayRestApi"
},
"ApiKeyRequired": false,
"AuthorizationType": "NONE",
"Integration": {
"IntegrationHttpMethod": "POST",
"Type": "AWS_PROXY",
"Uri": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":apigateway:",
{
"Ref": "AWS::Region"
},
":lambda:path/2015-03-31/functions/",
{
"Fn::GetAtt": [
"TimeoutLambdaFunction",
"Arn"
]
},
"/invocations"
]
]
}
},
"MethodResponses": []
}
},
"ApiGatewayMethodDemoErrorGet": {
"Type": "AWS::ApiGateway::Method",
"Properties": {
"HttpMethod": "GET",
"RequestParameters": {},
"ResourceId": {
"Ref": "ApiGatewayResourceDemoError"
},
"RestApiId": {
"Ref": "ApiGatewayRestApi"
},
"ApiKeyRequired": false,
"AuthorizationType": "NONE",
"Integration": {
"IntegrationHttpMethod": "POST",
"Type": "AWS_PROXY",
"Uri": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":apigateway:",
{
"Ref": "AWS::Region"
},
":lambda:path/2015-03-31/functions/",
{
"Fn::GetAtt": [
"ErrorLambdaFunction",
"Arn"
]
},
"/invocations"
]
]
}
},
"MethodResponses": []
}
},
"ApiGatewayDeployment1536766421374": {
"Type": "AWS::ApiGateway::Deployment",
"Properties": {
"RestApiId": {
"Ref": "ApiGatewayRestApi"
},
"StageName": "dev"
},
"DependsOn": [
"ApiGatewayMethodDemoServiceDashaGet",
"ApiGatewayMethodDemoServiceDashbGet",
"ApiGatewayMethodDemoTimeoutGet",
"ApiGatewayMethodDemoErrorGet"
]
},
"ServiceDashaLambdaPermissionApiGateway": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"FunctionName": {
"Fn::GetAtt": [
"ServiceDashaLambdaFunction",
"Arn"
]
},
"Action": "lambda:InvokeFunction",
"Principal": {
"Fn::Join": [
"",
[
"apigateway.",
{
"Ref": "AWS::URLSuffix"
}
]
]
},
"SourceArn": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":execute-api:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":",
{
"Ref": "ApiGatewayRestApi"
},
"/*/*"
]
]
}
}
},
"ServiceDashbLambdaPermissionApiGateway": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"FunctionName": {
"Fn::GetAtt": [
"ServiceDashbLambdaFunction",
"Arn"
]
},
"Action": "lambda:InvokeFunction",
"Principal": {
"Fn::Join": [
"",
[
"apigateway.",
{
"Ref": "AWS::URLSuffix"
}
]
]
},
"SourceArn": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":execute-api:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":",
{
"Ref": "ApiGatewayRestApi"
},
"/*/*"
]
]
}
}
},
"TimeoutLambdaPermissionApiGateway": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"FunctionName": {
"Fn::GetAtt": [
"TimeoutLambdaFunction",
"Arn"
]
},
"Action": "lambda:InvokeFunction",
"Principal": {
"Fn::Join": [
"",
[
"apigateway.",
{
"Ref": "AWS::URLSuffix"
}
]
]
},
"SourceArn": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":execute-api:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":",
{
"Ref": "ApiGatewayRestApi"
},
"/*/*"
]
]
}
}
},
"ErrorLambdaPermissionApiGateway": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"FunctionName": {
"Fn::GetAtt": [
"ErrorLambdaFunction",
"Arn"
]
},
"Action": "lambda:InvokeFunction",
"Principal": {
"Fn::Join": [
"",
[
"apigateway.",
{
"Ref": "AWS::URLSuffix"
}
]
]
},
"SourceArn": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":execute-api:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":",
{
"Ref": "ApiGatewayRestApi"
},
"/*/*"
]
]
}
}
},
"SNSTopicServerlessobservabilitydev": {
"Type": "AWS::SNS::Topic",
"Properties": {
"TopicName": "serverless-observability-dev",
"DisplayName": "serverless-observability-dev",
"Subscription": [
{
"Endpoint": {
"Fn::GetAtt": [
"ServiceDashreadDashsnsLambdaFunction",
"Arn"
]
},
"Protocol": "lambda"
},
{
"Endpoint": {
"Fn::GetAtt": [
"SnsLambdaFunction",
"Arn"
]
},
"Protocol": "lambda"
}
]
}
},
"ServiceDashreadDashsnsLambdaPermissionServerlessobservabilitydevSNS": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"FunctionName": {
"Fn::GetAtt": [
"ServiceDashreadDashsnsLambdaFunction",
"Arn"
]
},
"Action": "lambda:InvokeFunction",
"Principal": {
"Fn::Join": [
"",
[
"sns.",
{
"Ref": "AWS::URLSuffix"
}
]
]
},
"SourceArn": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":sns:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":",
"serverless-observability-dev"
]
]
}
}
},
"SnsLambdaPermissionServerlessobservabilitydevSNS": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"FunctionName": {
"Fn::GetAtt": [
"SnsLambdaFunction",
"Arn"
]
},
"Action": "lambda:InvokeFunction",
"Principal": {
"Fn::Join": [
"",
[
"sns.",
{
"Ref": "AWS::URLSuffix"
}
]
]
},
"SourceArn": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":sns:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":",
"serverless-observability-dev"
]
]
}
}
},
"ServiceDashreadDashdynamoEventSourceMappingDynamodbDynamoDB": {
"Type": "AWS::Lambda::EventSourceMapping",
"DependsOn": "IamRoleLambdaExecution",
"Properties": {
"BatchSize": 10,
"EventSourceArn": {
"Fn::GetAtt": [
"DynamoDB",
"StreamArn"
]
},
"FunctionName": {
"Fn::GetAtt": [
"ServiceDashreadDashdynamoLambdaFunction",
"Arn"
]
},
"StartingPosition": "TRIM_HORIZON",
"Enabled": "True"
}
},
"DynamoDB": {
"Type": "AWS::DynamoDB::Table",
"Properties": {
"TableName": "serverless-observability-dev",
"AttributeDefinitions": [
{
"AttributeName": "id",
"AttributeType": "S"
}
],
"KeySchema": [
{
"AttributeName": "id",
"KeyType": "HASH"
}
],
"ProvisionedThroughput": {
"ReadCapacityUnits": 1,
"WriteCapacityUnits": 1
},
"StreamSpecification": {
"StreamViewType": "NEW_AND_OLD_IMAGES"
}
}
}
},
"Outputs": {
"ServerlessDeploymentBucketName": {
"Value": {
"Ref": "ServerlessDeploymentBucket"
}
},
"ServiceEndpoint": {
"Description": "URL of the service endpoint",
"Value": {
"Fn::Join": [
"",
[
"https://",
{
"Ref": "ApiGatewayRestApi"
},
{
"Fn::Sub": ".execute-api.${AWS::Region}."
},
{
"Ref": "AWS::URLSuffix"
},
"/dev"
]
]
}
}
}
}
Terraform
data "aws_iam_role" "role" {
name = "example-role"
}
resource "aws_api_gateway_rest_api" "api" {
name = "example-api"
}
resource "aws_api_gateway_resource" "resource" {
rest_api_id = "${aws_api_gateway_rest_api.api.id}"
parent_id = "${aws_api_gateway_rest_api.api.root_resource_id}"
path_part = "example-resource"
}
resource "aws_lambda_function" "function" {
filename = "example-zip-file-name.zip"
function_name = "example-function-name"
role = "${aws_iam_role.role.arn}"
handler = "src/example-file-name.handler"
source_code_hash = "${base64sha256(file("example-zip-file-name.zip"))}"
runtime = "nodejs6.10"
environment {
variables {
some_variable = "some_value"
}
}
}
module "serverless" {
source = "salte-io/serverless/aws"
version = "1.0.0"
api_id = "${aws_api_gateway_rest_api.api.id}"
resource_id = "${aws_api_gateway_resource.resource.id}"
http_method = "GET"
function_name = "${aws_lambda_function.function.function_name}"
invoke_arn = "${aws_lambda_function.function.invoke_arn}"
}
AWS SERVERless application model
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: 'SAM template for Serverless framework service: '
Resources:
DynamoDB:
Type: 'AWS::DynamoDB::Table'
Properties:
TableName: serverless-observability-dev
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
StreamSpecification:
StreamViewType: NEW_AND_OLD_IMAGES
ServiceA:
Type: 'AWS::Serverless::Function'
Properties:
Handler: functions/service-a.handler
Runtime: nodejs8.10
CodeUri: >-
/home/vgaltes/Study/Serverless/serverless-observabiilty/.serverless/serverless-observability.zip
MemorySize: 128
Timeout: 10
Policies:
- Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 'dynamodb:PutItem'
- 'dynamodb:GetItem'
- 'dynamodb:DescribeStream'
- 'dynamodb:GetRecords'
- 'dynamodb:GetShardIterator'
- 'dynamodb:ListStreams'
Resource:
- >-
arn:aws:dynamodb:us-east-1:*:table/serverless-observability-dev
- Effect: Allow
Action:
- 's3:GetObject*'
- 's3:PutObject*'
- 's3:ListBucket*'
- 's3:PutBucketNotification'
Resource:
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}/*
- Effect: Allow
Action:
- 'sns:Publish'
- 'sns:Subscribe'
Resource:
- 'arn:aws:sns:us-east-1:*:serverless-observability-dev'
- Effect: Allow
Action:
- 'lambda:InvokeFunction'
Resource:
- >-
arn:aws:lambda:us-east-1:*:function:serverless-observability-dev-*
Environment:
Variables:
stage: dev
service: serverless-observability
accountId:
Ref: 'AWS::AccountId'
BUCKET_NAME: 'serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}'
Events:
Event1:
Type: Api
Properties:
Path: /demo/service-a
Method: get
RestApiId:
Ref: ServerlessObservability
ServerlessObservability:
Type: 'AWS::Serverless::Api'
Properties:
StageName: dev
DefinitionBody:
swagger: '2.0'
info:
title:
Ref: 'AWS::StackName'
paths:
/demo/service-a:
get:
x-amazon-apigateway-integration:
httpMethod: POST
type: aws_proxy
uri:
'Fn::Sub': >-
arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ServiceA.Arn}/invocations
responses: {}
/demo/service-b:
get:
x-amazon-apigateway-integration:
httpMethod: POST
type: aws_proxy
uri:
'Fn::Sub': >-
arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ServiceB.Arn}/invocations
responses: {}
/demo/timeout:
get:
x-amazon-apigateway-integration:
httpMethod: POST
type: aws_proxy
uri:
'Fn::Sub': >-
arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Timeout.Arn}/invocations
responses: {}
/demo/error:
get:
x-amazon-apigateway-integration:
httpMethod: POST
type: aws_proxy
uri:
'Fn::Sub': >-
arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Error.Arn}/invocations
responses: {}
ServiceALambdaPermission:
Type: 'AWS::Lambda::Permission'
DependsOn:
- ServiceA
Properties:
Action: 'lambda:InvokeFunction'
FunctionName:
Ref: ServiceA
Principal: apigateway.amazonaws.com
ServiceB:
Type: 'AWS::Serverless::Function'
Properties:
Handler: functions/service-b.handler
Runtime: nodejs8.10
CodeUri: >-
/home/vgaltes/Study/Serverless/serverless-observabiilty/.serverless/serverless-observability.zip
MemorySize: 128
Timeout: 3
Policies:
- Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 'dynamodb:PutItem'
- 'dynamodb:GetItem'
- 'dynamodb:DescribeStream'
- 'dynamodb:GetRecords'
- 'dynamodb:GetShardIterator'
- 'dynamodb:ListStreams'
Resource:
- >-
arn:aws:dynamodb:us-east-1:*:table/serverless-observability-dev
- Effect: Allow
Action:
- 's3:GetObject*'
- 's3:PutObject*'
- 's3:ListBucket*'
- 's3:PutBucketNotification'
Resource:
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}/*
- Effect: Allow
Action:
- 'sns:Publish'
- 'sns:Subscribe'
Resource:
- 'arn:aws:sns:us-east-1:*:serverless-observability-dev'
- Effect: Allow
Action:
- 'lambda:InvokeFunction'
Resource:
- >-
arn:aws:lambda:us-east-1:*:function:serverless-observability-dev-*
Environment:
Variables:
stage: dev
service: serverless-observability
accountId:
Ref: 'AWS::AccountId'
Events:
Event1:
Type: Api
Properties:
Path: /demo/service-b
Method: get
RestApiId:
Ref: ServerlessObservability
ServiceBLambdaPermission:
Type: 'AWS::Lambda::Permission'
DependsOn:
- ServiceB
Properties:
Action: 'lambda:InvokeFunction'
FunctionName:
Ref: ServiceB
Principal: apigateway.amazonaws.com
ServiceC:
Type: 'AWS::Serverless::Function'
Properties:
Handler: functions/service-c.handler
Runtime: nodejs8.10
CodeUri: >-
/home/vgaltes/Study/Serverless/serverless-observabiilty/.serverless/serverless-observability.zip
MemorySize: 128
Timeout: 3
Policies:
- Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 'dynamodb:PutItem'
- 'dynamodb:GetItem'
- 'dynamodb:DescribeStream'
- 'dynamodb:GetRecords'
- 'dynamodb:GetShardIterator'
- 'dynamodb:ListStreams'
Resource:
- >-
arn:aws:dynamodb:us-east-1:*:table/serverless-observability-dev
- Effect: Allow
Action:
- 's3:GetObject*'
- 's3:PutObject*'
- 's3:ListBucket*'
- 's3:PutBucketNotification'
Resource:
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}/*
- Effect: Allow
Action:
- 'sns:Publish'
- 'sns:Subscribe'
Resource:
- 'arn:aws:sns:us-east-1:*:serverless-observability-dev'
- Effect: Allow
Action:
- 'lambda:InvokeFunction'
Resource:
- >-
arn:aws:lambda:us-east-1:*:function:serverless-observability-dev-*
Environment:
Variables:
stage: dev
service: serverless-observability
accountId:
Ref: 'AWS::AccountId'
ServiceReadSns:
Type: 'AWS::Serverless::Function'
Properties:
Handler: functions/service-read-sns.handler
Runtime: nodejs8.10
CodeUri: >-
/home/vgaltes/Study/Serverless/serverless-observabiilty/.serverless/serverless-observability.zip
MemorySize: 128
Timeout: 3
Policies:
- Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 'dynamodb:PutItem'
- 'dynamodb:GetItem'
- 'dynamodb:DescribeStream'
- 'dynamodb:GetRecords'
- 'dynamodb:GetShardIterator'
- 'dynamodb:ListStreams'
Resource:
- >-
arn:aws:dynamodb:us-east-1:*:table/serverless-observability-dev
- Effect: Allow
Action:
- 's3:GetObject*'
- 's3:PutObject*'
- 's3:ListBucket*'
- 's3:PutBucketNotification'
Resource:
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}/*
- Effect: Allow
Action:
- 'sns:Publish'
- 'sns:Subscribe'
Resource:
- 'arn:aws:sns:us-east-1:*:serverless-observability-dev'
- Effect: Allow
Action:
- 'lambda:InvokeFunction'
Resource:
- >-
arn:aws:lambda:us-east-1:*:function:serverless-observability-dev-*
Environment:
Variables:
stage: dev
service: serverless-observability
accountId:
Ref: 'AWS::AccountId'
Events:
Event1:
Type: SNS
Properties:
Topic: ''
ServerlessObservabilitySnsTopicQVJUw:
Type: 'AWS::SNS::Topic'
Properties:
TopicName:
topicName: serverless-observability-dev
displayName: serverless-observability-dev
DisplayName: serverless-observability-dev
ServiceReadDynamo:
Type: 'AWS::Serverless::Function'
Properties:
Handler: functions/service-read-dynamo.handler
Runtime: nodejs8.10
CodeUri: >-
/home/vgaltes/Study/Serverless/serverless-observabiilty/.serverless/serverless-observability.zip
MemorySize: 128
Timeout: 3
Policies:
- Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 'dynamodb:PutItem'
- 'dynamodb:GetItem'
- 'dynamodb:DescribeStream'
- 'dynamodb:GetRecords'
- 'dynamodb:GetShardIterator'
- 'dynamodb:ListStreams'
Resource:
- >-
arn:aws:dynamodb:us-east-1:*:table/serverless-observability-dev
- Effect: Allow
Action:
- 's3:GetObject*'
- 's3:PutObject*'
- 's3:ListBucket*'
- 's3:PutBucketNotification'
Resource:
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}/*
- Effect: Allow
Action:
- 'sns:Publish'
- 'sns:Subscribe'
Resource:
- 'arn:aws:sns:us-east-1:*:serverless-observability-dev'
- Effect: Allow
Action:
- 'lambda:InvokeFunction'
Resource:
- >-
arn:aws:lambda:us-east-1:*:function:serverless-observability-dev-*
Environment:
Variables:
stage: dev
service: serverless-observability
accountId:
Ref: 'AWS::AccountId'
Events:
Event1:
Type: Dynamodb
Properties:
Stream:
'Fn::GetAtt':
- DynamoDB
- StreamArn
ServiceReadS3:
Type: 'AWS::Serverless::Function'
Properties:
Handler: functions/service-read-s3.handler
Runtime: nodejs8.10
CodeUri: >-
/home/vgaltes/Study/Serverless/serverless-observabiilty/.serverless/serverless-observability.zip
MemorySize: 128
Timeout: 3
Policies:
- Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 'dynamodb:PutItem'
- 'dynamodb:GetItem'
- 'dynamodb:DescribeStream'
- 'dynamodb:GetRecords'
- 'dynamodb:GetShardIterator'
- 'dynamodb:ListStreams'
Resource:
- >-
arn:aws:dynamodb:us-east-1:*:table/serverless-observability-dev
- Effect: Allow
Action:
- 's3:GetObject*'
- 's3:PutObject*'
- 's3:ListBucket*'
- 's3:PutBucketNotification'
Resource:
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}/*
- Effect: Allow
Action:
- 'sns:Publish'
- 'sns:Subscribe'
Resource:
- 'arn:aws:sns:us-east-1:*:serverless-observability-dev'
- Effect: Allow
Action:
- 'lambda:InvokeFunction'
Resource:
- >-
arn:aws:lambda:us-east-1:*:function:serverless-observability-dev-*
Environment:
Variables:
stage: dev
service: serverless-observability
accountId:
Ref: 'AWS::AccountId'
Events:
Event1:
Type: S3
Properties:
Bucket: 'serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}'
Events: '*'
Timeout:
Type: 'AWS::Serverless::Function'
Properties:
Handler: functions/timeout.handler
Runtime: nodejs8.10
CodeUri: >-
/home/vgaltes/Study/Serverless/serverless-observabiilty/.serverless/serverless-observability.zip
MemorySize: 128
Timeout: 1
Policies:
- Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 'dynamodb:PutItem'
- 'dynamodb:GetItem'
- 'dynamodb:DescribeStream'
- 'dynamodb:GetRecords'
- 'dynamodb:GetShardIterator'
- 'dynamodb:ListStreams'
Resource:
- >-
arn:aws:dynamodb:us-east-1:*:table/serverless-observability-dev
- Effect: Allow
Action:
- 's3:GetObject*'
- 's3:PutObject*'
- 's3:ListBucket*'
- 's3:PutBucketNotification'
Resource:
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}/*
- Effect: Allow
Action:
- 'sns:Publish'
- 'sns:Subscribe'
Resource:
- 'arn:aws:sns:us-east-1:*:serverless-observability-dev'
- Effect: Allow
Action:
- 'lambda:InvokeFunction'
Resource:
- >-
arn:aws:lambda:us-east-1:*:function:serverless-observability-dev-*
Environment:
Variables:
stage: dev
service: serverless-observability
accountId:
Ref: 'AWS::AccountId'
Events:
Event1:
Type: Api
Properties:
Path: /demo/timeout
Method: get
RestApiId:
Ref: ServerlessObservability
TimeoutLambdaPermission:
Type: 'AWS::Lambda::Permission'
DependsOn:
- Timeout
Properties:
Action: 'lambda:InvokeFunction'
FunctionName:
Ref: Timeout
Principal: apigateway.amazonaws.com
Error:
Type: 'AWS::Serverless::Function'
Properties:
Handler: functions/error.handler
Runtime: nodejs8.10
CodeUri: >-
/home/vgaltes/Study/Serverless/serverless-observabiilty/.serverless/serverless-observability.zip
MemorySize: 128
Timeout: 3
Policies:
- Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 'dynamodb:PutItem'
- 'dynamodb:GetItem'
- 'dynamodb:DescribeStream'
- 'dynamodb:GetRecords'
- 'dynamodb:GetShardIterator'
- 'dynamodb:ListStreams'
Resource:
- >-
arn:aws:dynamodb:us-east-1:*:table/serverless-observability-dev
- Effect: Allow
Action:
- 's3:GetObject*'
- 's3:PutObject*'
- 's3:ListBucket*'
- 's3:PutBucketNotification'
Resource:
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}/*
- Effect: Allow
Action:
- 'sns:Publish'
- 'sns:Subscribe'
Resource:
- 'arn:aws:sns:us-east-1:*:serverless-observability-dev'
- Effect: Allow
Action:
- 'lambda:InvokeFunction'
Resource:
- >-
arn:aws:lambda:us-east-1:*:function:serverless-observability-dev-*
Environment:
Variables:
stage: dev
service: serverless-observability
accountId:
Ref: 'AWS::AccountId'
Events:
Event1:
Type: Api
Properties:
Path: /demo/error
Method: get
RestApiId:
Ref: ServerlessObservability
ErrorLambdaPermission:
Type: 'AWS::Lambda::Permission'
DependsOn:
- Error
Properties:
Action: 'lambda:InvokeFunction'
FunctionName:
Ref: Error
Principal: apigateway.amazonaws.com
Sns:
Type: 'AWS::Serverless::Function'
Properties:
Handler: functions/sns.handler
Runtime: nodejs8.10
CodeUri: >-
/home/vgaltes/Study/Serverless/serverless-observabiilty/.serverless/serverless-observability.zip
MemorySize: 128
Timeout: 3
Policies:
- Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 'dynamodb:PutItem'
- 'dynamodb:GetItem'
- 'dynamodb:DescribeStream'
- 'dynamodb:GetRecords'
- 'dynamodb:GetShardIterator'
- 'dynamodb:ListStreams'
Resource:
- >-
arn:aws:dynamodb:us-east-1:*:table/serverless-observability-dev
- Effect: Allow
Action:
- 's3:GetObject*'
- 's3:PutObject*'
- 's3:ListBucket*'
- 's3:PutBucketNotification'
Resource:
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}
- >-
arn:aws:s3:::serverless-observability-dev-#{AWS::Region}-#{AWS::AccountId}/*
- Effect: Allow
Action:
- 'sns:Publish'
- 'sns:Subscribe'
Resource:
- 'arn:aws:sns:us-east-1:*:serverless-observability-dev'
- Effect: Allow
Action:
- 'lambda:InvokeFunction'
Resource:
- >-
arn:aws:lambda:us-east-1:*:function:serverless-observability-dev-*
Environment:
Variables:
stage: dev
service: serverless-observability
accountId:
Ref: 'AWS::AccountId'
Events:
Event1:
Type: SNS
Properties:
Topic: ''
ServerlessObservabilitySnsTopicOJtJm:
Type: 'AWS::SNS::Topic'
Properties:
TopicName:
topicName: serverless-observability-dev
displayName: serverless-observability-dev
DisplayName: serverless-observability-dev

SERVERLESS FRAMEWORK
service: serverless-observability
plugins:
- serverless-pseudo-parameters
- serverless-plugin-existing-s3
custom:
bucketName: serverless-observability-${self:provider.stage}-#{AWS::Region}-#{AWS::AccountId}
provider:
name: aws
runtime: nodejs8.10
stage: dev
region: us-east-1
versionFunctions: false
environment:
stage: ${self:provider.stage}
service: ${self:service}
accountId:
Ref: AWS::AccountId
iamRoleStatements:
- Effect: "Allow"
Action:
- "dynamodb:PutItem"
- "dynamodb:GetItem"
- "dynamodb:DescribeStream"
- "dynamodb:GetRecords"
- "dynamodb:GetShardIterator"
- "dynamodb:ListStreams"
Resource:
- "arn:aws:dynamodb:${self:provider.region}:*:table/serverless-observability-${self:provider.stage}"
- Effect: "Allow"
Action:
- "s3:GetObject*"
- "s3:PutObject*"
- "s3:ListBucket*"
- "s3:PutBucketNotification"
Resource:
- "arn:aws:s3:::${self:custom.bucketName}"
- "arn:aws:s3:::${self:custom.bucketName}/*"
- Effect: "Allow"
Action:
- "sns:Publish"
- "sns:Subscribe"
Resource:
- "arn:aws:sns:${self:provider.region}:*:serverless-observability-${self:provider.stage}"
- Effect: "Allow"
Action:
- "lambda:InvokeFunction"
Resource:
- "arn:aws:lambda:${self:provider.region}:*:function:serverless-observability-${self:provider.stage}-*"
functions:
service-a:
handler: functions/service-a.handler
timeout: 10
events:
- http:
path: demo/service-a
method: get
request:
parameters:
querystrings:
n: true
environment:
BUCKET_NAME: ${self:custom.bucketName}
service-b:
handler: functions/service-b.handler
events:
- http:
path: demo/service-b
method: get
service-c:
handler: functions/service-c.handler
service-read-sns:
handler: functions/service-read-sns.handler
events:
- sns:
topicName: "serverless-observability-${self:provider.stage}"
displayName: "serverless-observability-${self:provider.stage}"
service-read-dynamo:
handler: functions/service-read-dynamo.handler
events:
- stream:
type: dynamodb
arn:
Fn::GetAtt:
- DynamoDB
- StreamArn
service-read-s3:
handler: functions/service-read-s3.handler
events:
- s3:
bucket: ${self:custom.bucketName}
timeout:
handler: functions/timeout.handler
timeout: 1
events:
- http:
path: demo/timeout
method: get
error:
handler: functions/error.handler
events:
- http:
path: demo/error
method: get
sns:
handler: functions/sns.handler
events:
- sns:
topicName: ${self:service}-${self:provider.stage}
displayName: ${self:service}-${self:provider.stage}
# you can add CloudFormation resource templates here
resources:
Resources:
# S3Bucket:
# Type: AWS::S3::Bucket
# Properties:
# BucketName: ${self:custom.bucketName}
DynamoDB:
Type: AWS::DynamoDB::Table
Properties:
TableName: serverless-observability-${self:provider.stage}
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
StreamSpecification:
StreamViewType: NEW_AND_OLD_IMAGES

PULUMI
// Copyright 2016-2018, Pulumi Corporation. All rights reserved.
const cloud = require("@pulumi/cloud-aws");
// A bucket to store videos and thumbnails.
const bucket = new cloud.Bucket("bucket");
const bucketName = bucket.bucket.id;
// A task which runs a containerized FFMPEG job to extract a thumbnail image.
const ffmpegThumbnailTask = new cloud.Task("ffmpegThumbTask", {
build: "./docker-ffmpeg-thumb",
memoryReservation: 512,
});
// When a new video is uploaded, run the FFMPEG task on the video file.
// Use the time index specified in the filename (e.g. cat_00-01.mp4 uses timestamp 00:01)
bucket.onPut("onNewVideo", bucketArgs => {
console.log(`*** New video: file ${bucketArgs.key} was uploaded at ${bucketArgs.eventTime}.`);
const file = bucketArgs.key;
const thumbnailFile = file.substring(0, file.indexOf('_')) + '.jpg';
const framePos = file.substring(file.indexOf('_')+1, file.indexOf('.')).replace('-',':');
ffmpegThumbnailTask.run({
environment: {
"S3_BUCKET": bucketName.get(),
"INPUT_VIDEO": file,
"TIME_OFFSET": framePos,
"OUTPUT_FILE": thumbnailFile,
},
}).then(() => {
console.log(`Running thumbnailer task.`);
});
}, { keySuffix: ".mp4" });
// When a new thumbnail is created, log a message.
bucket.onPut("onNewThumbnail", bucketArgs => {
console.log(`*** New thumbnail: file ${bucketArgs.key} was saved at ${bucketArgs.eventTime}.`);
return Promise.resolve();
}, { keySuffix: ".jpg" });
// Export the bucket name.
exports.bucketName = bucketName;

STACKERY

OTHER TOOLS
- Claudia JS
- Apex
- Sparta
- A million more...

AWS CLOUD DEVELOPMENT KIT

APP SYNC

SHARING RESOURCES
automate and enable low risk releases

TECHNICAL PRACTICES OF FEEDBACK


OBSERVABILITY
- Monitoring
- Alerting and visualization
- Distributed systems tracing infrastructure
- Log aggregation
CHALLENGES
- No access to the underlying infrastructure
- Timing
- Concurrency
- Platform limitations

WHAT AWS OFFERS

GENERAL PURPOSE SOLUTIONS



SERVERLESS SPECIFIC SOLUTIONS





TECHNICAL PRACTICES OF CONTINUAL LEARNING AND EXPERIMENTATION


chaos engineering
"Limited scope, continuous, disaster recovery"

CHAOS MONKEY & SERVERLESS

actionable failure modes
- Improperly tuned timeouts
- Missing error handling
- Missing fallbacks for when a downstream service is unavailable
SECURITY


SUMMARY
| TESTING | |
| CONTINUOUS INTEGRATION | |
| DEPLOYMENT PIPELINE | |
| LOW-RISK RELEASES | |
| OBSERVABILITY | |
| CHAOS ENGINEERING |



MORE INFO
Donostia 9 y 10 de Mayo
theserverelesscourse.com
info@vgaltes.com
THANK YOU!
Vicenç García Altés
@vgaltes
theserverlesscourse.com
info@vgaltes.com

Operational Serverles
By Vicenç Garcia
Operational Serverles
- 841