Skip to content

Commit

Permalink
Merge pull request #8 from gunnargrosch/develop
Browse files Browse the repository at this point in the history
Blacklist failure feature
  • Loading branch information
gunnargrosch authored Feb 17, 2020
2 parents a45dec3 + e2cf89a commit afce4eb
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 14 deletions.
20 changes: 14 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Description

`failure-lambda` is a small Node module for injecting failure into AWS Lambda (https://aws.amazon.com/lambda). It offers a simple failure injection wrapper for your Lambda handler where you then can choose to inject failure by setting the `failureMode` to `latency`, `exception`, `statuscode` or `diskspace`. You control your failure injection using SSM Parameter Store.
`failure-lambda` is a small Node module for injecting failure into AWS Lambda (https://aws.amazon.com/lambda). It offers a simple failure injection wrapper for your Lambda handler where you then can choose to inject failure by setting the `failureMode` to `latency`, `exception`, `blacklist`, `diskspace` or `statuscode`. You control your failure injection using SSM Parameter Store.

## How to install

Expand All @@ -22,10 +22,10 @@ exports.handler = failureLambda(async (event, context) => {
```
4. Create a parameter in SSM Parameter Store.
```json
{"isEnabled": false, "failureMode": "latency", "rate": 1, "minLatency": 100, "maxLatency": 400, "exceptionMsg": "Exception message!", "statusCode": 404, "diskSpace": 100}
{"isEnabled": false, "failureMode": "latency", "rate": 1, "minLatency": 100, "maxLatency": 400, "exceptionMsg": "Exception message!", "statusCode": 404, "diskSpace": 100, "blacklist": ["s3.*.amazonaws.com", "dynamodb.*.amazonaws.com"]}
```
```bash
aws ssm put-parameter --region eu-north-1 --name failureLambdaConfig --type String --overwrite --value "{\"isEnabled\": false, \"failureMode\": \"latency\", \"rate\": 1, \"minLatency\": 100, \"maxLatency\": 400, \"exceptionMsg\": \"Exception message!\", \"statusCode\": 404, \"diskSpace\": 100}"
aws ssm put-parameter --region eu-west-1 --name failureLambdaConfig --type String --overwrite --value "{\"isEnabled\": false, \"failureMode\": \"latency\", \"rate\": 1, \"minLatency\": 100, \"maxLatency\": 400, \"exceptionMsg\": \"Exception message!\", \"statusCode\": 404, \"diskSpace\": 100, \"blacklist\": [\"s3.*.amazonaws.com\", \"dynamodb.*.amazonaws.com\"]}"
```
5. Add an environment variable to your Lambda function with the key FAILURE_INJECTION_PARAM and the value set to the name of your parameter in SSM Parameter Store.
6. Try it out!
Expand All @@ -36,12 +36,13 @@ Edit the values of your parameter in SSM Parameter Store to use the failure inje

* `isEnabled: true` means that failure is injected into your Lambda function.
* `isEnabled: false` means that the failure injection module is disabled and no failure is injected.
* `failureMode` selects which failure you want to inject. The options are `latency`, `exception` or `statuscode` as explained below.
* `failureMode` selects which failure you want to inject. The options are `latency`, `exception`, `blacklist`, `diskspace` or `statuscode` as explained below.
* `rate` controls the rate of failure. 1 means that failure is injected on all invocations and 0.5 that failure is injected on about half of all invocations.
* `minLatency` and `maxLatency` is the span of latency in milliseconds injected into your function when `failureMode` is set to `latency`.
* `exceptionMsg` is the message thrown with the exception created when `failureMode` is set to `exception`.
* `statusCode` is the status code returned by your function when `failureMode` is set to `statuscode`.
* `diskSpace` is size in MB of the file created in tmp when `failureMode` is set to `diskspace`.
* `blacklist` is an array of regular expressions, if a connection is made to a host matching one of the regular expressions it will be blocked.

## Example

Expand All @@ -57,9 +58,14 @@ Inspired by Yan Cui's articles on latency injection for AWS Lambda (https://hack

## Changelog

### 2020-02-17 v0.2.0

* Added blacklist failure.
* Updated example application to retrive file from S3 based on URL from DynamoDB.

### 2020-02-13 v0.1.1

* Fixed issue with exception injection not throwing the exception. Thanks to [Jason Barto](https://github.com/jpbarto)!
* Fixed issue with exception injection not throwing the exception.

### 2019-12-30 v0.1.0

Expand All @@ -70,6 +76,8 @@ Inspired by Yan Cui's articles on latency injection for AWS Lambda (https://hack

* Initial release

## Authors
## Contributors

**Gunnar Grosch** - [GitHub](https://github.com/gunnargrosch) | [Twitter](https://twitter.com/gunnargrosch) | [LinkedIn](https://www.linkedin.com/in/gunnargrosch/)

**Jason Barto** - [GitHub](https://github.com/jpbarto) | [Twitter](https://twitter.com/Jason_Barto) | [LinkedIn](https://www.linkedin.com/in/jasonbarto)
27 changes: 25 additions & 2 deletions example/index.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,40 @@
'use strict'
const failureLambda = require('failure-lambda')
const fs = require('fs')
const AWS = require('aws-sdk')
const s3 = new AWS.S3()
const dynamoDb = new AWS.DynamoDB.DocumentClient()
let response

exports.handler = failureLambda(async (event, context) => {
try {
fs.writeFile('/tmp/example-' + Date.now() + '.tmp', 'Contents', (err) => {
let fileName = Date.now() + '.tmp'
let contents = 'Hello failureLambda!'
fs.writeFile('/tmp/' + fileName, contents, (err) => {
if (err) throw err
})
let s3Params = {
Bucket: process.env.FAILURE_INJECTION_BUCKET,
Key: fileName,
Body: contents
}
s3.upload(s3Params, (err) => {
if (err) throw err
})
let ddbParams = {
TableName: process.env.FAILURE_INJECTION_TABLE,
Item: {
id: Date.now(),
contents: contents
}
}
dynamoDb.put(ddbParams, (err) => {
if (err) throw err
})
response = {
statusCode: 200,
body: JSON.stringify({
message: 'Hello failureLambda!'
message: contents
})
}
} catch (err) {
Expand Down
62 changes: 59 additions & 3 deletions example/serverless.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,53 @@ provider:
Action:
- ssm:GetParameters
- ssm:GetParameter
Resource: "arn:aws:ssm:${opt:region, self:provider.region}:*:parameter/${self:service}-${opt:stage, self:provider.stage}-failureLambdaExample"
Resource:
Fn::Join:
- ''
- - 'arn:aws:ssm:${opt:region, self:provider.region}:*:parameter/'
- Ref: failureLambdaParameter
- Effect: Allow
Action:
- s3:ListBucket
Resource:
Fn::Join:
- ''
- - 'arn:aws:s3:::'
- Ref: failureLambdaBucket
- Effect: Allow
Action:
- s3:GetObject
- s3:PutObject
Resource:
Fn::Join:
- ''
- - 'arn:aws:s3:::'
- Ref: failureLambdaBucket
- '/*'
- Effect: Allow
Action:
- dynamodb:Query
- dynamodb:Scan
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
Resource:
Fn::Join:
- ''
- - 'arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/'
- Ref: failureLambdaTable
functions:
failureLambdaExample:
handler: index.handler
timeout: 3
environment:
FAILURE_INJECTION_PARAM:
Ref: failureLambdaParameter
FAILURE_INJECTION_BUCKET:
Ref: failureLambdaBucket
FAILURE_INJECTION_TABLE:
Ref: failureLambdaTable
events:
- http:
path: failureLambdaExample/
Expand All @@ -27,9 +66,26 @@ resources:
failureLambdaParameter:
Type: 'AWS::SSM::Parameter'
Properties:
Name: ${self:service}-${opt:stage, self:provider.stage}-failureLambdaExample
Type: String
Value: '{"isEnabled": false, "failureMode": "latency", "rate": 1, "minLatency": 100, "maxLatency": 400, "exceptionMsg": "Exception message!", "statusCode": 404, "diskSpace": 100}'
Value: '{"isEnabled": false, "failureMode": "latency", "rate": 1, "minLatency": 100, "maxLatency": 400, "exceptionMsg": "Exception message!", "statusCode": 404, "diskSpace": 100, "blacklist": ["s3.*.amazonaws.com", "dynamodb.*.amazonaws.com"]}'
failureLambdaBucket:
Type: 'AWS::S3::Bucket'
Properties:
VersioningConfiguration:
Status: Suspended
failureLambdaTable:
Type: 'AWS::DynamoDB::Table'
DeletionPolicy: Delete
Properties:
AttributeDefinitions:
-
AttributeName: id
AttributeType: N
KeySchema:
-
AttributeName: id
KeyType: HASH
BillingMode: PAY_PER_REQUEST
package:
exclude:
- .vscode
Expand Down
22 changes: 22 additions & 0 deletions lib/failure.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
const aws = require('aws-sdk')
const ssm = new aws.SSM()
const childProcess = require('child_process')
const Mitm = require('mitm')

async function getConfig() {
try {
Expand Down Expand Up @@ -36,6 +37,27 @@ var injectFailure = function (fn) {
} else if (config.failureMode === 'diskspace') {
console.log('Injecting disk space: ' + config.diskSpace + ' MB')
childProcess.spawnSync('dd', ['if=/dev/zero', 'of=/tmp/diskspace-failure-' + Date.now() + '.tmp', 'count=1000', 'bs=' + config.diskSpace * 1000])
} else if (config.failureMode === 'blacklist') {
console.log('Injecting dependency failure through a network blackhole for blacklisted sites: ' + config.blacklist)
let mitm = Mitm()
let blRegexs = []
config.blacklist.forEach(function (regexStr) {
blRegexs.push(new RegExp(regexStr))
})
mitm.on('connect', function (socket, opts) {
let block = false
blRegexs.forEach(function (blRegex) {
if (blRegex.test(opts.host)) {
console.log('Intercepted network connection to ' + opts.host)
block = true
}
})
if (block) {
socket.end()
} else {
socket.bypass()
}
})
}
}
return fn.apply(this, arguments)
Expand Down
23 changes: 22 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "failure-lambda",
"version": "0.1.1",
"version": "0.2.0",
"description": "Module for failure injection into AWS Lambda",
"main": "./lib/failure.js",
"scripts": {
Expand Down Expand Up @@ -33,5 +33,7 @@
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.1"
},
"dependencies": {}
"dependencies": {
"mitm": "^1.7.0"
}
}

0 comments on commit afce4eb

Please sign in to comment.