Added Ruby support to fnctl init. (#286)

This commit is contained in:
Travis Reeder
2016-11-15 06:39:20 -08:00
committed by C Cirello
parent 14a5ecd6b9
commit 299422cf7d
38 changed files with 129 additions and 344 deletions

View File

@@ -116,7 +116,8 @@ func main() {
} }
``` ```
Copy and paste the code above into a file called `hello.go`, then run: Copy and paste the code above into a file called `func.go`, then run the following commands to build your function
and deploy it.
```sh ```sh
# create func.yaml file, replace $USERNAME with your Docker Hub username. # create func.yaml file, replace $USERNAME with your Docker Hub username.
@@ -136,6 +137,10 @@ fnctl routes create myapp /hello
You can find a bunch of examples in various languages in the [examples](examples/) directory. You can also You can find a bunch of examples in various languages in the [examples](examples/) directory. You can also
write your functions in AWS's [Lambda format](docs/lambda/README.md). write your functions in AWS's [Lambda format](docs/lambda/README.md).
## Usage
This is a more detailed explanation of the main commands you'll use in IronFunctions as a developer.
### Create an Application ### Create an Application
An application is essentially a grouping of functions, that put together, form an API. Here's how to create an app. An application is essentially a grouping of functions, that put together, form an API. Here's how to create an app.

View File

@@ -10,7 +10,6 @@ function build () {
} }
function run () { function run () {
build
docker run --rm --name functions -it -v /var/run/docker.sock:/var/run/docker.sock -e LOG_LEVEL=debug -e "DB_URL=bolt:///app/data/bolt.db" -v $PWD/data:/app/data -p 8080:8080 iron/functions docker run --rm --name functions -it -v /var/run/docker.sock:/var/run/docker.sock -e LOG_LEVEL=debug -e "DB_URL=bolt:///app/data/bolt.db" -v $PWD/data:/app/data -p 8080:8080 iron/functions
} }

View File

@@ -1,2 +0,0 @@
/func
vendor

View File

@@ -1,5 +0,0 @@
FROM iron/go
ADD func .
ENTRYPOINT ["./func"]

View File

@@ -1,77 +0,0 @@
# Hello Function Image (Go Language)
This images compares the payload info with the header.
## Requirements
- IronFunctions API
## Development
### Building image locally
```
# SET BELOW TO YOUR DOCKER HUB USERNAME
USERNAME=YOUR_DOCKER_HUB_USERNAME
# build it
./build.sh
```
### Publishing to DockerHub
```
# tagging
docker run --rm -v "$PWD":/app treeder/bump patch
docker tag $USERNAME/func-hello-go:latest $USERNAME/func-hello-go:`cat VERSION`
# pushing to docker hub
docker push $USERNAME/func-hello-go
```
### Testing image
```
./test.sh
```
## Running it on IronFunctions
### Let's define some environment variables
```
# Set your Function server address
# Eg. 127.0.0.1:8080
FUNCAPI=YOUR_FUNCTIONS_ADDRESS
```
### Running with IronFunctions
With this command we are going to create an application with name `hello`.
```
curl -X POST --data '{
"app": {
"name": "hello",
}
}' http://$FUNCAPI/v1/apps
```
Now, we can create our route
```
curl -X POST --data '{
"route": {
"image": "'$USERNAME'/func-hello-go",
"path": "/hello",
}
}' http://$FUNCAPI/v1/apps/hello/routes
```
#### Testing function
Now that we created our IronFunction route, let's test our new route
```
curl -X POST --data '{"name": "Johnny"}' http://$FUNCAPI/r/hello/hello
```

View File

@@ -1 +0,0 @@
0.0.1

View File

@@ -1,8 +0,0 @@
#!/bin/bash
set -ex
FUNCPKG=$(pwd | sed "s|$GOPATH/src/||")
# build image
docker run --rm -v "$PWD":/go/src/$FUNCPKG -w /go/src/$FUNCPKG iron/go:dev go build -o func
docker build -t iron/func-hello-go .

View File

@@ -1,3 +0,0 @@
image: iron/func-hello-gp
build:
- ./build.sh

