fn improvements: (#560)

- standardized required args validation
- routes create/update now prioritize args, over flags, over funcfile configuration
- removed deadcode
This commit is contained in:
Pedro Nasser
2017-03-01 22:55:48 -03:00
committed by Travis Reeder
parent 2772afb5f0
commit dea100d3d9
10 changed files with 139 additions and 188 deletions

View File

@@ -192,7 +192,7 @@ can use -- yes, you can share functions! The source code for this function is in
You can read more about [writing your own functions here](docs/writing.md). You can read more about [writing your own functions here](docs/writing.md).
```sh ```sh
fn routes create myapp /hello iron/hello fn routes create myapp /hello -i iron/hello
``` ```
Or using cURL: Or using cURL:

View File

@@ -58,7 +58,7 @@ Note: Route level configuration overrides app level configuration.
Using `fn`: Using `fn`:
```sh ```sh
fn routes create --config k1=v1 --config k2=v2 myapp /path image fn routes create myapp /path --config k1=v1 --config k2=v2 --image iron/hello
``` ```
Or using a cURL: Or using a cURL:

View File

@@ -34,7 +34,7 @@ This will create a docker image and push the image to docker.
## Publishing to IronFunctions ## Publishing to IronFunctions
```bash ```bash
fn routes create <app_name> fn routes create <app_name> </path>
``` ```
This creates a full path in the form of `http://<host>:<port>/r/<app_name>/<function>` This creates a full path in the form of `http://<host>:<port>/r/<app_name>/<function>`

View File

@@ -24,15 +24,14 @@ func apps() cli.Command {
a := appsCmd{client: apiClient()} a := appsCmd{client: apiClient()}
return cli.Command{ return cli.Command{
Name: "apps", Name: "apps",
Usage: "manage applications", Usage: "manage applications",
ArgsUsage: "fn apps",
Subcommands: []cli.Command{ Subcommands: []cli.Command{
{ {
Name: "create", Name: "create",
Aliases: []string{"c"}, Aliases: []string{"c"},
Usage: "create a new app", Usage: "create a new app",
ArgsUsage: "`app`", ArgsUsage: "<app>",
Action: a.create, Action: a.create,
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.StringSliceFlag{ cli.StringSliceFlag{
@@ -45,14 +44,14 @@ func apps() cli.Command {
Name: "inspect", Name: "inspect",
Aliases: []string{"i"}, Aliases: []string{"i"},
Usage: "retrieve one or all apps properties", Usage: "retrieve one or all apps properties",
ArgsUsage: "`app` [property.[key]]", ArgsUsage: "<app> [property.[key]]",
Action: a.inspect, Action: a.inspect,
}, },
{ {
Name: "update", Name: "update",
Aliases: []string{"u"}, Aliases: []string{"u"},
Usage: "update an `app`", Usage: "update an `app`",
ArgsUsage: "`app`", ArgsUsage: "<app>",
Action: a.update, Action: a.update,
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.StringSliceFlag{ cli.StringSliceFlag{
@@ -69,14 +68,14 @@ func apps() cli.Command {
Name: "set", Name: "set",
Aliases: []string{"s"}, Aliases: []string{"s"},
Usage: "store a configuration key for this application", Usage: "store a configuration key for this application",
ArgsUsage: "`app` <key> <value>", ArgsUsage: "<app> <key> <value>",
Action: a.configSet, Action: a.configSet,
}, },
{ {
Name: "unset", Name: "unset",
Aliases: []string{"u"}, Aliases: []string{"u"},
Usage: "remove a configuration key for this application", Usage: "remove a configuration key for this application",
ArgsUsage: "`app` <key>", ArgsUsage: "<app> <key>",
Action: a.configUnset, Action: a.configUnset,
}, },
}, },
@@ -124,10 +123,6 @@ func (a *appsCmd) list(c *cli.Context) error {
} }
func (a *appsCmd) create(c *cli.Context) error { func (a *appsCmd) create(c *cli.Context) error {
if c.Args().First() == "" {
return errors.New("error: missing app name after create command")
}
body := &models.AppWrapper{App: &models.App{ body := &models.AppWrapper{App: &models.App{
Name: c.Args().Get(0), Name: c.Args().Get(0),
Config: extractEnvConfig(c.StringSlice("config")), Config: extractEnvConfig(c.StringSlice("config")),
@@ -155,10 +150,6 @@ func (a *appsCmd) create(c *cli.Context) error {
} }
func (a *appsCmd) update(c *cli.Context) error { func (a *appsCmd) update(c *cli.Context) error {
if c.Args().First() == "" {
return errors.New("error: missing app name after update command")
}
appName := c.Args().First() appName := c.Args().First()
patchedApp := &functions.App{ patchedApp := &functions.App{
@@ -175,10 +166,6 @@ func (a *appsCmd) update(c *cli.Context) error {
} }
func (a *appsCmd) configSet(c *cli.Context) error { func (a *appsCmd) configSet(c *cli.Context) error {
if c.Args().Get(0) == "" || c.Args().Get(1) == "" || c.Args().Get(2) == "" {
return errors.New("error: application configuration setting takes three arguments: an app name, a key and a value")
}
appName := c.Args().Get(0) appName := c.Args().Get(0)
key := c.Args().Get(1) key := c.Args().Get(1)
value := c.Args().Get(2) value := c.Args().Get(2)
@@ -198,10 +185,6 @@ func (a *appsCmd) configSet(c *cli.Context) error {
} }
func (a *appsCmd) configUnset(c *cli.Context) error { func (a *appsCmd) configUnset(c *cli.Context) error {
if c.Args().Get(0) == "" || c.Args().Get(1) == "" {
return errors.New("error: application configuration setting takes three arguments: an app name, a key and a value")
}
appName := c.Args().Get(0) appName := c.Args().Get(0)
key := c.Args().Get(1) key := c.Args().Get(1)

View File

@@ -21,7 +21,7 @@ func deploy() cli.Command {
flags = append(flags, cmd.flags()...) flags = append(flags, cmd.flags()...)
return cli.Command{ return cli.Command{
Name: "deploy", Name: "deploy",
ArgsUsage: "`APPNAME`", ArgsUsage: "<appName>",
Usage: "scan local directory for functions, build and push all of them to `APPNAME`.", Usage: "scan local directory for functions, build and push all of them to `APPNAME`.",
Flags: flags, Flags: flags,
Action: cmd.scan, Action: cmd.scan,
@@ -68,9 +68,6 @@ func (p *deploycmd) flags() []cli.Flag {
} }
func (p *deploycmd) scan(c *cli.Context) error { func (p *deploycmd) scan(c *cli.Context) error {
if c.Args().First() == "" {
return errors.New("application name is missing")
}
p.appName = c.Args().First() p.appName = c.Args().First()
p.verbwriter = verbwriter(p.verbose) p.verbwriter = verbwriter(p.verbose)

View File

@@ -11,9 +11,8 @@ type imagesCmd struct {
func images() cli.Command { func images() cli.Command {
return cli.Command{ return cli.Command{
Name: "images", Name: "images",
Usage: "manage function images", Usage: "manage function images",
ArgsUsage: "fn images",
Subcommands: []cli.Command{ Subcommands: []cli.Command{
build(), build(),
deploy(), deploy(),

View File

@@ -35,28 +35,27 @@ func lambda() cli.Command {
flags = append(flags, getFlags()...) flags = append(flags, getFlags()...)
return cli.Command{ return cli.Command{
Name: "lambda", Name: "lambda",
Usage: "create and publish lambda functions", Usage: "create and publish lambda functions",
ArgsUsage: "fn lambda",
Subcommands: []cli.Command{ Subcommands: []cli.Command{
{ {
Name: "create-function", Name: "create-function",
Usage: `create Docker image that can run your Lambda function, where files are the contents of the zip file to be uploaded to AWS Lambda.`, Usage: `create Docker image that can run your Lambda function, where files are the contents of the zip file to be uploaded to AWS Lambda.`,
ArgsUsage: "name runtime handler /path [/paths...]", ArgsUsage: "<name> <runtime> <handler> </path> [/paths...]",
Action: create, Action: create,
Flags: flags, Flags: flags,
}, },
{ {
Name: "test-function", Name: "test-function",
Usage: `runs local dockerized Lambda function and writes output to stdout.`, Usage: `runs local dockerized Lambda function and writes output to stdout.`,
ArgsUsage: "name [--payload <value>]", ArgsUsage: "<name>",
Action: test, Action: test,
Flags: flags, Flags: flags,
}, },
{ {
Name: "aws-import", Name: "aws-import",
Usage: `converts an existing Lambda function to an image, where the function code is downloaded to a directory in the current working directory that has the same name as the Lambda function.`, Usage: `converts an existing Lambda function to an image, where the function code is downloaded to a directory in the current working directory that has the same name as the Lambda function.`,
ArgsUsage: "arn region image/name [--profile <aws profile>] [--version <version>] [--download-only]", ArgsUsage: "<arn> <region> <image/name>",
Action: awsImport, Action: awsImport,
Flags: flags, Flags: flags,
}, },
@@ -103,9 +102,6 @@ func transcribeEnvConfig(configs []string) map[string]string {
func create(c *cli.Context) error { func create(c *cli.Context) error {
args := c.Args() args := c.Args()
if len(args) < 4 {
return fmt.Errorf("Expected at least 4 arguments, NAME RUNTIME HANDLER and file %d", len(args))
}
functionName := args[0] functionName := args[0]
runtime := args[1] runtime := args[1]
handler := args[2] handler := args[2]
@@ -186,9 +182,6 @@ func test(c *cli.Context) error {
func awsImport(c *cli.Context) error { func awsImport(c *cli.Context) error {
args := c.Args() args := c.Args()
if len(args) < 3 {
return fmt.Errorf("Missing arguments ARN, REGION and/or IMAGE")
}
version := c.String("version") version := c.String("version")
downloadOnly := c.Bool("download-only") downloadOnly := c.Bool("download-only")

View File

@@ -1,9 +1,11 @@
package main package main
import ( import (
"bytes"
"fmt" "fmt"
"net/url" "net/url"
"os" "os"
"strings"
vers "github.com/iron-io/functions/api/version" vers "github.com/iron-io/functions/api/version"
functions "github.com/iron-io/functions_go" functions "github.com/iron-io/functions_go"
@@ -76,9 +78,49 @@ GLOBAL OPTIONS:
version(), version(),
} }
app.Commands = append(app.Commands, aliasesFn()...) app.Commands = append(app.Commands, aliasesFn()...)
prepareCmdArgsValidation(app.Commands)
return app return app
} }
func parseArgs(c *cli.Context) ([]string, []string) {
args := strings.Split(c.Command.ArgsUsage, " ")
var reqArgs []string
var optArgs []string
for _, arg := range args {
if strings.HasPrefix(arg, "[") {
optArgs = append(optArgs, arg)
} else {
reqArgs = append(reqArgs, arg)
}
}
return reqArgs, optArgs
}
func prepareCmdArgsValidation(cmds []cli.Command) {
// TODO: refactor fn to use urfave/cli.v2
// v1 doesn't let us validate args before the cmd.Action
for i, cmd := range cmds {
prepareCmdArgsValidation(cmd.Subcommands)
if cmd.Action == nil {
continue
}
action := cmd.Action
cmd.Action = func(c *cli.Context) error {
reqArgs, _ := parseArgs(c)
if c.NArg() < len(reqArgs) {
var help bytes.Buffer
cli.HelpPrinter(&help, cli.CommandHelpTemplate, c.Command)
return fmt.Errorf("ERROR: Missing required arguments: %s\n\n%s", strings.Join(reqArgs[c.NArg():], " "), help.String())
}
return cli.HandleAction(action, c)
}
cmds[i] = cmd
}
}
func main() { func main() {
app := newFn() app := newFn()
app.Run(os.Args) app.Run(os.Args)

View File

@@ -12,7 +12,6 @@ import (
"path" "path"
"strings" "strings"
"text/tabwriter" "text/tabwriter"
"time"
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"
@@ -26,19 +25,53 @@ type routesCmd struct {
client *fnclient.Functions client *fnclient.Functions
} }
var routeFlags = []cli.Flag{
cli.StringFlag{
Name: "image,i",
Usage: "image name",
},
cli.Int64Flag{
Name: "memory,m",
Usage: "memory in MiB",
},
cli.StringFlag{
Name: "type,t",
Usage: "route type - sync or async",
},
cli.StringSliceFlag{
Name: "config,c",
Usage: "route configuration",
},
cli.StringSliceFlag{
Name: "headers",
Usage: "route response headers",
},
cli.StringFlag{
Name: "format,f",
Usage: "hot container IO format - json or http",
},
cli.IntFlag{
Name: "max-concurrency,mc",
Usage: "maximum concurrency for hot container",
},
cli.DurationFlag{
Name: "timeout",
Usage: "route timeout (eg. 30s)",
},
}
func routes() cli.Command { func routes() cli.Command {
r := routesCmd{client: apiClient()} r := routesCmd{client: apiClient()}
return cli.Command{ return cli.Command{
Name: "routes", Name: "routes",
Usage: "manage routes", Usage: "manage routes",
ArgsUsage: "fn routes",
Subcommands: []cli.Command{ Subcommands: []cli.Command{
{ {
Name: "call", Name: "call",
Usage: "call a route", Usage: "call a route",
ArgsUsage: "`app` /path", ArgsUsage: "<app> </path> [image]",
Action: r.call, Action: r.call,
Flags: runflags(), Flags: runflags(),
}, },
@@ -46,87 +79,24 @@ func routes() cli.Command {
Name: "list", Name: "list",
Aliases: []string{"l"}, Aliases: []string{"l"},
Usage: "list routes for `app`", Usage: "list routes for `app`",
ArgsUsage: "`app`", ArgsUsage: "<app>",
Action: r.list, Action: r.list,
}, },
{ {
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]", ArgsUsage: "<app> </path>",
Action: r.create, Action: r.create,
Flags: []cli.Flag{ Flags: routeFlags,
cli.Int64Flag{
Name: "memory,m",
Usage: "memory in MiB",
Value: 128,
},
cli.StringFlag{
Name: "type,t",
Usage: "route type - sync or async",
Value: "sync",
},
cli.StringSliceFlag{
Name: "config,c",
Usage: "route configuration",
},
cli.StringFlag{
Name: "format,f",
Usage: "hot function IO format - json or http",
Value: "",
},
cli.IntFlag{
Name: "max-concurrency",
Usage: "maximum concurrency for hot function",
Value: 1,
},
cli.DurationFlag{
Name: "timeout",
Usage: "route timeout",
Value: 30 * time.Second,
},
},
}, },
{ {
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 [image]", ArgsUsage: "<app> </path>",
Action: r.update, Action: r.update,
Flags: []cli.Flag{ Flags: routeFlags,
cli.StringFlag{
Name: "image,i",
Usage: "image name",
},
cli.Int64Flag{
Name: "memory,m",
Usage: "memory in MiB",
},
cli.StringFlag{
Name: "type,t",
Usage: "route type - sync or async",
},
cli.StringSliceFlag{
Name: "config,c",
Usage: "route configuration",
},
cli.StringSliceFlag{
Name: "headers",
Usage: "route response headers",
},
cli.StringFlag{
Name: "format,f",
Usage: "hot container IO format - json or http",
},
cli.IntFlag{
Name: "max-concurrency,mc",
Usage: "maximum concurrency for hot container",
},
cli.DurationFlag{
Name: "timeout",
Usage: "route timeout (eg. 30s)",
},
},
}, },
{ {
Name: "config", Name: "config",
@@ -136,14 +106,14 @@ func routes() cli.Command {
Name: "set", Name: "set",
Aliases: []string{"s"}, Aliases: []string{"s"},
Usage: "store a configuration key for this route", Usage: "store a configuration key for this route",
ArgsUsage: "`app` /path <key> <value>", ArgsUsage: "<app> </path> <key> <value>",
Action: r.configSet, Action: r.configSet,
}, },
{ {
Name: "unset", Name: "unset",
Aliases: []string{"u"}, Aliases: []string{"u"},
Usage: "remove a configuration key for this route", Usage: "remove a configuration key for this route",
ArgsUsage: "`app` /path <key>", ArgsUsage: "<app> </path> <key>",
Action: r.configUnset, Action: r.configUnset,
}, },
}, },
@@ -152,14 +122,14 @@ func routes() cli.Command {
Name: "delete", Name: "delete",
Aliases: []string{"d"}, Aliases: []string{"d"},
Usage: "delete a route from `app`", Usage: "delete a route from `app`",
ArgsUsage: "`app` /path", ArgsUsage: "<app> </path>",
Action: r.delete, Action: r.delete,
}, },
{ {
Name: "inspect", Name: "inspect",
Aliases: []string{"i"}, Aliases: []string{"i"},
Usage: "retrieve one or all routes properties", Usage: "retrieve one or all routes properties",
ArgsUsage: "`app` /path [property.[key]]", ArgsUsage: "<app> </path> [property.[key]]",
Action: r.inspect, Action: r.inspect,
}, },
}, },
@@ -172,7 +142,7 @@ func call() cli.Command {
return cli.Command{ return cli.Command{
Name: "call", Name: "call",
Usage: "call a remote function", Usage: "call a remote function",
ArgsUsage: "`app` /path", ArgsUsage: "<app> </path>",
Flags: runflags(), Flags: runflags(),
Action: r.call, Action: r.call,
} }
@@ -187,10 +157,6 @@ func cleanRoutePath(p string) string {
} }
func (a *routesCmd) list(c *cli.Context) error { func (a *routesCmd) list(c *cli.Context) error {
if len(c.Args()) < 1 {
return errors.New("error: routes listing takes one argument: an app name")
}
appName := c.Args().Get(0) appName := c.Args().Get(0)
resp, err := a.client.Routes.GetAppsAppRoutes(&apiroutes.GetAppsAppRoutesParams{ resp, err := a.client.Routes.GetAppsAppRoutes(&apiroutes.GetAppsAppRoutesParams{
@@ -201,11 +167,11 @@ func (a *routesCmd) list(c *cli.Context) error {
if err != nil { if err != nil {
switch err.(type) { switch err.(type) {
case *apiroutes.GetAppsAppRoutesNotFound: case *apiroutes.GetAppsAppRoutesNotFound:
return fmt.Errorf("error: %v", err.(*apiroutes.GetAppsAppRoutesNotFound).Payload.Error.Message) return fmt.Errorf("error: %s", err.(*apiroutes.GetAppsAppRoutesNotFound).Payload.Error.Message)
case *apiroutes.GetAppsAppRoutesDefault: case *apiroutes.GetAppsAppRoutesDefault:
return fmt.Errorf("unexpected error: %v", err.(*apiroutes.GetAppsAppRoutesDefault).Payload.Error.Message) return fmt.Errorf("unexpected error: %s", err.(*apiroutes.GetAppsAppRoutesDefault).Payload.Error.Message)
} }
return fmt.Errorf("unexpected error: %v", err) return fmt.Errorf("unexpected error: %s", err)
} }
w := tabwriter.NewWriter(os.Stdout, 0, 8, 0, '\t', 0) w := tabwriter.NewWriter(os.Stdout, 0, 8, 0, '\t', 0)
@@ -214,7 +180,7 @@ func (a *routesCmd) list(c *cli.Context) error {
u, err := url.Parse("../") u, err := url.Parse("../")
u.Path = path.Join(u.Path, "r", appName, route.Path) u.Path = path.Join(u.Path, "r", appName, route.Path)
if err != nil { if err != nil {
return fmt.Errorf("error parsing functions route path: %v", err) return fmt.Errorf("error parsing functions route path: %s", err)
} }
fmt.Fprint(w, route.Path, "\t", route.Image, "\n") fmt.Fprint(w, route.Path, "\t", route.Image, "\n")
@@ -225,10 +191,6 @@ 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 len(c.Args()) < 2 {
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)
route := cleanRoutePath(c.Args().Get(1)) route := cleanRoutePath(c.Args().Get(1))
@@ -253,7 +215,7 @@ func callfn(u string, content io.Reader, output io.Writer, method string, env []
req, err := http.NewRequest(method, u, content) req, err := http.NewRequest(method, u, content)
if err != nil { if err != nil {
return fmt.Errorf("error running route: %v", err) return fmt.Errorf("error running route: %s", err)
} }
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
@@ -264,7 +226,7 @@ func callfn(u string, content io.Reader, output io.Writer, method string, env []
resp, err := http.DefaultClient.Do(req) resp, err := http.DefaultClient.Do(req)
if err != nil { if err != nil {
return fmt.Errorf("error running route: %v", err) return fmt.Errorf("error running route: %s", err)
} }
io.Copy(output, resp.Body) io.Copy(output, resp.Body)
@@ -328,7 +290,7 @@ func routeWithFlags(c *cli.Context, rt *models.Route) {
func routeWithFuncFile(c *cli.Context, rt *models.Route) { func routeWithFuncFile(c *cli.Context, rt *models.Route) {
ff, err := loadFuncfile() ff, err := loadFuncfile()
if err == nil { if err == nil {
if rt.Image != "" { // flags take precedence if ff.FullName() != "" { // args take precedence
rt.Image = ff.FullName() rt.Image = ff.FullName()
} }
if ff.Format != nil { if ff.Format != nil {
@@ -348,18 +310,12 @@ func routeWithFuncFile(c *cli.Context, rt *models.Route) {
} }
func (a *routesCmd) create(c *cli.Context) error { func (a *routesCmd) create(c *cli.Context) error {
// 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) appName := c.Args().Get(0)
route := cleanRoutePath(c.Args().Get(1)) route := cleanRoutePath(c.Args().Get(1))
image := c.Args().Get(2)
rt := &models.Route{} rt := &models.Route{}
rt.Path = route rt.Path = route
rt.Image = image rt.Image = c.Args().Get(2)
routeWithFuncFile(c, rt) routeWithFuncFile(c, rt)
routeWithFlags(c, rt) routeWithFlags(c, rt)
@@ -368,7 +324,8 @@ func (a *routesCmd) create(c *cli.Context) error {
return errors.New("error: route path is missing") return errors.New("error: route path is missing")
} }
if rt.Image == "" { if rt.Image == "" {
return errors.New("error: function image name is missing") fmt.Println("No image specified, using `iron/hello`")
rt.Image = "iron/hello"
} }
body := &models.RouteWrapper{ body := &models.RouteWrapper{
@@ -384,13 +341,13 @@ func (a *routesCmd) create(c *cli.Context) error {
if err != nil { if err != nil {
switch err.(type) { switch err.(type) {
case *apiroutes.PostAppsAppRoutesBadRequest: case *apiroutes.PostAppsAppRoutesBadRequest:
return fmt.Errorf("error: %v", err.(*apiroutes.PostAppsAppRoutesBadRequest).Payload.Error.Message) return fmt.Errorf("error: %s", err.(*apiroutes.PostAppsAppRoutesBadRequest).Payload.Error.Message)
case *apiroutes.PostAppsAppRoutesConflict: case *apiroutes.PostAppsAppRoutesConflict:
return fmt.Errorf("error: %v", err.(*apiroutes.PostAppsAppRoutesConflict).Payload.Error.Message) return fmt.Errorf("error: %s", err.(*apiroutes.PostAppsAppRoutesConflict).Payload.Error.Message)
case *apiroutes.PostAppsAppRoutesDefault: case *apiroutes.PostAppsAppRoutesDefault:
return fmt.Errorf("unexpected error: %v", err.(*apiroutes.PostAppsAppRoutesDefault).Payload.Error.Message) return fmt.Errorf("unexpected error: %s", err.(*apiroutes.PostAppsAppRoutesDefault).Payload.Error.Message)
} }
return fmt.Errorf("unexpected error: %v", err) return fmt.Errorf("unexpected error: %s", err)
} }
fmt.Println(resp.Payload.Route.Path, "created with", resp.Payload.Route.Image) fmt.Println(resp.Payload.Route.Path, "created with", resp.Payload.Route.Image)
@@ -407,11 +364,11 @@ func (a *routesCmd) patchRoute(appName, routePath string, r *fnmodels.Route) err
if err != nil { if err != nil {
switch err.(type) { switch err.(type) {
case *apiroutes.GetAppsAppRoutesRouteNotFound: case *apiroutes.GetAppsAppRoutesRouteNotFound:
return fmt.Errorf("error: %v", err.(*apiroutes.GetAppsAppRoutesRouteNotFound).Payload.Error.Message) return fmt.Errorf("error: %s", err.(*apiroutes.GetAppsAppRoutesRouteNotFound).Payload.Error.Message)
case *apiroutes.GetAppsAppRoutesDefault: case *apiroutes.GetAppsAppRoutesDefault:
return fmt.Errorf("unexpected error: %v", err.(*apiroutes.GetAppsAppRoutesDefault).Payload.Error.Message) return fmt.Errorf("unexpected error: %s", err.(*apiroutes.GetAppsAppRoutesDefault).Payload.Error.Message)
} }
return fmt.Errorf("unexpected error: %v", err) return fmt.Errorf("unexpected error: %s", err)
} }
if resp.Payload.Route.Config == nil { if resp.Payload.Route.Config == nil {
@@ -472,23 +429,19 @@ func (a *routesCmd) patchRoute(appName, routePath string, r *fnmodels.Route) err
if err != nil { if err != nil {
switch err.(type) { switch err.(type) {
case *apiroutes.PatchAppsAppRoutesRouteBadRequest: case *apiroutes.PatchAppsAppRoutesRouteBadRequest:
return fmt.Errorf("error: %v", err.(*apiroutes.PatchAppsAppRoutesRouteBadRequest).Payload.Error.Message) return fmt.Errorf("error: %s", err.(*apiroutes.PatchAppsAppRoutesRouteBadRequest).Payload.Error.Message)
case *apiroutes.PatchAppsAppRoutesRouteNotFound: case *apiroutes.PatchAppsAppRoutesRouteNotFound:
return fmt.Errorf("error: %v", err.(*apiroutes.PatchAppsAppRoutesRouteNotFound).Payload.Error.Message) return fmt.Errorf("error: %s", err.(*apiroutes.PatchAppsAppRoutesRouteNotFound).Payload.Error.Message)
case *apiroutes.PatchAppsAppRoutesRouteDefault: case *apiroutes.PatchAppsAppRoutesRouteDefault:
return fmt.Errorf("unexpected error: %v", err.(*apiroutes.PatchAppsAppRoutesRouteDefault).Payload.Error.Message) return fmt.Errorf("unexpected error: %s", err.(*apiroutes.PatchAppsAppRoutesRouteDefault).Payload.Error.Message)
} }
return fmt.Errorf("unexpected error: %v", err) return fmt.Errorf("unexpected error: %s", err)
} }
return nil return nil
} }
func (a *routesCmd) update(c *cli.Context) error { func (a *routesCmd) update(c *cli.Context) error {
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) appName := c.Args().Get(0)
route := cleanRoutePath(c.Args().Get(1)) route := cleanRoutePath(c.Args().Get(1))
@@ -506,10 +459,6 @@ 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 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) appName := c.Args().Get(0)
route := cleanRoutePath(c.Args().Get(1)) route := cleanRoutePath(c.Args().Get(1))
key := c.Args().Get(2) key := c.Args().Get(2)
@@ -531,10 +480,6 @@ 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 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) appName := c.Args().Get(0)
route := cleanRoutePath(c.Args().Get(1)) route := cleanRoutePath(c.Args().Get(1))
key := c.Args().Get(2) key := c.Args().Get(2)
@@ -555,10 +500,6 @@ 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 len(c.Args()) < 2 {
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)
route := cleanRoutePath(c.Args().Get(1)) route := cleanRoutePath(c.Args().Get(1))
prop := c.Args().Get(2) prop := c.Args().Get(2)
@@ -572,11 +513,11 @@ func (a *routesCmd) inspect(c *cli.Context) error {
if err != nil { if err != nil {
switch err.(type) { switch err.(type) {
case *apiroutes.GetAppsAppRoutesRouteNotFound: case *apiroutes.GetAppsAppRoutesRouteNotFound:
return fmt.Errorf("error: %v", err.(*apiroutes.GetAppsAppRoutesRouteNotFound).Payload.Error.Message) return fmt.Errorf("error: %s", err.(*apiroutes.GetAppsAppRoutesRouteNotFound).Payload.Error.Message)
case *apiroutes.GetAppsAppRoutesRouteDefault: case *apiroutes.GetAppsAppRoutesRouteDefault:
return fmt.Errorf("unexpected error: %v", err.(*apiroutes.GetAppsAppRoutesRouteDefault).Payload.Error.Message) return fmt.Errorf("unexpected error: %s", err.(*apiroutes.GetAppsAppRoutesRouteDefault).Payload.Error.Message)
} }
return fmt.Errorf("unexpected error: %v", err) return fmt.Errorf("unexpected error: %s", err)
} }
enc := json.NewEncoder(os.Stdout) enc := json.NewEncoder(os.Stdout)
@@ -589,12 +530,12 @@ func (a *routesCmd) inspect(c *cli.Context) error {
data, err := json.Marshal(resp.Payload.Route) data, err := json.Marshal(resp.Payload.Route)
if err != nil { if err != nil {
return fmt.Errorf("failed to inspect route: %v", err) return fmt.Errorf("failed to inspect route: %s", err)
} }
var inspect map[string]interface{} var inspect map[string]interface{}
err = json.Unmarshal(data, &inspect) err = json.Unmarshal(data, &inspect)
if err != nil { if err != nil {
return fmt.Errorf("failed to inspect route: %v", err) return fmt.Errorf("failed to inspect route: %s", err)
} }
jq := jsonq.NewQuery(inspect) jq := jsonq.NewQuery(inspect)
@@ -608,10 +549,6 @@ 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 len(c.Args()) < 2 {
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)
route := cleanRoutePath(c.Args().Get(1)) route := cleanRoutePath(c.Args().Get(1))
@@ -623,11 +560,11 @@ func (a *routesCmd) delete(c *cli.Context) error {
if err != nil { if err != nil {
switch err.(type) { switch err.(type) {
case *apiroutes.DeleteAppsAppRoutesRouteNotFound: case *apiroutes.DeleteAppsAppRoutesRouteNotFound:
return fmt.Errorf("error: %v", err.(*apiroutes.DeleteAppsAppRoutesRouteNotFound).Payload.Error.Message) return fmt.Errorf("error: %s", err.(*apiroutes.DeleteAppsAppRoutesRouteNotFound).Payload.Error.Message)
case *apiroutes.DeleteAppsAppRoutesRouteDefault: case *apiroutes.DeleteAppsAppRoutesRouteDefault:
return fmt.Errorf("unexpected error: %v", err.(*apiroutes.DeleteAppsAppRoutesRouteDefault).Payload.Error.Message) return fmt.Errorf("unexpected error: %s", err.(*apiroutes.DeleteAppsAppRoutesRouteDefault).Payload.Error.Message)
} }
return fmt.Errorf("unexpected error: %v", err) return fmt.Errorf("unexpected error: %s", err)
} }
fmt.Println(appName, route, "deleted") fmt.Println(appName, route, "deleted")

View File

@@ -17,7 +17,7 @@ func run() cli.Command {
return cli.Command{ return cli.Command{
Name: "run", Name: "run",
Usage: "run a function locally", Usage: "run a function locally",
ArgsUsage: "USERNAME/image:tag", ArgsUsage: "[username/image:tag]",
Flags: append(runflags(), []cli.Flag{}...), Flags: append(runflags(), []cli.Flag{}...),
Action: r.run, Action: r.run,
} }
@@ -36,7 +36,7 @@ func runflags() []cli.Flag {
Usage: "select container links for the function", Usage: "select container links for the function",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "method", Name: "method",
Usage: "http method for function", Usage: "http method for function",
}, },
} }