aws-lambda-runner 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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
+ }
@@ -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
+ };
@@ -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
@@ -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: []