View File

@@ -1,22 +0,0 @@
package main
import (
"encoding/json"
"fmt"
"os"
)
type Input struct {
Name string `json:"name"`
}
func main() {
input := &Input{}
if err := json.NewDecoder(os.Stdin).Decode(input); err != nil {
// log.Println("Bad payload or no payload. Ignoring.", err)
}
if input.Name == "" {
input.Name = "World"
}
fmt.Printf("Hello %v!\n", input.Name)
}

View File

@@ -1,23 +0,0 @@
#!/bin/bash
HOST="${1:-localhost:8080}"
REQ="${2:-1}"
curl -H "Content-Type: application/json" -X POST -d '{
"app": { "name":"myapp" }
}' http://$HOST/v1/apps
curl -H "Content-Type: application/json" -X POST -d '{
"route": {
"type": "async",
"path":"/hello-async",
"image":"iron/hello"
}
}' http://$HOST/v1/apps/myapp/routes
for i in `seq 1 $REQ`;
do
curl -H "Content-Type: application/json" -X POST -d '{
"name":"Johnny"
}' http://$HOST/r/myapp/hello-async
done;

View File

@@ -1,23 +0,0 @@
#!/bin/bash
HOST="${1:-localhost:8080}"
REQ="${2:-1}"
curl -H "Content-Type: application/json" -X POST -d '{
"app": { "name":"myapp" }
}' http://$HOST/v1/apps
curl -H "Content-Type: application/json" -X POST -d '{
"route": {
"type": "sync",
"path":"/hello-sync",
"image":"iron/hello"
}
}' http://$HOST/v1/apps/myapp/routes
for i in `seq 1 $REQ`;
do
curl -H "Content-Type: application/json" -X POST -d '{
"name":"Johnny"
}' http://$HOST/r/myapp/hello-sync
done;

View File

@@ -1,9 +0,0 @@
#!/bin/bash
set -x
./build.sh
PAYLOAD='{"name":"Johnny"}'
# test it
echo $PAYLOAD | docker run --rm -i iron/func-hello-go

View File

@@ -1,2 +0,0 @@
bundle/
.bundle/

View File

@@ -1,9 +0,0 @@
FROM iron/ruby:dev
WORKDIR /function
ADD Gemfile* /function/
RUN bundle install
ADD . /function/
ENTRYPOINT ["ruby", "function.rb"]

View File

@@ -1,77 +0,0 @@
# Hello Function Image (Ruby)
This images compares the payload info with the header.
## Requirements
- IronFunctions API
## Development
### Building image locally
```
# SET BELOW TO YOUR DOCKER HUB USERNAME
USERNAME=YOUR_DOCKER_HUB_USERNAME
# build it
./build.sh
```
### Publishing to DockerHub
```
# tagging
docker run --rm -v "$PWD":/app treeder/bump patch
docker tag $USERNAME/func-hello-ruby:latest $USERNAME/func-hello-ruby:`cat VERSION`
# pushing to docker hub
docker push $USERNAME/func-hello-ruby
```
### Testing image
```
./test.sh
```
## Running it on IronFunctions
### Let's define some environment variables
```
# Set your Function server address
# Eg. 127.0.0.1:8080
FUNCAPI=YOUR_FUNCTIONS_ADDRESS
```
### Running with IronFunctions
With this command we are going to create an application with name `hello`.
```
curl -X POST --data '{
"app": {
"name": "hello",
}
}' http://$FUNCAPI/v1/apps
```
Now, we can create our route
```
curl -X POST --data '{
"route": {
"image": "'$USERNAME'/func-hello-ruby",
"path": "/hello",
}
}' http://$FUNCAPI/v1/apps/hello/routes
```
#### Testing function
Now that we created our IronFunction route, let's test our new route
```
curl -X POST --data '{"name": "Johnny"}' http://$FUNCAPI/r/hello/hello
```

View File

@@ -1 +0,0 @@
0.0.1

View File

@@ -1,4 +0,0 @@
#!/bin/bash
set -ex
docker build -t iron/func-hello-ruby .

View File

@@ -1,3 +0,0 @@
image: iron/func-hello-ruby
build:
- ./build.sh

