Fixes some route creation and updating bugs. (#526)

* Fixes some route creation and updating bugs.

* Updated README

* Added more info the quickstart

* Updated based on PR comments.

* Fixed based on comments.

* Updated per comments.
This commit is contained in:
Travis Reeder
2017-02-24 16:04:04 -08:00
committed by GitHub
parent bc9f15d5f4
commit 6119f07007
7 changed files with 108 additions and 33 deletions

View File

@@ -129,11 +129,11 @@ and deploy it.
fn init $USERNAME/hello fn init $USERNAME/hello
# build the function # build the function
fn build fn build
# test it # test it - you can pass data into it too by piping it in, eg: `cat hello.payload.json | fn run`
fn run fn run
# push it to Docker Hub # Once it's ready, build and push it to Docker Hub
fn push fn build && fn push
# create an app # create an app - you only do this once per app
fn apps create myapp fn apps create myapp
# create a route that maps /hello to your new function # create a route that maps /hello to your new function
fn routes create myapp /hello fn routes create myapp /hello
@@ -147,6 +147,15 @@ curl http://localhost:8080/r/myapp/hello
Or surf to it: http://localhost:8080/r/myapp/hello Or surf to it: http://localhost:8080/r/myapp/hello
To update your function:
```sh
# update a function with a new version and push it
fn bump && fn build && fn push
# then update the route
fn routes update myapp /hello
```
See below for more details. And you can find a bunch of examples in various languages in the [examples](examples/) directory. You can also See below for more details. And 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).

View File

