diff --git a/README.md b/README.md index d663500c9..e6381df3b 100644 --- a/README.md +++ b/README.md @@ -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 # 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 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 An application is essentially a grouping of functions, that put together, form an API. Here's how to create an app. diff --git a/build.ps1 b/build.ps1 index c12014be8..2c4057c55 100644 --- a/build.ps1 +++ b/build.ps1 @@ -10,7 +10,6 @@ function build () { } 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 } diff --git a/examples/hello-go/.gitignore b/examples/hello-go/.gitignore deleted file mode 100644 index f16ae5300..000000000 --- a/examples/hello-go/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/func -vendor \ No newline at end of file diff --git a/examples/hello-go/Dockerfile b/examples/hello-go/Dockerfile deleted file mode 100644 index f5f8ab200..000000000 --- a/examples/hello-go/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM iron/go - -ADD func . - -ENTRYPOINT ["./func"] \ No newline at end of file diff --git a/examples/hello-go/README.md b/examples/hello-go/README.md deleted file mode 100644 index e539afc66..000000000 --- a/examples/hello-go/README.md +++ /dev/null @@ -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 -``` \ No newline at end of file diff --git a/examples/hello-go/VERSION b/examples/hello-go/VERSION deleted file mode 100644 index 8a9ecc2ea..000000000 --- a/examples/hello-go/VERSION +++ /dev/null @@ -1 +0,0 @@ -0.0.1 \ No newline at end of file diff --git a/examples/hello-go/build.sh b/examples/hello-go/build.sh deleted file mode 100755 index 61bf638d3..000000000 --- a/examples/hello-go/build.sh +++ /dev/null @@ -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 . \ No newline at end of file diff --git a/examples/hello-go/func.yml b/examples/hello-go/func.yml deleted file mode 100644 index 28704e1cd..000000000 --- a/examples/hello-go/func.yml +++ /dev/null @@ -1,3 +0,0 @@ -image: iron/func-hello-gp -build: - - ./build.sh \ No newline at end of file diff --git a/examples/hello-go/function.go b/examples/hello-go/function.go deleted file mode 100644 index 60bb44f02..000000000 --- a/examples/hello-go/function.go +++ /dev/null @@ -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) -} diff --git a/examples/hello-go/hello-async.sh b/examples/hello-go/hello-async.sh deleted file mode 100755 index 568f2dc15..000000000 --- a/examples/hello-go/hello-async.sh +++ /dev/null @@ -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; \ No newline at end of file diff --git a/examples/hello-go/hello-sync.sh b/examples/hello-go/hello-sync.sh deleted file mode 100755 index 898b262ac..000000000 --- a/examples/hello-go/hello-sync.sh +++ /dev/null @@ -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; \ No newline at end of file diff --git a/examples/hello-go/test.sh b/examples/hello-go/test.sh deleted file mode 100755 index 7f3a0e581..000000000 --- a/examples/hello-go/test.sh +++ /dev/null @@ -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 \ No newline at end of file diff --git a/examples/hello-ruby/.gitignore b/examples/hello-ruby/.gitignore deleted file mode 100644 index e715a8a80..000000000 --- a/examples/hello-ruby/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -bundle/ -.bundle/ diff --git a/examples/hello-ruby/Dockerfile b/examples/hello-ruby/Dockerfile deleted file mode 100644 index f6c10018d..000000000 --- a/examples/hello-ruby/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -FROM iron/ruby:dev - -WORKDIR /function -ADD Gemfile* /function/ -RUN bundle install - -ADD . /function/ - -ENTRYPOINT ["ruby", "function.rb"] diff --git a/examples/hello-ruby/README.md b/examples/hello-ruby/README.md deleted file mode 100644 index 3dc96fdc8..000000000 --- a/examples/hello-ruby/README.md +++ /dev/null @@ -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 -``` \ No newline at end of file diff --git a/examples/hello-ruby/VERSION b/examples/hello-ruby/VERSION deleted file mode 100644 index 8acdd82b7..000000000 --- a/examples/hello-ruby/VERSION +++ /dev/null @@ -1 +0,0 @@ -0.0.1 diff --git a/examples/hello-ruby/build.sh b/examples/hello-ruby/build.sh deleted file mode 100755 index 4d8d73dbc..000000000 --- a/examples/hello-ruby/build.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -set -ex - -docker build -t iron/func-hello-ruby . \ No newline at end of file diff --git a/examples/hello-ruby/func.yml b/examples/hello-ruby/func.yml deleted file mode 100644 index e06d9139c..000000000 --- a/examples/hello-ruby/func.yml +++ /dev/null @@ -1,3 +0,0 @@ -image: iron/func-hello-ruby -build: - - ./build.sh \ No newline at end of file diff --git a/examples/hello-ruby/hello-async.sh b/examples/hello-ruby/hello-async.sh deleted file mode 100755 index d18bfa7b2..000000000 --- a/examples/hello-ruby/hello-async.sh +++ /dev/null @@ -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; \ No newline at end of file diff --git a/examples/hello-ruby/hello-sync.sh b/examples/hello-ruby/hello-sync.sh deleted file mode 100755 index ff3d595f9..000000000 --- a/examples/hello-ruby/hello-sync.sh +++ /dev/null @@ -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; \ No newline at end of file diff --git a/examples/hello-ruby/test.sh b/examples/hello-ruby/test.sh deleted file mode 100755 index 2a533a641..000000000 --- a/examples/hello-ruby/test.sh +++ /dev/null @@ -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 \ No newline at end of file diff --git a/examples/hello/go/Dockerfile b/examples/hello/go/Dockerfile deleted file mode 100644 index d6c2303ba..000000000 --- a/examples/hello/go/Dockerfile +++ /dev/null @@ -1,4 +0,0 @@ -FROM iron/go -WORKDIR /function -ADD . /function/ -ENTRYPOINT ["./func"] diff --git a/examples/hello/go/README.md b/examples/hello/go/README.md index 02bc28e70..9394b3f0a 100644 --- a/examples/hello/go/README.md +++ b/examples/hello/go/README.md @@ -20,3 +20,8 @@ Now you can call your function on IronFunctions: ```sh 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. + diff --git a/examples/hello/go/hello.go b/examples/hello/go/func.go similarity index 100% rename from examples/hello/go/hello.go rename to examples/hello/go/func.go diff --git a/examples/hello/go/function.yaml b/examples/hello/go/function.yaml deleted file mode 100644 index 946aea6a2..000000000 --- a/examples/hello/go/function.yaml +++ /dev/null @@ -1,4 +0,0 @@ -name: treeder/hello4 -version: 0.0.1 -runtime: go -entrypoint: ./func diff --git a/examples/hello/node/README.md b/examples/hello/node/README.md index c46e3b67c..2e7cff443 100644 --- a/examples/hello/node/README.md +++ b/examples/hello/node/README.md @@ -16,3 +16,26 @@ fnctl routes create 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. + } +}) +``` diff --git a/examples/hello/node/hello.js b/examples/hello/node/func.js similarity index 100% rename from examples/hello/node/hello.js rename to examples/hello/node/func.js diff --git a/examples/hello/node/function.yaml b/examples/hello/node/function.yaml deleted file mode 100644 index e08c8786a..000000000 --- a/examples/hello/node/function.yaml +++ /dev/null @@ -1,4 +0,0 @@ -name: treeder/node4 -version: 0.0.2 -runtime: node -entrypoint: node hello.js diff --git a/examples/hello/node/package.json b/examples/hello/node/package.json index 4ae5150cd..f332baddb 100644 --- a/examples/hello/node/package.json +++ b/examples/hello/node/package.json @@ -1,4 +1,7 @@ { - "dependencies": { + "name": "my-awesome-func", + "version": "1.0.0", + "dependencies": { + "request": "^2.78.0" } } \ No newline at end of file diff --git a/examples/hello/ruby/.gitignore b/examples/hello/ruby/.gitignore new file mode 100644 index 000000000..841840003 --- /dev/null +++ b/examples/hello/ruby/.gitignore @@ -0,0 +1,5 @@ +bundle/ +.bundle/ +func.yaml +Dockerfile +Gemfile.lock diff --git a/examples/hello-ruby/Gemfile b/examples/hello/ruby/Gemfile similarity index 65% rename from examples/hello-ruby/Gemfile rename to examples/hello/ruby/Gemfile index e05a90012..922b35274 100644 --- a/examples/hello-ruby/Gemfile +++ b/examples/hello/ruby/Gemfile @@ -1,3 +1,4 @@ source 'https://rubygems.org' +gem 'httparty', '~> 0.14.0' gem 'json', '> 1.8.2' diff --git a/examples/hello/ruby/README.md b/examples/hello/ruby/README.md new file mode 100644 index 000000000..c87fde884 --- /dev/null +++ b/examples/hello/ruby/README.md @@ -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 /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 +``` diff --git a/examples/hello-ruby/function.rb b/examples/hello/ruby/func.rb similarity index 65% rename from examples/hello-ruby/function.rb rename to examples/hello/ruby/func.rb index 94ede49af..a16a04030 100644 --- a/examples/hello-ruby/function.rb +++ b/examples/hello/ruby/func.rb @@ -1,3 +1,4 @@ +require_relative 'bundle/bundler/setup' require 'json' name = "World" @@ -8,4 +9,4 @@ if payload != "" name = payload['name'] end -puts "Hello #{name}!" +puts "Hello #{name} from Ruby!" diff --git a/examples/hello/ruby/hello.payload.json b/examples/hello/ruby/hello.payload.json new file mode 100644 index 000000000..97e136b69 --- /dev/null +++ b/examples/hello/ruby/hello.payload.json @@ -0,0 +1,3 @@ +{ + "name": "Johnny" +} diff --git a/fnctl/README.md b/fnctl/README.md index 3a7a4bf0f..8ed903a02 100644 --- a/fnctl/README.md +++ b/fnctl/README.md @@ -6,14 +6,22 @@ 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 -fnctl init [--runtime node] [--entrypoint "node hello.js"] +fnctl init / ``` -`--runtime` and `--entrypoint` are optional, init will try to figure out it out based on the files in the current directory. -If it can't figure it out, it will tell you. +If you want to override the convention with configuration, you can do that as well using: -If there's a Dockerfile found, it will use that as is +```sh +fnctl init [--runtime node] [--entrypoint "node hello.js"] / +``` + +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 diff --git a/fnctl/init.go b/fnctl/init.go index a97c928f5..adff59f59 100644 --- a/fnctl/init.go +++ b/fnctl/init.go @@ -25,6 +25,7 @@ var ( fileExtToRuntime = map[string]string{ ".go": "go", ".js": "node", + ".rb": "ruby", } fnInitRuntimes []string diff --git a/fnctl/langs/base.go b/fnctl/langs/base.go index 65e26295a..2f5685853 100644 --- a/fnctl/langs/base.go +++ b/fnctl/langs/base.go @@ -9,6 +9,8 @@ func GetLangHelper(lang string) (LangHelper, error) { return &GoLangHelper{}, nil case "node": return &NodeLangHelper{}, nil + case "ruby": + return &RubyLangHelper{}, nil } return nil, fmt.Errorf("No language helper found for %v", lang) } diff --git a/fnctl/langs/ruby.go b/fnctl/langs/ruby.go new file mode 100644 index 000000000..ca48dce24 --- /dev/null +++ b/fnctl/langs/ruby.go @@ -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 +}