View File

@@ -1,23 +0,0 @@
#!/bin/bash
HOST="${1:-localhost:8080}"
REQ="${2:-1}"
curl -H "Content-Type: application/json" -X POST -d '{
"app": { "name":"myapp" }
}' http://$HOST/v1/apps
curl -H "Content-Type: application/json" -X POST -d '{
"route": {
"type": "async",
"path":"/hello-async",
"image":"iron/hello:ruby"
}
}' http://$HOST/v1/apps/myapp/routes
for i in `seq 1 $REQ`;
do
curl -H "Content-Type: application/json" -X POST -d '{
"name":"Johnny"
}' http://$HOST/r/myapp/hello-async
done;

View File

@@ -1,23 +0,0 @@
#!/bin/bash
HOST="${1:-localhost:8080}"
REQ="${2:-1}"
curl -H "Content-Type: application/json" -X POST -d '{
"app": { "name":"myapp" }
}' http://$HOST/v1/apps
curl -H "Content-Type: application/json" -X POST -d '{
"route": {
"type": "sync",
"path":"/hello-sync",
"image":"iron/hello:ruby
}
}' http://$HOST/v1/apps/myapp/routes
for i in `seq 1 $REQ`;
do
curl -H "Content-Type: application/json" -X POST -d '{
"name":"Johnny"
}' http://$HOST/r/myapp/hello-sync
done;

View File

@@ -1,9 +0,0 @@
#!/bin/bash
set -x
./build.sh
PAYLOAD='{"name":"Johnny"}'
# test it
echo $PAYLOAD | docker run --rm -i -e TEST=1 iron/func-hello-ruby

View File

@@ -1,4 +0,0 @@
FROM iron/go
WORKDIR /function
ADD . /function/
ENTRYPOINT ["./func"]

View File

@@ -20,3 +20,8 @@ Now you can call your function on IronFunctions:
```sh ```sh
curl -H "Content-Type: application/json" -X POST -d @hello.payload.json http://localhost:8080/r/myapp/hello curl -H "Content-Type: application/json" -X POST -d @hello.payload.json http://localhost:8080/r/myapp/hello
``` ```
## Dependencies
Be sure you're dependencies are in the `vendor/` directory and that's it.

View File

@@ -1,4 +0,0 @@
name: treeder/hello4
version: 0.0.1
runtime: go
entrypoint: ./func

View File

