Skip to content

Commit 4cf115f

Browse files
author
Colby Swandale
committed
init commit
0 parents  commit 4cf115f

20 files changed

+699
-0
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.aws-sam
2+
samconfig.toml

Gemfile

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
source "https://rubygems.org"
2+
3+
gem "test-unit", group: :test

Gemfile.lock

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
GEM
2+
remote: https://rubygems.org/
3+
specs:
4+
power_assert (1.2.0)
5+
test-unit (3.3.6)
6+
power_assert
7+
8+
PLATFORMS
9+
ruby
10+
11+
DEPENDENCIES
12+
test-unit
13+
14+
BUNDLED WITH
15+
2.1.4

README.md

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# rubyapi-repl
2+
3+
4+
## Deploy the sample application
5+
6+
The Serverless Application Model Command Line Interface (SAM CLI) is an extension of the AWS CLI that adds functionality for building and testing Lambda applications. It uses Docker to run your functions in an Amazon Linux environment that matches Lambda. It can also emulate your application's build environment and API.
7+
8+
To use the SAM CLI, you need the following tools.
9+
10+
* SAM CLI - [Install the SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)
11+
* Ruby - [Install Ruby 2.7](https://www.ruby-lang.org/en/documentation/installation/)
12+
* Docker - [Install Docker community edition](https://hub.docker.com/search/?type=edition&offering=community)
13+
14+
To build and deploy your application for the first time, run the following in your shell:
15+
16+
```bash
17+
sam build
18+
sam deploy --guided
19+
```
20+
21+
The first command will build the source of your application. The second command will package and deploy your application to AWS, with a series of prompts:
22+
23+
* **Stack Name**: The name of the stack to deploy to CloudFormation. This should be unique to your account and region, and a good starting point would be something matching your project name.
24+
* **AWS Region**: The AWS region you want to deploy your app to.
25+
* **Confirm changes before deploy**: If set to yes, any change sets will be shown to you before execution for manual review. If set to no, the AWS SAM CLI will automatically deploy application changes.
26+
* **Allow SAM CLI IAM role creation**: Many AWS SAM templates, including this example, create AWS IAM roles required for the AWS Lambda function(s) included to access AWS services. By default, these are scoped down to minimum required permissions. To deploy an AWS CloudFormation stack which creates or modified IAM roles, the `CAPABILITY_IAM` value for `capabilities` must be provided. If permission isn't provided through this prompt, to deploy this example you must explicitly pass `--capabilities CAPABILITY_IAM` to the `sam deploy` command.
27+
* **Save arguments to samconfig.toml**: If set to yes, your choices will be saved to a configuration file inside the project, so that in the future you can just re-run `sam deploy` without parameters to deploy changes to your application.
28+
29+
You can find your API Gateway Endpoint URL in the output values displayed after deployment.
30+
31+
## Use the SAM CLI to build and test locally
32+
33+
Build your application with the `sam build` command.
34+
35+
```bash
36+
rubyapi-repl$ sam build
37+
```
38+
39+
The SAM CLI installs dependencies defined in `hello_world/Gemfile`, creates a deployment package, and saves it in the `.aws-sam/build` folder.
40+
41+
Test a single function by invoking it directly with a test event. An event is a JSON document that represents the input that the function receives from the event source. Test events are included in the `events` folder in this project.
42+
43+
Run functions locally and invoke them with the `sam local invoke` command.
44+
45+
```bash
46+
rubyapi-repl$ sam local invoke HelloWorldFunction --event events/event.json
47+
```
48+
49+
The SAM CLI can also emulate your application's API. Use the `sam local start-api` to run the API locally on port 3000.
50+
51+
```bash
52+
rubyapi-repl$ sam local start-api
53+
rubyapi-repl$ curl http://localhost:3000/
54+
```
55+
56+
The SAM CLI reads the application template to determine the API's routes and the functions that they invoke. The `Events` property on each function's definition includes the route and method for each path.
57+
58+
```yaml
59+
Events:
60+
HelloWorld:
61+
Type: Api
62+
Properties:
63+
Path: /hello
64+
Method: get
65+
```
66+
67+
## Add a resource to your application
68+
The application template uses AWS Serverless Application Model (AWS SAM) to define application resources. AWS SAM is an extension of AWS CloudFormation with a simpler syntax for configuring common serverless application resources such as functions, triggers, and APIs. For resources not included in [the SAM specification](https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md), you can use standard [AWS CloudFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html) resource types.
69+
70+
## Fetch, tail, and filter Lambda function logs
71+
72+
To simplify troubleshooting, SAM CLI has a command called `sam logs`. `sam logs` lets you fetch logs generated by your deployed Lambda function from the command line. In addition to printing the logs on the terminal, this command has several nifty features to help you quickly find the bug.
73+
74+
`NOTE`: This command works for all AWS Lambda functions; not just the ones you deploy using SAM.
75+
76+
```bash
77+
rubyapi-repl$ sam logs -n HelloWorldFunction --stack-name rubyapi-repl --tail
78+
```
79+
80+
You can find more information and examples about filtering Lambda function logs in the [SAM CLI Documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-logging.html).
81+
82+
## Testing
83+
84+
Tests are defined in the `tests` folder in this project.
85+
86+
```bash
87+
rubyapi-repl$ ruby tests/unit/test_handler.rb
88+
```
89+
90+
91+
## Resources
92+
93+
See the [AWS SAM developer guide](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html) for an introduction to SAM specification, the SAM CLI, and serverless application concepts.
94+
95+
Next, you can use AWS Serverless Application Repository to deploy ready to use Apps that go beyond hello world samples and learn how authors developed their applications: [AWS Serverless Application Repository main page](https://aws.amazon.com/serverless/serverlessrepo/)

Rakefile

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
require "rake/testtask"
2+
3+
task default: "test"
4+
5+
Rake::TestTask.new do |t|
6+
t.libs << "test"
7+
t.test_files = FileList['tests/**/*_test.rb']
8+
t.verbose = true
9+
end

app/Gemfile

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
source "https://rubygems.org"
2+
3+
ruby '~> 2.7.0'

app/code_executor.rb

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
require_relative './helper'
2+
require_relative './response'
3+
require_relative './payload'
4+
5+
require 'open3'
6+
7+
class CodeExecutor
8+
include Helper
9+
10+
attr_accessor :payload
11+
12+
def self.run(body)
13+
new(body).run
14+
end
15+
16+
def initialize(body)
17+
@payload = Payload.generate_from_body(body)
18+
end
19+
20+
def run
21+
execute_payload
22+
end
23+
24+
private
25+
26+
def execute_payload
27+
stdout, stderr, status = Open3.capture3(ruby_cmd, stdin_data: payload)
28+
Response.new(output: stdout, errors: stderr, status: status&.exitstatus)
29+
end
30+
31+
def ruby_cmd
32+
[ruby_env, ruby_bin_path, ruby_args].join(" ")
33+
end
34+
35+
# Workaround for SAM overwriting the PATH env
36+
def ruby_env
37+
"PATH=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/bin:/opt/bin:/opt/java/bin\""
38+
end
39+
40+
def ruby_bin_path
41+
ENV["RUBY_BIN"] || `which ruby`.strip
42+
end
43+
44+
def ruby_args
45+
return "" if disable_args?
46+
47+
args = ["--disable-did_you_mean"]
48+
49+
unless rubygems_required?
50+
args << "--disable-gems"
51+
end
52+
53+
args.join(" ")
54+
end
55+
end

app/helper.rb

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
module Helper
2+
def ruby_bin_path
3+
ENV["RUBY_BIN"] || `which ruby`.strip
4+
end
5+
6+
def rubygems_required?
7+
ENV["RUBYGEMS_REQUIRED"] && !ENV["RUBYGEMS_REQUIRED"].empty?
8+
end
9+
10+
def disable_args?
11+
ENV["DISBALE_RUBY_ARGS"] && !ENV["DISBALE_RUBY_ARGS"].empty?
12+
end
13+
14+
def minimal_execution?
15+
ENV["MINIMAL_EXECUTION"] && !ENV["DISBALE_RUBY_ARGS"].empty?
16+
end
17+
end

app/payload.rb

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
require_relative './helper'
2+
3+
require 'erb'
4+
5+
class Payload
6+
include Helper
7+
8+
CODE_TEMPLATE = <<~TEMPLATE
9+
<% unless minimal_execution? %>
10+
%w(abbrev base64 benchmark bigdecimal cgi cmath coverage csv date dbm delegate digest drb English
11+
erb etc expect fcntl fiddle fileutils find forwardable gdbm getoptlong io/console io/nonblock
12+
io/wait ipaddr irb json logger matrix mkmf monitor mutex_m net/ftp net/http net/imap net/smtp net/pop
13+
net/telnet nkf objspace observer open-uri open3 openssl optparse ostruct pathname pp
14+
prettyprint prime pstore psych pty racc/parser rake rdoc readline resolv ripper rss scanf
15+
sdbm securerandom set shell shellwords singleton socket stringio strscan sync syslog tempfile thwait time
16+
timeout tmpdir tracer tsort un uri weakref webrick yaml zlib).each do |l|
17+
begin
18+
require l
19+
rescue LoadError
20+
end
21+
end
22+
<% end %>
23+
24+
_ = begin
25+
<%= payload %>
26+
end
27+
28+
puts _.inspect
29+
TEMPLATE
30+
31+
attr_reader :payload
32+
33+
def self.generate_from_body(body)
34+
new(body).generate
35+
end
36+
37+
def initialize(payload)
38+
@payload = payload
39+
end
40+
41+
def generate
42+
b = binding
43+
template = ERB.new(CODE_TEMPLATE).result(b)
44+
end
45+
end

app/response.rb

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# frozen_string_literal: true
2+
3+
Response = Struct.new(:output, :errors, :status, keyword_init: true) do
4+
def status
5+
self[:status] || 0
6+
end
7+
end

app/run.rb

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# frozen_string_literal: true
2+
3+
require 'json'
4+
require 'open3'
5+
6+
require_relative './helper'
7+
require_relative './code_executor'
8+
9+
def lambda_handler(event:, context:)
10+
event.transform_keys!(&:to_sym)
11+
12+
body = event.fetch(:body)
13+
14+
return { statusCode: 400, body: {}.to_json } if body.empty?
15+
16+
response = CodeExecutor.run(body)
17+
18+
{
19+
statusCode: 200,
20+
body: { output: response.output, error: response.errors, status: response.status }.to_json
21+
}
22+
end
23+

rubies/artichoke-ruby/Makefile

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
build-ArtichokeRuby:
2+
mkdir -p "$(ARTIFACTS_DIR)/ruby"
3+
docker run --rm --user "$(id -u):$(id -g)" --mount type=bind,source="$(PWD)"/scripts,target=/scripts --mount type=bind,source="$(ARTIFACTS_DIR)/ruby",target=/build/ruby lambci/lambda:build-provided /scripts/build-ruby.sh artichoke-dev

rubies/jruby/Makefile

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
build-JRuby:
2+
mkdir -p "$(ARTIFACTS_DIR)/ruby"
3+
docker run --rm --user "$(id -u):$(id -g)" --mount type=bind,source="$(PWD)"/scripts,target=/scripts --user "$(id -u):$(id -g)" --mount type=bind,source="$(ARTIFACTS_DIR)/ruby",target=/build/ruby lambci/lambda:build-provided /scripts/build-ruby.sh jruby-9.2.9.0

rubies/mri/Makefile

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
build-MRIRuby27:
2+
mkdir -p "$(ARTIFACTS_DIR)/ruby"
3+
docker run --rm --user "$(id -u):$(id -g)" --mount type=bind,source="$(PWD)"/scripts,target=/scripts --mount type=bind,source="$(ARTIFACTS_DIR)/ruby",target=/build/ruby lambci/lambda:build-provided /scripts/build-ruby.sh 2.7.1
4+
5+
build-MRIRuby26:
6+
mkdir -p "$(ARTIFACTS_DIR)/ruby"
7+
docker run --rm --user "$(id -u):$(id -g)" --mount type=bind,source="$(PWD)"/scripts,target=/scripts --mount type=bind,source="$(ARTIFACTS_DIR)/ruby",target=/build/ruby lambci/lambda:build-provided /scripts/build-ruby.sh 2.6.6
8+
9+
build-MRIRuby25:
10+
mkdir -p "$(ARTIFACTS_DIR)/ruby"
11+
docker run --rm --user "$(id -u):$(id -g)" --mount type=bind,source="$(PWD)"/scripts,target=/scripts --mount type=bind,source="$(ARTIFACTS_DIR)/ruby",target=/build/ruby lambci/lambda:build-provided /scripts/build-ruby.sh 2.5.8
12+
13+
build-MRIRuby24:
14+
mkdir -p "$(ARTIFACTS_DIR)/ruby"
15+
docker run --rm --user "$(id -u):$(id -g)" --mount type=bind,source="$(PWD)"/scripts,target=/scripts --mount type=bind,source="$(ARTIFACTS_DIR)/ruby",target=/build/ruby lambci/lambda:build-provided /scripts/build-ruby.sh 2.4.9
16+
17+
build-MRIRuby23:
18+
mkdir -p "$(ARTIFACTS_DIR)/ruby"
19+
docker run --rm --user "$(id -u):$(id -g)" --mount type=bind,source="$(PWD)"/scripts,target=/scripts --mount type=bind,source="$(ARTIFACTS_DIR)/ruby",target=/build/ruby lambci/lambda:build-provided /scripts/build-ruby.sh 2.3.8
20+
21+
build-MRIRuby30:
22+
mkdir -p "$(ARTIFACTS_DIR)/ruby"
23+
docker run --rm --user "$(id -u):$(id -g)" --mount type=bind,source="$(PWD)"/scripts,target=/scripts --mount type=bind,source="$(ARTIFACTS_DIR)/ruby",target=/build/ruby lambci/lambda:build-provided /scripts/build-ruby.sh 3.0.0-dev

rubies/mruby/Makefile

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
build-MRuby:
2+
mkdir -p "$(ARTIFACTS_DIR)/ruby"
3+
docker run --rm --user "$(id -u):$(id -g)" --mount type=bind,source="$(PWD)"/scripts,target=/scripts --mount type=bind,source="$(ARTIFACTS_DIR)/ruby",target=/build/ruby lambci/lambda:build-provided /scripts/build-ruby.sh mruby-2.1.2
4+
5+
build-MRubyDev:
6+
mkdir -p "$(ARTIFACTS_DIR)/ruby"
7+
docker run --rm --user "$(id -u):$(id -g)" --mount type=bind,source="$(PWD)"/scripts,target=/scripts --mount type=bind,source="$(ARTIFACTS_DIR)/ruby",target=/build/ruby lambci/lambda:build-provided /scripts/build-ruby.sh mruby-dev

rubies/support/java/Makefile

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
build-Java:
2+
mkdir -p "$(ARTIFACTS_DIR)/java"
3+
curl -L https://download.java.net/java/GA/jdk15/779bf45e88a44cbd9ea6621d33e33db1/36/GPL/openjdk-15_linux-x64_bin.tar.gz | \
4+
tar --strip-components=1 -C "$(ARTIFACTS_DIR)/java" -xzvf - jdk-15

rubies/truffleruby/Makefile

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
build-TruffleRuby:
3+
mkdir -p "$(ARTIFACTS_DIR)/ruby"
4+
docker run --user "$(id -u):$(id -g)" --mount type=bind,source="$(PWD)"/scripts,target=/scripts --mount type=bind,source="$(ARTIFACTS_DIR)/ruby",target=/build/ruby lambci/lambda:build-provided /scripts/build-ruby.sh truffleruby-20.2.0

scripts/build-ruby.sh

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/bin/bash
2+
3+
set -euox pipefail
4+
5+
export TMPDIR=/build
6+
export RUBY_BUILD_CACHE_PATH=/build/cache
7+
export RUBY_CFLAGS="-Os"
8+
export KEEP_BUILD_PATH="yes"
9+
export RUBY_CONFIGURE_OPTS="--disable-install-doc"
10+
11+
git clone https://github.com/rbenv/ruby-build /opt/ruby-build --depth 1
12+
13+
if [[ $1 =~ "mruby" ]] || [[ $1 == "3.0.0-dev" ]]; then
14+
yum install -y ruby24 rubygem24-rake
15+
fi
16+
17+
/opt/ruby-build/bin/ruby-build $1 /build/ruby-tmp
18+
19+
if [[ $1 =~ "mruby" ]]; then
20+
cp /lib64/libncurses.so.5 /lib64/libtinfo.so.5 /build/ruby-tmp/lib/
21+
fi
22+
23+
chown -R $UID /build/ruby-tmp
24+
25+
cp -af /build/ruby-tmp/. /build/ruby/

0 commit comments

Comments
 (0)