update docs and contributing

This commit is contained in:
Pedro Nasser
2016-07-27 17:51:51 -03:00
parent f09a4cc94f
commit 338498e94d
14 changed files with 194 additions and 350 deletions

1
.gitignore vendored
View File

@@ -12,6 +12,7 @@ vendor/
/gateway
/functions
bolt.db
.glide/
private.sh
.env

View File

@@ -1,23 +1,24 @@
## Building
## Building/Testing
Build:
```sh
# one time:
First time or when a dependency changes or when the API changes, run:
```
glide install
# then every time
./build.sh
```
Test it, the iron token and project id are for cache.
To quick build and run (using default database):
```sh
docker run --env-file .env --rm -it --privileged -p 8080:8080 iron/functions
hack/api.sh
```
To build the docker image:
```sh
hack/build.sh
```
## Releasing
```sh
./release.sh
hack/release.sh
```

106
README.md
View File

@@ -1,54 +1,80 @@
Note: currently running at: http://gateway.iron.computer:8080/
# IronFunctions
First, let's fire up an IronFunctions instance. Copy the [example.env](example.env) file into a file named `.env` and fill in the missing values.
## [Overview](/iron-io/functions/blob/master/OVERVIEW.md)
Then start your functions instance:
## Quick Start
First let's start our IronFunctions API
```
docker run --env-file .env --rm -it --privileged -p 8080:8080 iron/functions
docker run --rm -it -p 8080:8080 iron/functions
```
## Usage
This command will quickly start our API using the default database `Bolt` running on `:8080`
First things first, create an app/service:
TOOD: App or service??
Now that we have our API up and running we can quickly create our first function
### Create App
```
curl -H "Content-Type: application/json" -X POST -d '{
"name": "MyRoute"
"path": "/myroute"
"image": "iron/hello"
}' http://localhost:8080/v1/apps/myapp/routes
```
Done. Now you have our first IronFunctions route ready.
Now let's test our new route.
```
curl http://localhost:8080/r/myapp/myroute
```
## Configuring your API
### Databases
These are the current databases supported by IronFunctions:
- [Running with BoltDB](/iron-io/functions/blob/master/docs/database/boltdb.md)
- [Running with Postgres](/iron-io/functions/blob/master/docs/database/postgres.md)
## API Usage
### Creating applications
```sh
iron create app APP_NAME
# OR
curl -H "Content-Type: application/json" -X POST -d '{"name":"APP_NAME"}' http://localhost:8080/api/v1/apps
curl -H "Content-Type: application/json" -X POST -d '{
"name":"APP_NAME"
}' http://localhost:8080/v1/apps
```
### Create a Route for your Function
### Creating routes in a application
Now add routes to the app. First we'll add a route to the output of a docker container:
```sh
iron add route myapp /hello iron/hello
# OR
curl -H "Content-Type: application/json" -X POST -d '{"path":"/hello", "image":"iron/hello"}' http://localhost:8080/api/v1/apps/myapp/routes
```
And how about a [slackbot](https://github.com/treeder/slackbots/tree/master/guppy) too:
```sh
curl -H "Content-Type: application/json" -X POST -d '{"path":"/guppy","image":"treeder/guppy:0.0.2", "content_type": "application/json"}' http://localhost:8080/api/v1/apps/myapp/routes
curl -H "Content-Type: application/json" -X POST -d '{
"name": "hello",
"path":"/hello",
"image":"iron/hello"
}' http://localhost:8080/v1/apps/myapp/routes
```
### Calling your Function
Surf to your function: http://localhost:8080/hello?app=APP_NAME . Boom!
```
curl http://localhost:8080/r/myapp/hello
```
#### To pass in data to your function,
### To pass in data to your function,
Your function will get the body of the request as is, and the headers of the request will be passed in as env vars.
```sh
curl -H "Content-Type: application/json" -X POST -d '{"name":"Johnny"}' http://localhost:8080/hello?app=APP_NAME
curl -H "Content-Type: application/json" -X POST -d '{
"name":"Johnny"
}' http://localhost:8080/r/myapp/hello
```
### Using IronFunctions Hosted by Iron.io
@@ -56,38 +82,26 @@ curl -H "Content-Type: application/json" -X POST -d '{"name":"Johnny"}' http://l
Simply point to https://functions.iron.io instead of localhost and add your Iron.io Authentication header (TODO: link), like this:
```sh
curl -H "Authorization: Bearer IRON_TOKEN" -H "Content-Type: application/json" -X POST -d '{"name":"APP_NAME"}' https://functions.iron.io/api/v1/apps
curl -H "Authorization: Bearer IRON_TOKEN" -H "Content-Type: application/json" -X POST -d '{"name":"APP_NAME"}' https://functions.iron.io/v1/apps
```
And you'll get an ironfunctions.com host:
```
APP_NAME.ironfunctions.com/PATH
APP_NAME.USER_ID.ironfunctions.com/PATH
```
### Updating Your Images
## [Examples](/iron-io/functions/blob/master/examples)
Tag your images with a version, eg `treeder/guppy:0.0.5` then use that including the tag and update
the route.
## Examples
TODO: Link to examples in various languages
TODO: Link to slackbots (easiest way to host slackbots?)
## Operations
This is info on how to run and manage IronFunctions.
### Logging
Run logspout container on your server.
#### Monitoring
## Logging
TODO
### Scaling
## Monitoring
TODO
## Scaling
TODO

0
docs/api.md Normal file
View File

11
docs/database/boltdb.md Normal file
View File

@@ -0,0 +1,11 @@
# IronFunctions using BoltDB
BoltDB is the default database, you just need to run the API.
## Persistent
To keep it persistent you add a volume flag to the command:
```
docker run --rm -it -v $PWD/bold.db:/app/bolt.db -p 8080:8080 iron/functions
```

34
docs/database/postgres.md Normal file
View File

@@ -0,0 +1,34 @@
# IronFunctions using Postgres
Let's presuppose you don't have even a postgres DB ready.
### 1. Let's start a postgres instance:
```
docker run --name iron-postgres \
-e POSTGRES_PASSWORD=ironfunctions -d postgres
```
### 2. Now let's create a new database to IronFunctions
Creating database:
```
docker run -it --rm --link iron-postgres:postgres postgres \
psql -h postgres -U postgres -c "CREATE DATABASE funcs;"
```
Granting access to postgres user
```
docker run -it --rm --link iron-postgres:postgres postgres \
psql -h postgres -U postgres -c 'GRANT ALL PRIVILEGES ON DATABASE funcs TO postgres;'
```
### 3. Now let's start IronFunctions connecting to our new postgres instance
```
docker run --rm --link "iron-postgres:postgres" \
-e "DB=postgres://postgres:ironfunctions@postgres/funcs?sslmode=disable" \
-it -p 8080:8080 iron/functions
```

View File

@@ -1,9 +0,0 @@
# For IronCache
IRON_TOKEN=X
IRON_PROJECT_ID=X
# For CloudFlare dns support
CLOUDFLARE_EMAIL=you@example.com
CLOUDFLARE_API_KEY=X
# See comments here to get zone id https://blog.cloudflare.com/cloudflare-tips-frequently-used-cloudflare-ap/#comment-2412200222
CLOUDFLARE_ZONE_ID=y

View File

@@ -1,23 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAhof/Rgb5YUGUCynxYAkbkSRQqIaaZem7g6r/lyePBk6IKzjia6QA+Ut+1KZt
uGrNXFR0THtfEWCFjIPBJfYLGmkG1gaYocWJUu/b3be3rKGlLWEuSpfHsYyLh4803QNU79Uu0ft8
ODB4QJl54WImD1JKzAZyarDalyb+GKbnU5NAULBbTccbGFbNSwPwebvoK9G6Z8qWChPqsYAZxfyC
D2LBt0PANwB+haC6Rj0t99R6mtLRz/iKYaHz26d6UxSzNsXArJlhSCABHdQ71rbPkO0M9PvJrhfg
y+bLA4sMrHvOSjEDWGY+j1qqEYXSc/Rwe5SMd8kV7i902ks7PjcCZQIDAQABAoIBAHjvlHk9F71o
GE+Y2tV8Gn31aVS1++IVpW2NsMoO07HVsu836cLd4co5JcDAA+4+hHG1sf53AVU7sZJJdr5LWlvZ
gj2wHFGApBwcZ0f/OWxEu5n5vIVtwCRJtbyc7eaochhPShGVw2s3l0JrNXd4pcIsNfUG7qAeb8Jl
WRKMJ3OmoEMOz5M3scRypQKOulRjO6RMJCtbl4AntMYNF7cdWeuIJ3eaMD8HaYbkr1USrwGk65QC
mKdUcNl9k++Txuf7UtbRB0apFsMnAKRPUTU+9TPGwMsZSzszk8TClMNO1ALYKKY5mE+cPqrAl5gC
ZpPOf45oT+2lxktqq5u5N8XMFoECgYEA16eGE3inh23EVly5ARnowGgFtorZsI6XIJHkYsETRocf
GAvQrEMAuFWZy0n5TlNBfzPhHh9rUXWCKlbldgnDgWKpphPux3UXTqTUak+j6397rtEP85RfYqDm
QxtW0uOkKkZSGyXXEYBwTbCsQBH28VZsJEYVe+G3uXPcUu3WEZUCgYEAn7Mwgk/JP5wgYo4E3gga
fOi0/de11MV5ad337qfdUC1pf1ju9q2CyHaV3g6eo2OnynGZHYq5qlyLWoi/hTr6A+yMZSnQ15io
9ker4uyAX6DdVDmWK9uErwrqLAV+Q6HoVmxoyBbMihQW8TqX/5jZegxqipDW16+qOFxtPbZhmZEC
gYEAlD85UBFVOSggHC5Jj5Q8CGh55O62j0S2Z1Fjau/HTGh+24zjukelKxLNUo5br5hUIhmL26VF
pQ3emTR7MRWtLDii3uQ89ShtCUcOLrbovG86mwZkrNGGcMqi/+a/XOHYbKdCsh7lJcbhbMbS4oh2
9ZivZpA3HJ4iKn6XKvsMebECgYEAhNWXU8zpqG9EwLVAdy5mWd92LG5wYDqhct2ejHQ0MayUQ8jF
e4l3bya0IbAnY+BQgKNcqKXrKTkw8G0uYLNdokXvwXW2sJ3abH/RCT+Ox/wWHSiJMJG3G6IIhfVL
wRW7G6ewwD22hGORcbU7GO8addo+BGPVUDJdc+PtOZeqNwECgYEAvLJQas3PKLL+qVmO9asvDtCl
tvOuvPFAuZBk6hLm9SSrFt5cCW+rulL8Kx1PxUk0C8LiJV8uwZIqQxE+gY5MkCfvt+xG1yurkywd
SCHOFr0m4gi8+XHvL4fmGzYPgHRi10kepSta5G8USigbcf5fOmw+Upa3qVnwot3CQdxmSfU=
-----END RSA PRIVATE KEY-----

118
glide.lock generated
View File

@@ -1,75 +1,71 @@
hash: a104a522dc2ba982d25101330bbd5d44778565128f0cb09f34061c167921046c
updated: 2016-07-14T08:40:37.798125603-07:00
hash: 2101b4c83f12c75cbc3cb5be0a7d544dd3a7d21a27ef8a5ee8b014ded8cee034
updated: 2016-07-27T16:56:51.792310167-03:00
imports:
- name: github.com/amir/raidman
version: 91c20f3f475cab75bb40ad7951d9bbdde357ade7
- name: github.com/asaskevich/govalidator
version: 593d64559f7600f29581a3ee42177f5dbded27a9
- name: github.com/boltdb/bolt
version: 5cc10bbbc5c141029940133bb33c9e969512a698
- name: github.com/gin-gonic/gin
version: 4a6bc4aac4607e253bcda67c8c5bcda693d2388e
subpackages:
- proto
- name: github.com/BurntSushi/toml
version: bec2dacf4b590d26237cfebff4471e21ce543494
- name: github.com/cactus/go-statsd-client
version: 91c326c3f7bd20f0226d3d1c289dd9f8ce28d33d
subpackages:
- statsd
- name: github.com/dgrijalva/jwt-go
version: 01aeca54ebda6e0fbfafd0a524d234159c05ec20
- binding
- render
- name: github.com/go-openapi/analysis
version: abc9a6171f5bf03ada39aead1aa7fd7bbd44d50f
- name: github.com/go-openapi/errors
version: d24ebc2075bad502fac3a8ae27aa6dd58e1952dc
- name: github.com/go-openapi/jsonpointer
version: 46af16f9f7b149af66e5d1bd010e3574dc06de98
- name: github.com/go-openapi/jsonreference
version: 13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272
- name: github.com/go-openapi/loads
version: 18441dfa706d924a39a030ee2c3b1d8d81917b38
- name: github.com/go-openapi/runtime
version: 11e322eeecc1032d5a0a96c566ed53f2b5c26e22
- name: github.com/go-openapi/spec
version: e9fab754f5629065e6b7a6100301226545d4477e
- name: github.com/go-openapi/strfmt
version: dfda818c47a4ae5a1dde75ac776f34b2c95de993
- name: github.com/go-openapi/swag
version: 1d0bd113de87027671077d3c71eb3ac5d7dbba72
- name: github.com/go-openapi/validate
version: deaf2c9013bc1a7f4c774662259a506ba874d80f
- name: github.com/golang/protobuf
version: 874264fbbb43f4d91e999fecb4b40143ed611400
version: 2402d76f3d41f928c7902a765dfc872356dd3aad
subpackages:
- proto
- name: github.com/gorilla/context
version: aed02d124ae4a0e94fea4541c8effd05bf0c8296
- name: github.com/gorilla/mux
version: 9fa818a44c2bf1396a17f9d5a3c0f6dd39d2ff8e
- name: github.com/iron-io/common
version: 7c9faec363c808052742b4c4b84876c4c2172308
- name: github.com/iron-io/titan
version: 697a5466b096fee73202f5ddccf8213a2357e062
repo: git@github.com:iron-io/titan.git
vcs: git
subpackages:
- httpshutdown
- msgpack
- semaphore
- serverutil
- name: github.com/iron-io/go
version: 1ed3de151aa27db91d6df5dc8c8ce164c833b57c
- jobserver/models
- name: github.com/lib/pq
version: 3cd0097429be7d611bb644ef85b42bfb102ceea4
subpackages:
- common
- common/httpshutdown
- common/msgpack
- common/semaphore
- common/stats
- name: github.com/iron-io/golog
version: 5b80d97af5a2a5d386e7609efb82192ae99a7c67
- name: github.com/iron-io/iron_go
version: 920c950272e820d9e2562fcbf40303f05564f118
- oid
- name: github.com/mailru/easyjson
version: 97eee20abef76a0591155412cf0d04f24b05098f
subpackages:
- cache
- worker
- api
- config
- name: github.com/mattn/go-colorable
version: 9056b7a9f2d1f2d96498d6d146acd1f9d5ed3d59
- name: github.com/mattn/go-isatty
version: 56b76bdf51f7708750eac80fa38b952bb9f32639
- jlexer
- jwriter
- buffer
- name: github.com/manucorporat/sse
version: ee05b128a739a0fb76c7ebd3ae4810c1de808d6d
- name: github.com/PuerkitoBio/purell
version: 1d5d1cfad45d42ec5f81fa8ef23de09cebc6dcc3
- name: github.com/PuerkitoBio/urlesc
version: 5bd2802263f21d8788851d5305584c82a5c75d7e
- name: github.com/Sirupsen/logrus
version: 32055c351ea8b00b96d70f28db48d9840feaf0ec
- name: github.com/vmihailenco/bufio
version: 24e7e48f60fc2d9e99e43c07485d9fff42051e66
- name: github.com/vrischmann/envconfig
version: 9e6e1c4d3b73427d03118518603bb904d9c55236
version: a283a10442df8dc09befd873fab202bf8a253d6a
- name: golang.org/x/net
version: a728288923b47049b2ce791836767ffbe964a5bd
version: f315505cf3349909cdf013ea56690da34e96a451
subpackages:
- proxy
- context
- name: golang.org/x/sys
version: b518c298ac9dc94b6ac0757394f50d10c5dfa25a
version: a646d33e2ee3172a661fc09bca23bb4889a41bc8
subpackages:
- unix
- name: gopkg.in/inconshreveable/log15.v2
version: b105bd37f74e5d9dc7b6ad7806715c7a2b83fd3f
subpackages:
- stack
- term
- name: gopkg.in/mgo.v2
version: 29cc868a5ca65f401ff318143f9408d02f4799cc
subpackages:
- bson
devImports: []
- name: gopkg.in/go-playground/validator.v8
version: c193cecd124b5cc722d7ee5538e945bdb3348435
testImports: []

View File

@@ -1,9 +1,14 @@
package: github.com/iron-io/microgateway
package: github.com/iron-io/functions
import:
- package: github.com/gorilla/mux
- package: github.com/iron-io/common
- package: github.com/iron-io/golog
- package: github.com/iron-io/iron_go
- package: github.com/Sirupsen/logrus
- package: github.com/boltdb/bolt
- package: github.com/gin-gonic/gin
- package: github.com/go-openapi/errors
- package: github.com/go-openapi/strfmt
- package: github.com/go-openapi/validate
- package: github.com/iron-io/titan
repo: git@github.com:iron-io/titan.git
vcs: git
subpackages:
- cache
- worker
- jobserver/models
- package: github.com/lib/pq

5
hack/api.sh Executable file
View File

@@ -0,0 +1,5 @@
set -ex
docker run --rm -v "$PWD":/go/src/github.com/iron-io/functions -w /go/src/github.com/iron-io/functions iron/go:dev sh -c 'go build -o functions'
docker build -t iron/functions:latest .
docker run --rm -it -p 8080:8080 -e LOG_LEVEL=debug -v $PWD/bolt.db:/app/bolt.db iron/functions

View File

@@ -15,7 +15,8 @@ perl -i -pe 's/\d+\.\d+\.\K(\d+)/$1+1/e' $version_file
version=$(grep -m1 -Eo "[0-9]+\.[0-9]+\.[0-9]+" $version_file)
echo "Version: $version"
./build.sh
docker run --rm -v "$PWD":/go/src/github.com/iron-io/functions -w /go/src/github.com/iron-io/functions iron/go:dev sh -c 'go build -o functions'
docker build -t iron/functions:latest .
git add -u
git commit -m "$service: $version release"

View File

@@ -1,192 +0,0 @@
/* I wanted to do some stuff to this so had to make a copy. Namely:
- change the Host handling for virtual hosts.
- get errors if the proxy request fails
*/
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// HTTP reverse proxy handler
package main
import (
"io"
"log"
"net"
"net/http"
"net/url"
"strings"
"sync"
"time"
)
// onExitFlushLoop is a callback set by tests to detect the state of the
// flushLoop() goroutine.
var onExitFlushLoop func()
// ReverseProxy is an HTTP Handler that takes an incoming request and
// sends it to another server, proxying the response back to the
// client.
type ReverseProxy struct {
// Director must be a function which modifies
// the request into a new request to be sent
// using Transport. Its response is then copied
// back to the original client unmodified.
Director func(*http.Request)
// The transport used to perform proxy requests.
// If nil, http.DefaultTransport is used.
Transport http.RoundTripper
// FlushInterval specifies the flush interval
// to flush to the client while copying the
// response body.
// If zero, no periodic flushing is done.
FlushInterval time.Duration
}
func singleJoiningSlash(a, b string) string {
aslash := strings.HasSuffix(a, "/")
bslash := strings.HasPrefix(b, "/")
switch {
case aslash && bslash:
return a + b[1:]
case !aslash && !bslash:
return a + "/" + b
}
return a + b
}
// NewSingleHostReverseProxy returns a new ReverseProxy that rewrites
// URLs to the scheme, host, and base path provided in target. If the
// target's path is "/base" and the incoming request was for "/dir",
// the target request will be for /base/dir.
func NewSingleHostReverseProxy(target *url.URL) *ReverseProxy {
targetQuery := target.RawQuery
director := func(req *http.Request) {
req.URL.Scheme = target.Scheme
req.URL.Host = target.Host
req.URL.Path = singleJoiningSlash(target.Path, req.URL.Path)
if targetQuery == "" || req.URL.RawQuery == "" {
req.URL.RawQuery = targetQuery + req.URL.RawQuery
} else {
req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery
}
}
return &ReverseProxy{Director: director}
}
func copyHeader(dst, src http.Header) {
for k, vv := range src {
for _, v := range vv {
dst.Add(k, v)
}
}
}
func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) error {
transport := p.Transport
if transport == nil {
transport = http.DefaultTransport
}
outreq := new(http.Request)
*outreq = *req // includes shallow copies of maps, but okay
p.Director(outreq)
outreq.Proto = "HTTP/1.1"
outreq.ProtoMajor = 1
outreq.ProtoMinor = 1
outreq.Close = false
// Remove the connection header to the backend. We want a
// persistent connection, regardless of what the client sent
// to us. This is modifying the same underlying map from req
// (shallow copied above) so we only copy it if necessary.
if outreq.Header.Get("Connection") != "" {
outreq.Header = make(http.Header)
copyHeader(outreq.Header, req.Header)
outreq.Header.Del("Connection")
}
if clientIp, _, err := net.SplitHostPort(req.RemoteAddr); err == nil {
outreq.Header.Set("X-Forwarded-For", clientIp)
}
res, err := transport.RoundTrip(outreq)
if err != nil {
log.Printf("http: proxy error: %v", err)
// rw.WriteHeader(http.StatusInternalServerError)
return err
}
defer res.Body.Close()
copyHeader(rw.Header(), res.Header)
rw.WriteHeader(res.StatusCode)
p.copyResponse(rw, res.Body)
return nil
}
func (p *ReverseProxy) copyResponse(dst io.Writer, src io.Reader) {
if p.FlushInterval != 0 {
if wf, ok := dst.(writeFlusher); ok {
mlw := &maxLatencyWriter{
dst: wf,
latency: p.FlushInterval,
done: make(chan bool),
}
go mlw.flushLoop()
defer mlw.stop()
dst = mlw
}
}
io.Copy(dst, src)
}
type writeFlusher interface {
io.Writer
http.Flusher
}
type maxLatencyWriter struct {
dst writeFlusher
latency time.Duration
lk sync.Mutex // protects Write + Flush
done chan bool
}
func (m *maxLatencyWriter) Write(p []byte) (int, error) {
m.lk.Lock()
defer m.lk.Unlock()
return m.dst.Write(p)
}
func (m *maxLatencyWriter) flushLoop() {
t := time.NewTicker(m.latency)
defer t.Stop()
for {
select {
case <-m.done:
if onExitFlushLoop != nil {
onExitFlushLoop()
}
return
case <-t.C:
m.lk.Lock()
m.dst.Flush()
m.lk.Unlock()
}
}
panic("unreached")
}
func (m *maxLatencyWriter) stop() { m.done <- true }