@@ -16,3 +16,26 @@ fnctl routes create myapp /hello
``` ```
Now surf to: http://localhost:8080/r/myapp/hello Now surf to: http://localhost:8080/r/myapp/hello
## Dependencies
Create a [package.json](https://docs.npmjs.com/getting-started/using-a-package.json) file in your functions directory.
Run:
```sh
docker run --rm -v "$PWD":/function -w /function iron/node:dev npm install
```
Then everything should work.
For example, using the `package.json` file in this directory which includes the [request](https://www.npmjs.com/package/request) package, you can add this to func.js and it will work:
```js
var request = require('request');
request('http://www.google.com', function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body) // Show the HTML for the Google homepage.
}
})
```

View File

@@ -1,4 +0,0 @@
name: treeder/node4
version: 0.0.2
runtime: node
entrypoint: node hello.js

View File

@@ -1,4 +1,7 @@
{ {
"name": "my-awesome-func",
"version": "1.0.0",
"dependencies": { "dependencies": {
"request": "^2.78.0"
} }
} }

5
examples/hello/ruby/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
bundle/
.bundle/
func.yaml
Dockerfile
Gemfile.lock

View File

@@ -1,3 +1,4 @@
source 'https://rubygems.org' source 'https://rubygems.org'
gem 'httparty', '~> 0.14.0'
gem 'json', '> 1.8.2' gem 'json', '> 1.8.2'

View File

@@ -0,0 +1,44 @@
## Quick Example for a Ruby Function (4 minutes)
This example will show you how to test and deploy a Ruby function to IronFunctions.
```sh
# create your func.yaml file
fnctl init <YOUR_DOCKERHUB_USERNAME>/hello
# install dependencies, we need the json gem to run this
docker run --rm -v "$PWD":/worker -w /worker iron/ruby:dev bundle install --standalone --clean
# build the function
fnctl build
# test it
cat hello.payload.json | fnctl run
# push it to Docker Hub for use with IronFunctions
fnctl push
# Create a route to this function on IronFunctions
fnctl routes create myapp /hello
```
Now surf to: http://localhost:8080/r/myapp/hello
## Dependencies
Create a [Gemfile](http://bundler.io/gemfile.html) file in your function directory, then run:
```sh
docker run --rm -v "$PWD":/worker -w /worker iron/ruby:dev bundle install --standalone --clean
```
Ruby doesn't pick up the gems automatically, so you'll have to add this to the top of your `func.rb` file:
```ruby
require_relative 'bundle/bundler/setup'
```
Open `func.rb` to see it in action.
To update dependencies:
```sh
docker run --rm -v "$PWD":/worker -w /worker iron/ruby:dev bundle update
# then install again to vendor them
docker run --rm -v "$PWD":/worker -w /worker iron/ruby:dev bundle update
```

View File

@@ -1,3 +1,4 @@
require_relative 'bundle/bundler/setup'
require 'json' require 'json'
name = "World" name = "World"
@@ -8,4 +9,4 @@ if payload != ""
name = payload['name'] name = payload['name']
end end
puts "Hello #{name}!" puts "Hello #{name} from Ruby!"

View File

@@ -0,0 +1,3 @@
{
"name": "Johnny"
}

View File

@@ -6,14 +6,22 @@
Init will help you create a [function file](../docs/function-file.md) (func.yaml) in the current directory. Init will help you create a [function file](../docs/function-file.md) (func.yaml) in the current directory.
To make things simple, we try to use convention over configuration, so `init` will look for a file named `func.{language-extension}`. For example,
if you are using Node, put the code that you want to execute in the file `func.js`. If you are using Python, use `func.py`. Ruby, use `func.rb`. Go, `func.go`. Etc.
Run:
```sh ```sh
fnctl init [--runtime node] [--entrypoint "node hello.js"] <name> fnctl init <DOCKER_HUB_USERNAME>/<FUNCTION_NAME>
``` ```
`--runtime` and `--entrypoint` are optional, init will try to figure out it out based on the files in the current directory. If you want to override the convention with configuration, you can do that as well using:
If it can't figure it out, it will tell you.
If there's a Dockerfile found, it will use that as is ```sh
fnctl init [--runtime node] [--entrypoint "node hello.js"] <DOCKER_HUB_USERNAME>/<FUNCTION_NAME>
```
Or, if you want full control, just make a Dockerfile. If `init` finds a Dockerfile, it will use that instead of runtime and entrypoint.
### Build, Bump, Run, Push ### Build, Bump, Run, Push

View File

@@ -25,6 +25,7 @@ var (
fileExtToRuntime = map[string]string{ fileExtToRuntime = map[string]string{
".go": "go", ".go": "go",
".js": "node", ".js": "node",
".rb": "ruby",
} }
fnInitRuntimes []string fnInitRuntimes []string

View File

@@ -9,6 +9,8 @@ func GetLangHelper(lang string) (LangHelper, error) {
return &GoLangHelper{}, nil return &GoLangHelper{}, nil
case "node": case "node":
return &NodeLangHelper{}, nil return &NodeLangHelper{}, nil
case "ruby":
return &RubyLangHelper{}, nil
} }
return nil, fmt.Errorf("No language helper found for %v", lang) return nil, fmt.Errorf("No language helper found for %v", lang)
} }

21
fnctl/langs/ruby.go Normal file
View File

@@ -0,0 +1,21 @@
package langs
type RubyLangHelper struct {
}
func (lh *RubyLangHelper) Entrypoint() string {
return "ruby func.rb"
}
func (lh *RubyLangHelper) HasPreBuild() bool {
return false
}
// PreBuild for Go builds the binary so the final image can be as small as possible
func (lh *RubyLangHelper) PreBuild() error {
return nil
}
func (lh *RubyLangHelper) AfterBuild() error {
return nil
}