@@ -67,14 +67,16 @@ See examples of this in [/examples/extensions/main.go](/examples/extensions/main
## Middleware ## Middleware
Middleware enables you to add functionality to every API request. For every request, the chain of Middleware will be called Middleware enables you to add functionality to every API request. For every request, the chain of Middleware will be called
in order allowing you to modify or reject requests, as well as write output and cancel the chain. in order allowing you to modify or reject requests, as well as write output and cancel the chain.
NOTES: NOTES:
* middleware is responsible for writing output if it's going to cancel the chain. * middleware is responsible for writing output if it's going to cancel the chain.
* cancel the chain by returning an error from your Middleware's Serve method. * cancel the chain by returning an error from your Middleware's Serve method.
See examples of this in [/examples/Middleware/main.go](/examples/middleware/main.go).
## Special Handlers ## Special Handlers
To understand how **Special Handlers** works you need to understand what are **Special Routes**. To understand how **Special Handlers** works you need to understand what are **Special Routes**.

View File

@@ -1,7 +1,9 @@
all: vendor all: vendor build
go build -o fn
./fn ./fn
build:
go build -o fn
docker: vendor docker: vendor
GOOS=linux go build -o fn GOOS=linux go build -o fn
docker build -t iron/fn . docker build -t iron/fn .
@@ -17,3 +19,7 @@ release:
GOOS=linux go build -o fn_linux GOOS=linux go build -o fn_linux
GOOS=darwin go build -o fn_mac GOOS=darwin go build -o fn_mac
GOOS=windows go build -o fn.exe GOOS=windows go build -o fn.exe
# install locally
install: build
sudo mv fn /usr/local/bin/

View File

@@ -226,6 +226,7 @@ fn apps delete myapp
### Route management ### Route management
``` ```
fn routes create myapp /hello iron/hello fn routes create myapp /hello iron/hello
# routes update will also update any changes in the func.yaml file too.
fn routes update myapp /hello --timeout 30 --type async fn routes update myapp /hello --timeout 30 --type async
fn routes config set myapp /hello log_level info fn routes config set myapp /hello log_level info
fn routes inspect myapp /hello fn routes inspect myapp /hello

View File

@@ -14,6 +14,7 @@ import (
"text/tabwriter" "text/tabwriter"
"time" "time"
"github.com/Sirupsen/logrus"
fnclient "github.com/iron-io/functions_go/client" fnclient "github.com/iron-io/functions_go/client"
apiroutes "github.com/iron-io/functions_go/client/routes" apiroutes "github.com/iron-io/functions_go/client/routes"
"github.com/iron-io/functions_go/models" "github.com/iron-io/functions_go/models"
@@ -53,7 +54,7 @@ func routes() cli.Command {
Name: "create", Name: "create",
Aliases: []string{"c"}, Aliases: []string{"c"},
Usage: "create a route in an `app`", Usage: "create a route in an `app`",
ArgsUsage: "`app` /path image/name", ArgsUsage: "`app` /path [image]",
Action: r.create, Action: r.create,
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.Int64Flag{ cli.Int64Flag{
@@ -91,7 +92,7 @@ func routes() cli.Command {
Name: "update", Name: "update",
Aliases: []string{"u"}, Aliases: []string{"u"},
Usage: "update a route in an `app`", Usage: "update a route in an `app`",
ArgsUsage: "`app` /path", ArgsUsage: "`app` /path [image]",
Action: r.update, Action: r.update,
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.StringFlag{ cli.StringFlag{
@@ -179,8 +180,8 @@ func call() cli.Command {
} }
func (a *routesCmd) list(c *cli.Context) error { func (a *routesCmd) list(c *cli.Context) error {
if c.Args().First() == "" { if len(c.Args()) < 1 {
return errors.New("error: routes listing takes one argument, an app name") return errors.New("error: routes listing takes one argument: an app name")
} }
appName := c.Args().Get(0) appName := c.Args().Get(0)
@@ -217,8 +218,8 @@ func (a *routesCmd) list(c *cli.Context) error {
} }
func (a *routesCmd) call(c *cli.Context) error { func (a *routesCmd) call(c *cli.Context) error {
if c.Args().Get(0) == "" || c.Args().Get(1) == "" { if len(c.Args()) < 2 {
return errors.New("error: routes listing takes three arguments: an app name and a route") return errors.New("error: routes listing takes three arguments: an app name and a path")
} }
appName := c.Args().Get(0) appName := c.Args().Get(0)
@@ -278,8 +279,9 @@ func envAsHeader(req *http.Request, selectedEnv []string) {
} }
func (a *routesCmd) create(c *cli.Context) error { func (a *routesCmd) create(c *cli.Context) error {
if c.Args().Get(0) == "" || c.Args().Get(1) == "" || c.Args().Get(2) == "" { // todo: @pedro , why aren't you just checking the length here?
return errors.New("error: routes creation takes at least three arguments: app name, route path and image name") if len(c.Args()) < 2 {
return errors.New("error: routes listing takes at least two arguments: an app name and a path")
} }
appName := c.Args().Get(0) appName := c.Args().Get(0)
@@ -291,6 +293,7 @@ func (a *routesCmd) create(c *cli.Context) error {
timeout time.Duration timeout time.Duration
) )
if image == "" { if image == "" {
// todo: why do we only load the func file if image isn't set? Don't we need to read the rest of these things regardless?
ff, err := loadFuncfile() ff, err := loadFuncfile()
if err != nil { if err != nil {
if _, ok := err.(*notFoundError); ok { if _, ok := err.(*notFoundError); ok {
@@ -454,18 +457,52 @@ func (a *routesCmd) patchRoute(appName, routePath string, r *fnmodels.Route) err
} }
func (a *routesCmd) update(c *cli.Context) error { func (a *routesCmd) update(c *cli.Context) error {
if c.Args().Get(0) == "" || c.Args().Get(1) == "" { if len(c.Args()) < 2 {
return errors.New("error: route configuration description takes two arguments: an app name and a route") return errors.New("error: route update takes at least two arguments: an app name and a path")
} }
appName := c.Args().Get(0) appName := c.Args().Get(0)
route := c.Args().Get(1) route := c.Args().Get(1)
image := c.Args().Get(2)
var ( var (
format string format string
maxC int maxC int
timeout time.Duration timeout time.Duration
) )
ff, err := loadFuncfile()
if err != nil {
if _, ok := err.(*notFoundError); ok {
if image == "" {
// the no image flag or func file
return errors.New("error: image name is missing or no function file found")
}
logrus.Warnln("func file not found, continuing...")
} else {
return err
}
}
if image != "" { // flags take precedence
image = ff.FullName()
}
if ff.Format != nil {
format = *ff.Format
}
if ff.maxConcurrency != nil {
maxC = *ff.maxConcurrency
}
if ff.Timeout != nil {
timeout = *ff.Timeout
}
if route == "" && ff.path != nil {
route = *ff.path
}
if route == "" {
return errors.New("error: route path is missing")
}
// if image == "" {
// return errors.New("error: function image name is missing")
// }
if f := c.String("format"); f != "" { if f := c.String("format"); f != "" {
format = f format = f
@@ -485,7 +522,7 @@ func (a *routesCmd) update(c *cli.Context) error {
to := int64(timeout.Seconds()) to := int64(timeout.Seconds())
patchRoute := &fnmodels.Route{ patchRoute := &fnmodels.Route{
Image: c.String("image"), Image: image,
Memory: c.Int64("memory"), Memory: c.Int64("memory"),
Type: c.String("type"), Type: c.String("type"),
Config: extractEnvConfig(c.StringSlice("config")), Config: extractEnvConfig(c.StringSlice("config")),
@@ -495,7 +532,7 @@ func (a *routesCmd) update(c *cli.Context) error {
Timeout: &to, Timeout: &to,
} }
err := a.patchRoute(appName, route, patchRoute) err = a.patchRoute(appName, route, patchRoute)
if err != nil { if err != nil {
return err return err
} }
@@ -505,8 +542,8 @@ func (a *routesCmd) update(c *cli.Context) error {
} }
func (a *routesCmd) configSet(c *cli.Context) error { func (a *routesCmd) configSet(c *cli.Context) error {
if c.Args().Get(0) == "" || c.Args().Get(1) == "" || c.Args().Get(2) == "" { if len(c.Args()) < 4 {
return errors.New("error: route configuration setting takes four arguments: an app name, a route, a key and a value") return errors.New("error: route configuration updates tak four arguments: an app name, a path, a key and a value")
} }
appName := c.Args().Get(0) appName := c.Args().Get(0)
@@ -530,8 +567,8 @@ func (a *routesCmd) configSet(c *cli.Context) error {
} }
func (a *routesCmd) configUnset(c *cli.Context) error { func (a *routesCmd) configUnset(c *cli.Context) error {
if c.Args().Get(0) == "" || c.Args().Get(1) == "" || c.Args().Get(2) == "" { if len(c.Args()) < 3 {
return errors.New("error: route configuration setting takes four arguments: an app name, a route and a key") return errors.New("error: route configuration updates take three arguments: an app name, a path and a key")
} }
appName := c.Args().Get(0) appName := c.Args().Get(0)
@@ -554,7 +591,7 @@ func (a *routesCmd) configUnset(c *cli.Context) error {
} }
func (a *routesCmd) inspect(c *cli.Context) error { func (a *routesCmd) inspect(c *cli.Context) error {
if c.Args().Get(0) == "" || c.Args().Get(1) == "" { if len(c.Args()) < 2 {
return errors.New("error: routes listing takes three arguments: an app name and a path") return errors.New("error: routes listing takes three arguments: an app name and a path")
} }
@@ -607,8 +644,8 @@ func (a *routesCmd) inspect(c *cli.Context) error {
} }
func (a *routesCmd) delete(c *cli.Context) error { func (a *routesCmd) delete(c *cli.Context) error {
if c.Args().Get(0) == "" || c.Args().Get(1) == "" { if len(c.Args()) < 2 {
return errors.New("error: routes listing takes three arguments: an app name and a path") return errors.New("error: routes delete takes two arguments: an app name and a path")
} }
appName := c.Args().Get(0) appName := c.Args().Get(0)

28
glide.lock generated
View File

@@ -1,5 +1,5 @@
hash: 78692441d2595a5a303c64d4884fd4d04eebfd6a382ddd166176548d9da02645 hash: 01f9cff01b9ee5c1d8c37c86779ab6bbd91278394e526f921f399f10a0523698
updated: 2017-01-18T21:41:13.698052314+01:00 updated: 2017-02-21T08:50:25.925523311-08:00
imports: imports:
- name: github.com/amir/raidman - name: github.com/amir/raidman
version: c74861fe6a7bb8ede0a010ce4485bdbb4fc4c985 version: c74861fe6a7bb8ede0a010ce4485bdbb4fc4c985
@@ -107,7 +107,7 @@ imports:
- name: github.com/fsnotify/fsnotify - name: github.com/fsnotify/fsnotify
version: fd9ec7deca8bf46ecd2a795baaacf2b3a9be1197 version: fd9ec7deca8bf46ecd2a795baaacf2b3a9be1197
- name: github.com/fsouza/go-dockerclient - name: github.com/fsouza/go-dockerclient
version: e085edda407c05214cc6e71e4881de47667e77ec version: 364c822d280c4f34afc3339e50d4fc0129d6b5ec
- name: github.com/garyburd/redigo - name: github.com/garyburd/redigo
version: 0708def8b0cf3a05acdf44a7f28b864c2958921d version: 0708def8b0cf3a05acdf44a7f28b864c2958921d
subpackages: subpackages:
@@ -135,8 +135,12 @@ imports:
version: 36d33bfe519efae5632669801b180bf1a245da3b version: 36d33bfe519efae5632669801b180bf1a245da3b
- name: github.com/go-openapi/loads - name: github.com/go-openapi/loads
version: 315567415dfd74b651f7a62cabfc82a57ed7b9ad version: 315567415dfd74b651f7a62cabfc82a57ed7b9ad
subpackages:
- fmts
- name: github.com/go-openapi/runtime - name: github.com/go-openapi/runtime
version: 14b161b40ece9dac8e244ab2fde2d209e108c6f5 version: 14b161b40ece9dac8e244ab2fde2d209e108c6f5
subpackages:
- client
- name: github.com/go-openapi/spec - name: github.com/go-openapi/spec
version: f7ae86df5bc115a2744343016c789a89f065a4bd version: f7ae86df5bc115a2744343016c789a89f065a4bd
- name: github.com/go-openapi/strfmt - name: github.com/go-openapi/strfmt
@@ -145,6 +149,8 @@ imports:
version: 3b6d86cd965820f968760d5d419cb4add096bdd7 version: 3b6d86cd965820f968760d5d419cb4add096bdd7
- name: github.com/go-openapi/validate - name: github.com/go-openapi/validate
version: 027696d4b54399770f1cdcc6c6daa56975f9e14e version: 027696d4b54399770f1cdcc6c6daa56975f9e14e
- name: github.com/go-resty/resty
version: ef723efa2a1b4fcdbafb5b1e7c6cf42065519728
- name: github.com/golang/groupcache - name: github.com/golang/groupcache
version: 72d04f9fcdec7d3821820cc4a6f150eae553639a version: 72d04f9fcdec7d3821820cc4a6f150eae553639a
subpackages: subpackages:
@@ -178,9 +184,18 @@ imports:
- json/scanner - json/scanner
- json/token - json/token
- name: github.com/heroku/docker-registry-client - name: github.com/heroku/docker-registry-client
version: 36bd5f538a6b9e70f2d863c9a8f6bf955a98eddc version: 95467b6cacee2a06f112a3cf7e47a70fad6000cf
subpackages: subpackages:
- registry - registry
- name: github.com/iron-io/functions_go
version: 69e4dec8454c3c710045263c2ede76139c141146
subpackages:
- client
- client/apps
- client/routes
- client/tasks
- client/version
- models
- name: github.com/iron-io/iron_go3 - name: github.com/iron-io/iron_go3
version: b50ecf8ff90187fc5fabccd9d028dd461adce4ee version: b50ecf8ff90187fc5fabccd9d028dd461adce4ee
subpackages: subpackages:
@@ -239,6 +254,8 @@ imports:
version: 017119f7a78a0b5fc0ea39ef6be09f03acf3345d version: 017119f7a78a0b5fc0ea39ef6be09f03acf3345d
- name: github.com/pivotal-golang/bytefmt - name: github.com/pivotal-golang/bytefmt
version: b12c1522f4cbb5f35861bd5dd2c39a4fa996441a version: b12c1522f4cbb5f35861bd5dd2c39a4fa996441a
- name: github.com/pkg/errors
version: 248dadf4e9068a0b3e79f02ed0a610d935de5302
- name: github.com/PuerkitoBio/purell - name: github.com/PuerkitoBio/purell
version: 0bcb03f4b4d0a9428594752bd2a3b9aa0a9d4bd4 version: 0bcb03f4b4d0a9428594752bd2a3b9aa0a9d4bd4
- name: github.com/PuerkitoBio/urlesc - name: github.com/PuerkitoBio/urlesc
@@ -246,7 +263,7 @@ imports:
- name: github.com/satori/go.uuid - name: github.com/satori/go.uuid
version: 879c5887cd475cd7864858769793b2ceb0d44feb version: 879c5887cd475cd7864858769793b2ceb0d44feb
- name: github.com/Sirupsen/logrus - name: github.com/Sirupsen/logrus
version: d26492970760ca5d33129d2d799e34be5c4782eb version: c078b1e43f58d563c74cebe63c85789e76ddb627
subpackages: subpackages:
- hooks/syslog - hooks/syslog
- name: github.com/spf13/afero - name: github.com/spf13/afero
@@ -275,6 +292,7 @@ imports:
- context/ctxhttp - context/ctxhttp
- idna - idna
- proxy - proxy
- publicsuffix
- name: golang.org/x/sys - name: golang.org/x/sys
version: 478fcf54317e52ab69f40bb4c7a1520288d7f7ea version: 478fcf54317e52ab69f40bb4c7a1520288d7f7ea
subpackages: subpackages:

View File

@@ -31,6 +31,8 @@ import:
- package: github.com/ccirello/supervisor - package: github.com/ccirello/supervisor
version: v0.5.1 version: v0.5.1
- package: github.com/iron-io/runner - package: github.com/iron-io/runner
- package: github.com/iron-io/functions_go
version: master
- package: github.com/golang/groupcache - package: github.com/golang/groupcache
subpackages: subpackages:
- consistenthash - consistenthash