aws-lambda-runner 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/js/package.json +24 -0
- data/js/request.js +60 -0
- data/js/startup.js +19 -0
- data/lib/lambda_runner.rb +100 -0
- data/lib/sample_req.json +37 -0
- data/lib/sample_sns_req.json +22 -0
- metadata +134 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0bcd4937c0e10b5e7a0601406c1eb22f36da5d85
|
4
|
+
data.tar.gz: 105b4d4144d2bd73de84bb9f50ce02e63087b0f2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 51002e44f87ac3d99a319a1495a62a936c00ea0cd1cc9fe8fb485d66e01a667f235a9eee4d9a1b45115e6963d8f2ffac4c084a74c08c134bb803673114e6e8a6
|
7
|
+
data.tar.gz: d650889fb646cce2254ab8c9a25a9a5e57584c41ef2cdd8bc94c086b522616301db56ef31103340b65193e00a9a35a60ee37834f2b1ba6dc36aca5309fa246d0
|
data/js/package.json
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
{
|
2
|
+
"name": "lambda-helper",
|
3
|
+
"version": "1.0.0",
|
4
|
+
"description": "",
|
5
|
+
"main": "startup.js",
|
6
|
+
"scripts": {
|
7
|
+
"test": "mocha"
|
8
|
+
},
|
9
|
+
"author": "",
|
10
|
+
"license": " ",
|
11
|
+
"devDependencies": {
|
12
|
+
"jshint": "^2.5.11",
|
13
|
+
"mocha": "^2.1.0",
|
14
|
+
"mocha-jshint": "0.0.9",
|
15
|
+
"mock-res": "^0.2.1",
|
16
|
+
"should": "^4.6.0"
|
17
|
+
},
|
18
|
+
"dependencies": {
|
19
|
+
"aws-sdk": "^2.1.34",
|
20
|
+
"istanbul": "^0.3.6",
|
21
|
+
"mock-req": "^0.1.0",
|
22
|
+
"stdio": "^0.2.7"
|
23
|
+
}
|
24
|
+
}
|
data/js/request.js
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
|
2
|
+
var url = require('url');
|
3
|
+
|
4
|
+
var next_id = 0;
|
5
|
+
var done = {};
|
6
|
+
var errors = {};
|
7
|
+
var timeout = {};
|
8
|
+
|
9
|
+
exports.request = function(req, res, opts, handler) {
|
10
|
+
if (req.method === 'POST') {
|
11
|
+
var id = next_id;
|
12
|
+
var output = '';
|
13
|
+
next_id += 1;
|
14
|
+
req.on('data', function(chunk) {
|
15
|
+
setTimeout(function() {
|
16
|
+
if (!done[id]) {
|
17
|
+
timeout[id] = true;
|
18
|
+
}
|
19
|
+
}, opts.timeout);
|
20
|
+
output += chunk.toString()
|
21
|
+
});
|
22
|
+
req.on('end', function(chunk) {
|
23
|
+
handler(JSON.parse(output), {
|
24
|
+
done: function(err, message) {
|
25
|
+
if (err) {
|
26
|
+
errors[id] = err;
|
27
|
+
console.warn('Error:', err);
|
28
|
+
}
|
29
|
+
console.info('Finished:', message);
|
30
|
+
done[id] = true;
|
31
|
+
}
|
32
|
+
});
|
33
|
+
});
|
34
|
+
res.writeHead(200, {'Content-Type': 'text/plain'});
|
35
|
+
res.end(String(id));
|
36
|
+
} else if (req.method === 'DELETE') {
|
37
|
+
res.writeHead(202, {'Content-Type': 'text/plain'});
|
38
|
+
var terminationMessage = 'Terminating server at http://[localhost]:' + opts.port + ' for ' + opts['module-path'] + ' / ' + opts.handler;
|
39
|
+
res.end(terminationMessage + '\n');
|
40
|
+
console.info(terminationMessage);
|
41
|
+
server.close();
|
42
|
+
} else if (req.method === 'GET') {
|
43
|
+
var request_id = parseInt(url.parse(req.url, true).query.id);
|
44
|
+
var status = 200;
|
45
|
+
var output = '';
|
46
|
+
if (timeout[request_id]) {
|
47
|
+
status = 504;
|
48
|
+
} else if (errors[request_id]) {
|
49
|
+
status = 502;
|
50
|
+
output = errors[request_id];
|
51
|
+
} else if (done[request_id]) {
|
52
|
+
status = 201;
|
53
|
+
}
|
54
|
+
res.writeHead(status, {'Content-Type': 'text/plain'});
|
55
|
+
res.end(output + '\n');
|
56
|
+
} else {
|
57
|
+
res.writeHead(500, {'Content-Type': 'text/plain'});
|
58
|
+
res.end('Not implemented: ' + req.method + '\n');
|
59
|
+
}
|
60
|
+
};
|
data/js/startup.js
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
var http = require('http');
|
4
|
+
var stdio = require('stdio');
|
5
|
+
var request = require('./request.js');
|
6
|
+
|
7
|
+
var opts = stdio.getopt({
|
8
|
+
'port': {mandatory: true, args: 1, key: 'p', description: 'Listen port'},
|
9
|
+
'module-path': {mandatory: true, args: 1, key: 'm', description: 'Path to the lambda module'},
|
10
|
+
'handler': {mandatory: true, args: 1, key: 'h', description: 'handler function to call'},
|
11
|
+
'timeout': {mandatory: true, args: 1, key: 't', description: 'timeout for handler function'}
|
12
|
+
});
|
13
|
+
console.info(opts);
|
14
|
+
|
15
|
+
var module = require(opts['module-path']);
|
16
|
+
var server = http.createServer(function (req, res) {
|
17
|
+
request.request(req, res, opts, module[opts.handler]);
|
18
|
+
}).listen(opts.port);
|
19
|
+
console.info('Server running at http://[localhost]:' + opts.port + ' for ' + opts['module-path'] + ' / ' + opts.handler);
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'process-helper'
|
2
|
+
require 'rest-client'
|
3
|
+
require 'json'
|
4
|
+
require 'English'
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
def load_json(name)
|
8
|
+
File.open(File.join(File.dirname(__FILE__), name)) { |file| return JSON.load(file) }
|
9
|
+
end
|
10
|
+
|
11
|
+
# runs a nodejs lambda program so the s3 events can be sent to it via http post
|
12
|
+
module LambdaRunner
|
13
|
+
# abstract for running the program
|
14
|
+
class Runner
|
15
|
+
def initialize(module_path, name)
|
16
|
+
@module_path = module_path
|
17
|
+
@name = name
|
18
|
+
@port = 8897
|
19
|
+
end
|
20
|
+
|
21
|
+
def install_deps
|
22
|
+
@npm_cwd = File.expand_path('../../js/', __FILE__)
|
23
|
+
STDOUT.puts("trying to use npm install in #{@npm_cwd}")
|
24
|
+
npm_install_pid = spawn('npm', 'install', chdir: @npm_cwd)
|
25
|
+
Process.wait(npm_install_pid)
|
26
|
+
fail 'failed to install the lambda startup' if ($CHILD_STATUS.exitstatus != 0)
|
27
|
+
end
|
28
|
+
|
29
|
+
def add_aws_sdk
|
30
|
+
STDOUT.puts("Copying aws-sdk into the lambda function's node_modules.")
|
31
|
+
# cp -r File.expand_path(../../js/node_modules/aws-sdk, __FILE__) $(dirname @module_path)/node_modules
|
32
|
+
FileUtils.cp_r File.expand_path('../../js/node_modules/aws-sdk', __FILE__), "#{File.dirname(@module_path)}/node_modules"
|
33
|
+
end
|
34
|
+
|
35
|
+
def start(opts = { cover: true })
|
36
|
+
install_deps
|
37
|
+
add_aws_sdk
|
38
|
+
# start node in a way that emulates how it's run in production
|
39
|
+
cmd = ['node']
|
40
|
+
cmd = [File.join(@npm_cwd, 'node_modules/.bin/istanbul'), 'cover', '--root', File.dirname(@module_path), '--'] if opts[:cover]
|
41
|
+
cmd += [File.join(@npm_cwd, 'startup.js'), '-p', @port.to_s, '-m', @module_path, '-h', @name, '-t', '1000']
|
42
|
+
@proc = ProcessHelper::ProcessHelper.new(print_lines: true)
|
43
|
+
@proc.start(cmd, 'Server running at http')
|
44
|
+
end
|
45
|
+
|
46
|
+
def url
|
47
|
+
"http://localhost:#{@port}/"
|
48
|
+
end
|
49
|
+
|
50
|
+
def wait(response)
|
51
|
+
case response.code
|
52
|
+
when 201 then false
|
53
|
+
when 200 then true
|
54
|
+
when 504 then fail 'timeout'
|
55
|
+
when 502 then fail response
|
56
|
+
else fail "unknown response #{response.code}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def send(message)
|
61
|
+
id = RestClient.post(url, message, content_type: :json).to_str
|
62
|
+
loop do
|
63
|
+
wait(RestClient.get(url, params: { id: id })) || break
|
64
|
+
sleep(0.1)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def stop
|
69
|
+
RestClient.delete(url)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# aws events
|
74
|
+
class Events
|
75
|
+
def self.s3_event(bucket, key, local_path)
|
76
|
+
event = load_json('sample_req.json')
|
77
|
+
event['Records'].each do |record|
|
78
|
+
record['file'] = { 'path' => local_path }
|
79
|
+
record['s3']['bucket'].update('name' => bucket,
|
80
|
+
'arn' => 'arn:aws:s3:::' + bucket)
|
81
|
+
record['s3']['object']['key'] = key
|
82
|
+
record
|
83
|
+
end
|
84
|
+
event.to_json
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.sns_event(topicArn, messageId, timestamp, messageBody)
|
88
|
+
event = load_json('sample_sns_req.json')
|
89
|
+
event['Records'].each do |record|
|
90
|
+
record['Sns']['topicArn'] = topicArn
|
91
|
+
record['Sns']['messageId'] = messageId
|
92
|
+
record['Sns']['timestamp'] = timestamp
|
93
|
+
record['Sns']['messageBody'] = messageBody
|
94
|
+
end
|
95
|
+
event.to_json
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# vi: tabstop=2:softtabstop=2:shiftwidth=2:expandtab
|
data/lib/sample_req.json
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
{
|
2
|
+
"Records": [
|
3
|
+
{
|
4
|
+
"eventVersion": "2.0",
|
5
|
+
"eventSource": "aws:s3",
|
6
|
+
"awsRegion": "eu-west-1",
|
7
|
+
"eventTime": "1970-01-01T00:00:00.000Z",
|
8
|
+
"eventName": "ObjectCreated:Put",
|
9
|
+
"userIdentity": {
|
10
|
+
"principalId": "1"
|
11
|
+
},
|
12
|
+
"requestParameters": {
|
13
|
+
"sourceIPAddress": "1"
|
14
|
+
},
|
15
|
+
"responseElements": {
|
16
|
+
"x-amz-request-id": "1",
|
17
|
+
"x-amz-id-2": "1"
|
18
|
+
},
|
19
|
+
"s3": {
|
20
|
+
"s3SchemaVersion": "1.0",
|
21
|
+
"configurationId": "1",
|
22
|
+
"bucket": {
|
23
|
+
"name": "example-bucket",
|
24
|
+
"ownerIdentity": {
|
25
|
+
"principalId": "1"
|
26
|
+
},
|
27
|
+
"arn": "arn:aws:s3:::example-bucket"
|
28
|
+
},
|
29
|
+
"object": {
|
30
|
+
"key": "key/to/file.xml",
|
31
|
+
"size": 1,
|
32
|
+
"eTag": "1"
|
33
|
+
}
|
34
|
+
}
|
35
|
+
}
|
36
|
+
]
|
37
|
+
}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
{
|
2
|
+
"Records":[
|
3
|
+
{
|
4
|
+
"EventSource":"aws:sns",
|
5
|
+
"EventVersion": "1.0",
|
6
|
+
"EventSubscriptionArn": "arn:aws:sns:eu-west-1:1:lambda_topic:0123456789abcd",
|
7
|
+
"Sns":{
|
8
|
+
"Type": "Notification",
|
9
|
+
"MessageId":"95df01b4-ee98-5cb9-9903-4c221d41eb5e",
|
10
|
+
"TopicArn":"arn:aws:sns:eu-west-1:123456789012:lambda_topic",
|
11
|
+
"Subject":"TestInvoke",
|
12
|
+
"Message":"<message payload>",
|
13
|
+
"Timestamp":"2015-04-02T07:36:57.451Z",
|
14
|
+
"SignatureVersion":"1",
|
15
|
+
"Signature":"r0Dc5YVHuAglGcmZ9Q7SpFb2PuRDFmJNprJlAEEk8CzSq9Btu8U7dxOu++uU",
|
16
|
+
"SigningCertUrl":"http://sns.eu-west-1.amazonaws.com/SimpleNotificationService-d6d679a1d18e95c2f9ffcf11f4f9e198.pem",
|
17
|
+
"UnsubscribeUrl":"http://cloudcast.amazon.com/?foo",
|
18
|
+
"MessageAttributes":{"key":{"Type":"String","Value":"value"}}
|
19
|
+
}
|
20
|
+
}
|
21
|
+
]
|
22
|
+
}
|
metadata
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: aws-lambda-runner
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- andrew wheat
|
8
|
+
- tristan hill
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2015-01-09 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: process-helper
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '1'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '1'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: rest-client
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '1.0'
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '1.0'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: file_utils
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - "~>"
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '1'
|
49
|
+
type: :runtime
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - "~>"
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '1'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: rubocop
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - "~>"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: minitest
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - "~>"
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '5.0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - "~>"
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '5.0'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: rake
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - "~>"
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '10.0'
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - "~>"
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '10.0'
|
98
|
+
description: Trigger AWS Lambda functions without deploying to AWS
|
99
|
+
email: []
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- js/package.json
|
105
|
+
- js/request.js
|
106
|
+
- js/startup.js
|
107
|
+
- lib/lambda_runner.rb
|
108
|
+
- lib/sample_req.json
|
109
|
+
- lib/sample_sns_req.json
|
110
|
+
homepage: https://github.com/bbc/aws-lambda-runner
|
111
|
+
licenses:
|
112
|
+
- Apache 2
|
113
|
+
metadata: {}
|
114
|
+
post_install_message:
|
115
|
+
rdoc_options: []
|
116
|
+
require_paths:
|
117
|
+
- lib
|
118
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0'
|
123
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
124
|
+
requirements:
|
125
|
+
- - ">="
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: '0'
|
128
|
+
requirements: []
|
129
|
+
rubyforge_project:
|
130
|
+
rubygems_version: 2.2.2
|
131
|
+
signing_key:
|
132
|
+
specification_version: 4
|
133
|
+
summary: AWS Lambda testing helper
|
134
|
+
test_files: []
|