From 6119f07007265cc8936f26c91fdb3cc32c9c4e69 Mon Sep 17 00:00:00 2001 From: Travis Reeder Date: Fri, 24 Feb 2017 16:04:04 -0800 Subject: [PATCH] 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. --- README.md | 17 ++++++-- docs/operating/extending.md | 6 ++- fn/Makefile | 10 ++++- fn/README.md | 1 + fn/routes.go | 77 +++++++++++++++++++++++++++---------- glide.lock | 28 +++++++++++--- glide.yaml | 2 + 7 files changed, 108 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 16951afbb..14be83d74 100644 --- a/README.md +++ b/README.md @@ -129,11 +129,11 @@ and deploy it. fn init $USERNAME/hello # build the function 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 -# push it to Docker Hub -fn push -# create an app +# Once it's ready, build and push it to Docker Hub +fn build && fn push +# create an app - you only do this once per app fn apps create myapp # create a route that maps /hello to your new function 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 +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 write your functions in AWS's [Lambda format](docs/lambda/README.md). diff --git a/docs/operating/extending.md b/docs/operating/extending.md index 473f616ea..1d87df292 100644 --- a/docs/operating/extending.md +++ b/docs/operating/extending.md @@ -67,14 +67,16 @@ See examples of this in [/examples/extensions/main.go](/examples/extensions/main ## Middleware -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. +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. NOTES: * 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. +See examples of this in [/examples/Middleware/main.go](/examples/middleware/main.go). + ## Special Handlers To understand how **Special Handlers** works you need to understand what are **Special Routes**. diff --git a/fn/Makefile b/fn/Makefile index 904a20179..de477320e 100644 --- a/fn/Makefile +++ b/fn/Makefile @@ -1,7 +1,9 @@ -all: vendor - go build -o fn +all: vendor build ./fn +build: + go build -o fn + docker: vendor GOOS=linux go build -o fn docker build -t iron/fn . @@ -17,3 +19,7 @@ release: GOOS=linux go build -o fn_linux GOOS=darwin go build -o fn_mac GOOS=windows go build -o fn.exe + +# install locally +install: build + sudo mv fn /usr/local/bin/ \ No newline at end of file diff --git a/fn/README.md b/fn/README.md index f5bc51547..119c00792 100644 --- a/fn/README.md +++ b/fn/README.md @@ -226,6 +226,7 @@ fn apps delete myapp ### Route management ``` 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 config set myapp /hello log_level info fn routes inspect myapp /hello diff --git a/fn/routes.go b/fn/routes.go index 2572af368..d2d8d0a15 100644 --- a/fn/routes.go +++ b/fn/routes.go @@ -14,6 +14,7 @@ import ( "text/tabwriter" "time" + "github.com/Sirupsen/logrus" fnclient "github.com/iron-io/functions_go/client" apiroutes "github.com/iron-io/functions_go/client/routes" "github.com/iron-io/functions_go/models" @@ -53,7 +54,7 @@ func routes() cli.Command { Name: "create", Aliases: []string{"c"}, Usage: "create a route in an `app`", - ArgsUsage: "`app` /path image/name", + ArgsUsage: "`app` /path [image]", Action: r.create, Flags: []cli.Flag{ cli.Int64Flag{ @@ -91,7 +92,7 @@ func routes() cli.Command { Name: "update", Aliases: []string{"u"}, Usage: "update a route in an `app`", - ArgsUsage: "`app` /path", + ArgsUsage: "`app` /path [image]", Action: r.update, Flags: []cli.Flag{ cli.StringFlag{ @@ -179,8 +180,8 @@ func call() cli.Command { } func (a *routesCmd) list(c *cli.Context) error { - if c.Args().First() == "" { - return errors.New("error: routes listing takes one argument, an app name") + if len(c.Args()) < 1 { + return errors.New("error: routes listing takes one argument: an app name") } 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 { - if c.Args().Get(0) == "" || c.Args().Get(1) == "" { - return errors.New("error: routes listing takes three arguments: an app name and a route") + if len(c.Args()) < 2 { + return errors.New("error: routes listing takes three arguments: an app name and a path") } appName := c.Args().Get(0) @@ -278,8 +279,9 @@ func envAsHeader(req *http.Request, selectedEnv []string) { } func (a *routesCmd) create(c *cli.Context) error { - if c.Args().Get(0) == "" || c.Args().Get(1) == "" || c.Args().Get(2) == "" { - return errors.New("error: routes creation takes at least three arguments: app name, route path and image name") + // todo: @pedro , why aren't you just checking the length here? + 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) @@ -291,6 +293,7 @@ func (a *routesCmd) create(c *cli.Context) error { timeout time.Duration ) 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() if err != nil { 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 { - if c.Args().Get(0) == "" || c.Args().Get(1) == "" { - return errors.New("error: route configuration description takes two arguments: an app name and a route") + if len(c.Args()) < 2 { + return errors.New("error: route update takes at least two arguments: an app name and a path") } appName := c.Args().Get(0) route := c.Args().Get(1) - + image := c.Args().Get(2) var ( format string maxC int 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 != "" { format = f @@ -485,7 +522,7 @@ func (a *routesCmd) update(c *cli.Context) error { to := int64(timeout.Seconds()) patchRoute := &fnmodels.Route{ - Image: c.String("image"), + Image: image, Memory: c.Int64("memory"), Type: c.String("type"), Config: extractEnvConfig(c.StringSlice("config")), @@ -495,7 +532,7 @@ func (a *routesCmd) update(c *cli.Context) error { Timeout: &to, } - err := a.patchRoute(appName, route, patchRoute) + err = a.patchRoute(appName, route, patchRoute) if err != nil { return err } @@ -505,8 +542,8 @@ func (a *routesCmd) update(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) == "" { - return errors.New("error: route configuration setting takes four arguments: an app name, a route, a key and a value") + if len(c.Args()) < 4 { + 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) @@ -530,8 +567,8 @@ func (a *routesCmd) configSet(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) == "" { - return errors.New("error: route configuration setting takes four arguments: an app name, a route and a key") + if len(c.Args()) < 3 { + return errors.New("error: route configuration updates take three arguments: an app name, a path and a key") } 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 { - 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") } @@ -607,8 +644,8 @@ func (a *routesCmd) inspect(c *cli.Context) error { } func (a *routesCmd) delete(c *cli.Context) error { - if c.Args().Get(0) == "" || c.Args().Get(1) == "" { - return errors.New("error: routes listing takes three arguments: an app name and a path") + if len(c.Args()) < 2 { + return errors.New("error: routes delete takes two arguments: an app name and a path") } appName := c.Args().Get(0) diff --git a/glide.lock b/glide.lock index 8c5b0762a..1568e4194 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: 78692441d2595a5a303c64d4884fd4d04eebfd6a382ddd166176548d9da02645 -updated: 2017-01-18T21:41:13.698052314+01:00 +hash: 01f9cff01b9ee5c1d8c37c86779ab6bbd91278394e526f921f399f10a0523698 +updated: 2017-02-21T08:50:25.925523311-08:00 imports: - name: github.com/amir/raidman version: c74861fe6a7bb8ede0a010ce4485bdbb4fc4c985 @@ -107,7 +107,7 @@ imports: - name: github.com/fsnotify/fsnotify version: fd9ec7deca8bf46ecd2a795baaacf2b3a9be1197 - name: github.com/fsouza/go-dockerclient - version: e085edda407c05214cc6e71e4881de47667e77ec + version: 364c822d280c4f34afc3339e50d4fc0129d6b5ec - name: github.com/garyburd/redigo version: 0708def8b0cf3a05acdf44a7f28b864c2958921d subpackages: @@ -135,8 +135,12 @@ imports: version: 36d33bfe519efae5632669801b180bf1a245da3b - name: github.com/go-openapi/loads version: 315567415dfd74b651f7a62cabfc82a57ed7b9ad + subpackages: + - fmts - name: github.com/go-openapi/runtime version: 14b161b40ece9dac8e244ab2fde2d209e108c6f5 + subpackages: + - client - name: github.com/go-openapi/spec version: f7ae86df5bc115a2744343016c789a89f065a4bd - name: github.com/go-openapi/strfmt @@ -145,6 +149,8 @@ imports: version: 3b6d86cd965820f968760d5d419cb4add096bdd7 - name: github.com/go-openapi/validate version: 027696d4b54399770f1cdcc6c6daa56975f9e14e +- name: github.com/go-resty/resty + version: ef723efa2a1b4fcdbafb5b1e7c6cf42065519728 - name: github.com/golang/groupcache version: 72d04f9fcdec7d3821820cc4a6f150eae553639a subpackages: @@ -178,9 +184,18 @@ imports: - json/scanner - json/token - name: github.com/heroku/docker-registry-client - version: 36bd5f538a6b9e70f2d863c9a8f6bf955a98eddc + version: 95467b6cacee2a06f112a3cf7e47a70fad6000cf subpackages: - 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 version: b50ecf8ff90187fc5fabccd9d028dd461adce4ee subpackages: @@ -239,6 +254,8 @@ imports: version: 017119f7a78a0b5fc0ea39ef6be09f03acf3345d - name: github.com/pivotal-golang/bytefmt version: b12c1522f4cbb5f35861bd5dd2c39a4fa996441a +- name: github.com/pkg/errors + version: 248dadf4e9068a0b3e79f02ed0a610d935de5302 - name: github.com/PuerkitoBio/purell version: 0bcb03f4b4d0a9428594752bd2a3b9aa0a9d4bd4 - name: github.com/PuerkitoBio/urlesc @@ -246,7 +263,7 @@ imports: - name: github.com/satori/go.uuid version: 879c5887cd475cd7864858769793b2ceb0d44feb - name: github.com/Sirupsen/logrus - version: d26492970760ca5d33129d2d799e34be5c4782eb + version: c078b1e43f58d563c74cebe63c85789e76ddb627 subpackages: - hooks/syslog - name: github.com/spf13/afero @@ -275,6 +292,7 @@ imports: - context/ctxhttp - idna - proxy + - publicsuffix - name: golang.org/x/sys version: 478fcf54317e52ab69f40bb4c7a1520288d7f7ea subpackages: diff --git a/glide.yaml b/glide.yaml index 234a5db3a..3001d2c81 100644 --- a/glide.yaml +++ b/glide.yaml @@ -31,6 +31,8 @@ import: - package: github.com/ccirello/supervisor version: v0.5.1 - package: github.com/iron-io/runner +- package: github.com/iron-io/functions_go + version: master - package: github.com/golang/groupcache subpackages: - consistenthash