Merge branch 'master' into slack

This commit is contained in:
Travis Reeder
2017-08-23 12:14:38 -07:00
committed by GitHub
19 changed files with 269 additions and 246 deletions

View File

@@ -49,17 +49,19 @@ configuration options [here](docs/operating/options.md). If you are on Windows,
Functions are small but powerful blocks of code that generally do one simple thing. Forget about monoliths when using functions, just focus on the task that you want the function to perform. Functions are small but powerful blocks of code that generally do one simple thing. Forget about monoliths when using functions, just focus on the task that you want the function to perform.
The following is a simple Go program that outputs a string to STDOUT. Copy and paste the code below into a file called `func.go`. Currently the function must be named func.your_language_extention (ie func.go, func.js, etc.) First, create an empty directory called `hello` and cd into it.
The following is a simple Go program that outputs a string to STDOUT. Copy and paste the code below into a file called `func.go`.
```go ```go
package main package main
import ( import (
"fmt" "fmt"
) )
func main() { func main() {
fmt.Println("Hello from Fn!") fmt.Println("Hello from Fn!")
} }
``` ```
@@ -68,12 +70,15 @@ Now run the following CLI commands:
```sh ```sh
# Initialize your function # Initialize your function
# This detects your runtime from the code above and creates a func.yaml # This detects your runtime from the code above and creates a func.yaml
fn init <DOCKERHUB_USERNAME>/hello fn init
# Test your function # Test your function
# This will run inside a container exactly how it will on the server # This will run inside a container exactly how it will on the server
fn run fn run
# Set your Docker Hub username
export FN_REGISTRY=<DOCKERHUB_USERNAME>
# Deploy your functions to the Fn server (default localhost:8080) # Deploy your functions to the Fn server (default localhost:8080)
# This will create a route to your function as well # This will create a route to your function as well
fn deploy myapp fn deploy myapp
@@ -83,19 +88,21 @@ Now you can call your function:
```sh ```sh
curl http://localhost:8080/r/myapp/hello curl http://localhost:8080/r/myapp/hello
# or:
fn call myapp /hello
``` ```
Or in a browser: [http://localhost:8080/r/myapp/hello](http://localhost:8080/r/myapp/hello) Or in a browser: [http://localhost:8080/r/myapp/hello](http://localhost:8080/r/myapp/hello)
That's it! You just deployed your first function and called it. Now to update your function That's it! You just deployed your first function and called it. To update your function
you can update your code and run `fn deploy myapp` again. you can update your code and run `fn deploy myapp` again.
## To Learn More ## To Learn More
- Visit our Functions [Tutorial Series](examples/tutorial/) * Visit our Functions [Tutorial Series](examples/tutorial/)
- See our [full documentation](docs/README.md) * See our [full documentation](docs/README.md)
- View all of our [examples](/examples) * View all of our [examples](/examples)
- You can also write your functions in AWS [Lambda format](docs/lambda/README.md) * You can also write your functions in AWS [Lambda format](docs/lambda/README.md)
## Get Involved ## Get Involved
@@ -103,7 +110,6 @@ you can update your code and run `fn deploy myapp` again.
- Learn how to [contribute](CONTRIBUTING.md) - Learn how to [contribute](CONTRIBUTING.md)
- See [milestones](https://github.com/fnproject/fn/milestones) for detailed issues - See [milestones](https://github.com/fnproject/fn/milestones) for detailed issues
## User Interface ## User Interface
This is the graphical user interface for Fn. It is currently not buildable. This is the graphical user interface for Fn. It is currently not buildable.
@@ -114,9 +120,8 @@ docker run --rm -it --link functions:api -p 4000:4000 -e "API_URL=http://api:808
For more information, see: [https://github.com/treeder/functions-ui](https://github.com/treeder/functions-ui) For more information, see: [https://github.com/treeder/functions-ui](https://github.com/treeder/functions-ui)
## Next up
# Next up ### Check out the [Tutorial Series](examples/tutorial/)
### Check out the [Tutorial Series](examples/tutorial/).
It will demonstrate some of Fn capabilities through a series of exmaples. We'll try to show examples in most major languages. This is a great place to start! It will demonstrate some of Fn capabilities through a series of exmaples. We'll try to show examples in most major languages. This is a great place to start!

View File

@@ -4,6 +4,9 @@ all: vendor build
build: build:
go build -o fn go build -o fn
install:
go build -o ${GOPATH}/bin/fn
docker: vendor docker: vendor
GOOS=linux go build -o fn GOOS=linux go build -o fn
docker build -t treeder/fn . docker build -t treeder/fn .
@@ -23,3 +26,5 @@ release:
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
docker run --rm -v ${PWD}:/go/src/github.com/fnproject/fn/cli -w /go/src/github.com/fnproject/fn/cli funcy/go:dev go build -o fn_alpine docker run --rm -v ${PWD}:/go/src/github.com/fnproject/fn/cli -w /go/src/github.com/fnproject/fn/cli funcy/go:dev go build -o fn_alpine
.PHONY: install

View File

@@ -12,13 +12,13 @@ if you are using Node, put the code that you want to execute in the file `func.j
Run: Run:
```sh ```sh
fn init <DOCKER_HUB_USERNAME>/<FUNCTION_NAME> fn init [<FUNCTION_NAME>]
``` ```
If you want to override the convention with configuration, you can do that as well using: If you want to override the convention with configuration, you can do that as well using:
```sh ```sh
fn init [--runtime node] [--entrypoint "node hello.js"] <DOCKER_HUB_USERNAME>/<FUNCTION_NAME> fn init [--runtime node] [--entrypoint "node hello.js"] [<FUNCTION_NAME>]
``` ```
Or, if you want full control, just make a Dockerfile. If `init` finds a Dockerfile, it will use that instead of runtime and entrypoint. Or, if you want full control, just make a Dockerfile. If `init` finds a Dockerfile, it will use that instead of runtime and entrypoint.

View File

@@ -102,17 +102,17 @@ func (a *appsCmd) list(c *cli.Context) error {
}) })
if err != nil { if err != nil {
// fmt.Println("err type:", reflect.TypeOf(err)) switch e := err.(type) {
switch err.(type) {
case *apiapps.GetAppsAppNotFound: case *apiapps.GetAppsAppNotFound:
return fmt.Errorf("error: %v", err.(*apiapps.GetAppsAppNotFound).Payload.Error.Message) return fmt.Errorf("error: %v", e.Payload.Error.Message)
case *apiapps.GetAppsAppDefault: case *apiapps.GetAppsAppDefault:
return fmt.Errorf("unexpected error: %v", err.(*apiapps.GetAppsAppDefault).Payload.Error.Message) return fmt.Errorf("unexpected error: %v", e.Payload.Error.Message)
case *apiapps.GetAppsDefault: case *apiapps.GetAppsDefault:
// this is the one getting called, not sure what the one above is? // this is the one getting called, not sure what the one above is?
return fmt.Errorf("unexpected error: %v", err.(*apiapps.GetAppsDefault).Payload.Error.Message) return fmt.Errorf("unexpected error: %v", e.Payload.Error.Message)
default:
return fmt.Errorf("unexpected error: %v", err)
} }
return fmt.Errorf("unexpected error: %v", err)
} }
if len(resp.Payload.Apps) == 0 { if len(resp.Payload.Apps) == 0 {
@@ -139,15 +139,16 @@ func (a *appsCmd) create(c *cli.Context) error {
}) })
if err != nil { if err != nil {
switch err.(type) { switch e := err.(type) {
case *apiapps.PostAppsBadRequest: case *apiapps.PostAppsBadRequest:
return fmt.Errorf("error: %v", err.(*apiapps.PostAppsBadRequest).Payload.Error.Message) return fmt.Errorf("error: %v", e.Payload.Error.Message)
case *apiapps.PostAppsConflict: case *apiapps.PostAppsConflict:
return fmt.Errorf("error: %v", err.(*apiapps.PostAppsConflict).Payload.Error.Message) return fmt.Errorf("error: %v", e.Payload.Error.Message)
case *apiapps.PostAppsDefault: case *apiapps.PostAppsDefault:
return fmt.Errorf("unexpected error: %v", err.(*apiapps.PostAppsDefault).Payload.Error.Message) return fmt.Errorf("unexpected error: %v", e.Payload.Error.Message)
default:
return fmt.Errorf("unexpected error: %v", err)
} }
return fmt.Errorf("unexpected error: %v", err)
} }
fmt.Println("Successfully created app: ", resp.Payload.App.Name) fmt.Println("Successfully created app: ", resp.Payload.App.Name)
@@ -215,15 +216,16 @@ func (a *appsCmd) patchApp(appName string, app *models.App) error {
}) })
if err != nil { if err != nil {
switch err.(type) { switch e := err.(type) {
case *apiapps.PatchAppsAppBadRequest: case *apiapps.PatchAppsAppBadRequest:
return errors.New(err.(*apiapps.PatchAppsAppBadRequest).Payload.Error.Message) return errors.New(e.Payload.Error.Message)
case *apiapps.PatchAppsAppNotFound: case *apiapps.PatchAppsAppNotFound:
return errors.New(err.(*apiapps.PatchAppsAppNotFound).Payload.Error.Message) return errors.New(e.Payload.Error.Message)
case *apiapps.PatchAppsAppDefault: case *apiapps.PatchAppsAppDefault:
return errors.New(err.(*apiapps.PatchAppsAppDefault).Payload.Error.Message) return errors.New(e.Payload.Error.Message)
default:
return fmt.Errorf("unexpected error: %v", err)
} }
return fmt.Errorf("unexpected error: %v", err)
} }
return nil return nil
@@ -243,13 +245,14 @@ func (a *appsCmd) inspect(c *cli.Context) error {
}) })
if err != nil { if err != nil {
switch err.(type) { switch e := err.(type) {
case *apiapps.GetAppsAppNotFound: case *apiapps.GetAppsAppNotFound:
return fmt.Errorf("error: %v", err.(*apiapps.GetAppsAppNotFound).Payload.Error.Message) return fmt.Errorf("error: %v", e.Payload.Error.Message)
case *apiapps.GetAppsAppDefault: case *apiapps.GetAppsAppDefault:
return fmt.Errorf("unexpected error: %v", err.(*apiapps.GetAppsAppDefault).Payload.Error.Message) return fmt.Errorf("unexpected error: %v", e.Payload.Error.Message)
default:
return fmt.Errorf("unexpected error: %v", err)
} }
return fmt.Errorf("unexpected error: %v", err)
} }
enc := json.NewEncoder(os.Stdout) enc := json.NewEncoder(os.Stdout)
@@ -294,11 +297,11 @@ func (a *appsCmd) delete(c *cli.Context) error {
}) })
if err != nil { if err != nil {
switch err.(type) { switch e := err.(type) {
case *apiapps.DeleteAppsAppNotFound: case *apiapps.DeleteAppsAppNotFound:
return errors.New(err.(*apiapps.DeleteAppsAppNotFound).Payload.Error.Message) return errors.New(e.Payload.Error.Message)
case *apiapps.DeleteAppsAppDefault: case *apiapps.DeleteAppsAppDefault:
return errors.New(err.(*apiapps.DeleteAppsAppDefault).Payload.Error.Message) return errors.New(e.Payload.Error.Message)
} }
return fmt.Errorf("unexpected error: %v", err) return fmt.Errorf("unexpected error: %v", err)
} }

View File

@@ -40,8 +40,6 @@ func (b *buildcmd) flags() []cli.Flag {
// build will take the found valid function and build it // build will take the found valid function and build it
func (b *buildcmd) build(c *cli.Context) error { func (b *buildcmd) build(c *cli.Context) error {
verbwriter := verbwriter(b.verbose)
path, err := os.Getwd() path, err := os.Getwd()
if err != nil { if err != nil {
return err return err
@@ -51,11 +49,11 @@ func (b *buildcmd) build(c *cli.Context) error {
return err return err
} }
ff, err := buildfunc(verbwriter, fn, b.noCache) ff, err := buildfunc(fn, b.noCache)
if err != nil { if err != nil {
return err return err
} }
fmt.Printf("Function %v built successfully.\n", ff.FullName()) fmt.Printf("Function %v built successfully.\n", ff.ImageName())
return nil return nil
} }

View File

@@ -41,7 +41,6 @@ func (b *bumpcmd) flags() []cli.Flag {
// bump will take the found valid function and bump its version // bump will take the found valid function and bump its version
func (b *bumpcmd) bump(c *cli.Context) error { func (b *bumpcmd) bump(c *cli.Context) error {
verbwriter := verbwriter(b.verbose)
path, err := os.Getwd() path, err := os.Getwd()
if err != nil { if err != nil {
@@ -52,7 +51,7 @@ func (b *bumpcmd) bump(c *cli.Context) error {
return err return err
} }
fmt.Fprintln(verbwriter, "bumping version for", fn) fmt.Println("bumping version for", fn)
funcfile, err := parsefuncfile(fn) funcfile, err := parsefuncfile(fn)
if err != nil { if err != nil {

View File

@@ -64,12 +64,12 @@ func (call *callsCmd) get(ctx *cli.Context) error {
} }
resp, err := call.client.Call.GetAppsAppCallsCall(&params) resp, err := call.client.Call.GetAppsAppCallsCall(&params)
if err != nil { if err != nil {
switch err.(type) { switch e := err.(type) {
case *apicall.GetAppsAppCallsCallNotFound: case *apicall.GetAppsAppCallsCallNotFound:
return fmt.Errorf("error: %v", err.(*apicall.GetAppsAppCallsCallNotFound).Payload.Error.Message) return fmt.Errorf("error: %v", e.Payload.Error.Message)
default:
return fmt.Errorf("unexpected error: %v", err)
} }
return fmt.Errorf("unexpected error: %v", err)
} }
printCalls([]*models.Call{resp.Payload.Call}) printCalls([]*models.Call{resp.Payload.Call})
return nil return nil
@@ -87,12 +87,12 @@ func (call *callsCmd) list(ctx *cli.Context) error {
} }
resp, err := call.client.Call.GetAppsAppCalls(&params) resp, err := call.client.Call.GetAppsAppCalls(&params)
if err != nil { if err != nil {
switch err.(type) { switch e := err.(type) {
case *apicall.GetCallsCallNotFound: case *apicall.GetCallsCallNotFound:
return fmt.Errorf("error: %v", err.(*apicall.GetCallsCallNotFound).Payload.Error.Message) return fmt.Errorf("error: %v", e.Payload.Error.Message)
default:
return fmt.Errorf("unexpected error: %v", err)
} }
return fmt.Errorf("unexpected error: %v", err)
} }
printCalls(resp.Payload.Calls) printCalls(resp.Payload.Calls)
return nil return nil

View File

@@ -11,6 +11,10 @@ import (
"github.com/go-openapi/strfmt" "github.com/go-openapi/strfmt"
) )
const (
envFnToken = "FN_TOKEN"
)
func Host() string { func Host() string {
apiURL := os.Getenv("API_URL") apiURL := os.Getenv("API_URL")
if apiURL == "" { if apiURL == "" {
@@ -26,8 +30,8 @@ func Host() string {
func APIClient() *fnclient.Functions { func APIClient() *fnclient.Functions {
transport := httptransport.New(Host(), "/v1", []string{"http"}) transport := httptransport.New(Host(), "/v1", []string{"http"})
if os.Getenv("FN_TOKEN") != "" { if os.Getenv(envFnToken) != "" {
transport.DefaultAuthentication = httptransport.BearerToken(os.Getenv("FN_TOKEN")) transport.DefaultAuthentication = httptransport.BearerToken(os.Getenv(envFnToken))
} }
// create the API client, with the transport // create the API client, with the transport

View File

@@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"log"
"os" "os"
"os/exec" "os/exec"
"os/signal" "os/signal"
@@ -22,18 +23,23 @@ import (
const ( const (
functionsDockerImage = "funcy/functions" functionsDockerImage = "funcy/functions"
minRequiredDockerVersion = "17.5.0" minRequiredDockerVersion = "17.5.0"
envFnRegistry = "FN_REGISTRY"
) )
func verbwriter(verbose bool) io.Writer { type HasRegistry interface {
// this is too limiting, removes all logs which isn't what we want Registry() string
// verbwriter := ioutil.Discard
// if verbose {
verbwriter := os.Stderr
// }
return verbwriter
} }
func buildfunc(verbwriter io.Writer, fn string, noCache bool) (*funcfile, error) { func setRegistryEnv(hr HasRegistry) {
if hr.Registry() != "" {
err := os.Setenv(envFnRegistry, hr.Registry())
if err != nil {
log.Fatalf("Couldn't set %s env var: %v\n", envFnRegistry, err)
}
}
}
func buildfunc(fn string, noCache bool) (*funcfile, error) {
funcfile, err := parsefuncfile(fn) funcfile, err := parsefuncfile(fn)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -53,23 +59,21 @@ func buildfunc(verbwriter io.Writer, fn string, noCache bool) (*funcfile, error)
} }
} }
if err := localbuild(verbwriter, fn, funcfile.Build); err != nil { if err := localbuild(fn, funcfile.Build); err != nil {
return nil, err return nil, err
} }
if err := dockerbuild(verbwriter, fn, funcfile, noCache); err != nil { if err := dockerbuild(fn, funcfile, noCache); err != nil {
return nil, err return nil, err
} }
return funcfile, nil return funcfile, nil
} }
func localbuild(verbwriter io.Writer, path string, steps []string) error { func localbuild(path string, steps []string) error {
for _, cmd := range steps { for _, cmd := range steps {
exe := exec.Command("/bin/sh", "-c", cmd) exe := exec.Command("/bin/sh", "-c", cmd)
exe.Dir = filepath.Dir(path) exe.Dir = filepath.Dir(path)
exe.Stderr = verbwriter
exe.Stdout = verbwriter
if err := exe.Run(); err != nil { if err := exe.Run(); err != nil {
return fmt.Errorf("error running command %v (%v)", cmd, err) return fmt.Errorf("error running command %v (%v)", cmd, err)
} }
@@ -78,7 +82,7 @@ func localbuild(verbwriter io.Writer, path string, steps []string) error {
return nil return nil
} }
func dockerbuild(verbwriter io.Writer, path string, ff *funcfile, noCache bool) error { func dockerbuild(path string, ff *funcfile, noCache bool) error {
err := dockerVersionCheck() err := dockerVersionCheck()
if err != nil { if err != nil {
return err return err
@@ -89,9 +93,9 @@ func dockerbuild(verbwriter io.Writer, path string, ff *funcfile, noCache bool)
var helper langs.LangHelper var helper langs.LangHelper
dockerfile := filepath.Join(dir, "Dockerfile") dockerfile := filepath.Join(dir, "Dockerfile")
if !exists(dockerfile) { if !exists(dockerfile) {
helper = langs.GetLangHelper(*ff.Runtime) helper = langs.GetLangHelper(ff.Runtime)
if helper == nil { if helper == nil {
return fmt.Errorf("Cannot build, no language helper found for %v", *ff.Runtime) return fmt.Errorf("Cannot build, no language helper found for %v", ff.Runtime)
} }
dockerfile, err = writeTmpDockerfile(helper, dir, ff) dockerfile, err = writeTmpDockerfile(helper, dir, ff)
if err != nil { if err != nil {
@@ -106,7 +110,7 @@ func dockerbuild(verbwriter io.Writer, path string, ff *funcfile, noCache bool)
} }
} }
fmt.Printf("Building image %v\n", ff.FullName()) fmt.Printf("Building image %v\n", ff.ImageName())
cancel := make(chan os.Signal, 3) cancel := make(chan os.Signal, 3)
signal.Notify(cancel, os.Interrupt) // and others perhaps signal.Notify(cancel, os.Interrupt) // and others perhaps
@@ -117,7 +121,7 @@ func dockerbuild(verbwriter io.Writer, path string, ff *funcfile, noCache bool)
go func(done chan<- error) { go func(done chan<- error) {
args := []string{ args := []string{
"build", "build",
"-t", ff.FullName(), "-t", ff.ImageName(),
"-f", dockerfile, "-f", dockerfile,
} }
if noCache { if noCache {
@@ -261,8 +265,12 @@ func extractEnvConfig(configs []string) map[string]string {
} }
func dockerpush(ff *funcfile) error { func dockerpush(ff *funcfile) error {
fmt.Println("Pushing to docker registry...") err := validImageName(ff.ImageName())
cmd := exec.Command("docker", "push", ff.FullName()) if err != nil {
return err
}
fmt.Printf("Pushing %v to docker registry...", ff.ImageName())
cmd := exec.Command("docker", "push", ff.ImageName())
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
@@ -271,6 +279,19 @@ func dockerpush(ff *funcfile) error {
return nil return nil
} }
func validImageName(n string) error {
// must have at least owner name and a tag
split := strings.Split(n, ":")
if len(split) < 2 {
return errors.New("image name must have a tag")
}
split2 := strings.Split(split[0], "/")
if len(split2) < 2 {
return errors.New("image name must have an owner and name, eg: username/myfunc. Be sure to set FN_REGISTRY env var or pass in --registry.")
}
return nil
}
func appNamePath(img string) (string, string) { func appNamePath(img string) (string, string) {
sep := strings.Index(img, "/") sep := strings.Index(img, "/")
if sep < 0 { if sep < 0 {

View File

@@ -3,7 +3,6 @@ package main
import ( import (
"errors" "errors"
"fmt" "fmt"
"io"
"log" "log"
"os" "os"
"path" "path"
@@ -40,8 +39,11 @@ type deploycmd struct {
incremental bool incremental bool
skippush bool skippush bool
noCache bool noCache bool
registry string
}
verbwriter io.Writer func (cmd *deploycmd) Registry() string {
return cmd.registry
} }
func (p *deploycmd) flags() []cli.Flag { func (p *deploycmd) flags() []cli.Flag {
@@ -73,18 +75,23 @@ func (p *deploycmd) flags() []cli.Flag {
Usage: "does not push Docker built images onto Docker Hub - useful for local development.", Usage: "does not push Docker built images onto Docker Hub - useful for local development.",
Destination: &p.skippush, Destination: &p.skippush,
}, },
cli.StringFlag{
Name: "registry",
Usage: "Sets the Docker owner for images and optionally the registry. This will be prefixed to your function name for pushing to Docker registries. eg: `--registry username` will set your Docker Hub owner. `--registry registry.hub.docker.com/username` will set the registry and owner.",
Destination: &p.registry,
},
} }
} }
func (p *deploycmd) scan(c *cli.Context) error { func (p *deploycmd) scan(c *cli.Context) error {
p.appName = c.Args().First() p.appName = c.Args().First()
p.verbwriter = verbwriter(p.verbose)
var walked bool var walked bool
wd, err := os.Getwd() wd, err := os.Getwd()
if err != nil { if err != nil {
log.Fatalln("Couldn't get working directory:", err) log.Fatalln("Couldn't get working directory:", err)
} }
setRegistryEnv(p)
err = filepath.Walk(wd, func(path string, info os.FileInfo, err error) error { err = filepath.Walk(wd, func(path string, info os.FileInfo, err error) error {
if path != wd && info.IsDir() { if path != wd && info.IsDir() {
@@ -101,7 +108,7 @@ func (p *deploycmd) scan(c *cli.Context) error {
e := p.deploy(c, path) e := p.deploy(c, path)
if err != nil { if err != nil {
fmt.Fprintln(p.verbwriter, path, e) fmt.Println(path, e)
} }
now := time.Now() now := time.Now()
@@ -110,7 +117,7 @@ func (p *deploycmd) scan(c *cli.Context) error {
return e return e
}) })
if err != nil { if err != nil {
fmt.Fprintf(p.verbwriter, "error: %s\n", err) fmt.Printf("error: %s\n", err)
} }
if !walked { if !walked {
@@ -132,7 +139,7 @@ func (p *deploycmd) deploy(c *cli.Context, funcFilePath string) error {
return err return err
} }
funcfile, err := buildfunc(p.verbwriter, funcFileName, p.noCache) funcfile, err := buildfunc(funcFileName, p.noCache)
if err != nil { if err != nil {
return err return err
} }
@@ -152,14 +159,14 @@ func (p *deploycmd) deploy(c *cli.Context, funcFilePath string) error {
} }
func (p *deploycmd) route(c *cli.Context, ff *funcfile) error { func (p *deploycmd) route(c *cli.Context, ff *funcfile) error {
fmt.Printf("Updating route %s using image %s...\n", ff.Path, ff.FullName()) fmt.Printf("Updating route %s using image %s...\n", ff.Path, ff.ImageName())
if err := resetBasePath(p.Configuration); err != nil { if err := resetBasePath(p.Configuration); err != nil {
return fmt.Errorf("error setting endpoint: %v", err) return fmt.Errorf("error setting endpoint: %v", err)
} }
routesCmd := routesCmd{client: client.APIClient()} routesCmd := routesCmd{client: client.APIClient()}
rt := &models.Route{} rt := &models.Route{}
if err := routeWithFuncFile(c, ff, rt); err != nil { if err := routeWithFuncFile(ff, rt); err != nil {
return fmt.Errorf("error getting route with funcfile: %s", err) return fmt.Errorf("error getting route with funcfile: %s", err)
} }
return routesCmd.putRoute(c, p.appName, ff.Path, rt) return routesCmd.putRoute(c, p.appName, ff.Path, rt)

View File

@@ -9,7 +9,6 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
fnmodels "github.com/funcy/functions_go/models"
yaml "gopkg.in/yaml.v2" yaml "gopkg.in/yaml.v2"
) )
@@ -39,19 +38,37 @@ type fftest struct {
} }
type funcfile struct { type funcfile struct {
fnmodels.Route
Name string `yaml:"name,omitempty" json:"name,omitempty"` Name string `yaml:"name,omitempty" json:"name,omitempty"`
Version string `yaml:"version,omitempty" json:"version,omitempty"` Version string `yaml:"version,omitempty" json:"version,omitempty"`
Runtime *string `yaml:"runtime,omitempty" json:"runtime,omitempty"` Runtime string `yaml:"runtime,omitempty" json:"runtime,omitempty"`
Entrypoint string `yaml:"entrypoint,omitempty" json:"entrypoint,omitempty"` Entrypoint string `yaml:"entrypoint,omitempty" json:"entrypoint,omitempty"`
Cmd string `yaml:"cmd,omitempty" json:"cmd,omitempty"` Cmd string `yaml:"cmd,omitempty" json:"cmd,omitempty"`
Build []string `yaml:"build,omitempty" json:"build,omitempty"` Build []string `yaml:"build,omitempty" json:"build,omitempty"`
Tests []fftest `yaml:"tests,omitempty" json:"tests,omitempty"` Tests []fftest `yaml:"tests,omitempty" json:"tests,omitempty"`
// route specific
Type string `yaml:"type,omitempty" json:"type,omitempty"`
Memory uint64 `yaml:"memory,omitempty" json:"memory,omitempty"`
Format string `yaml:"format,omitempty" json:"format,omitempty"`
Timeout *int32 `yaml:"timeout,omitempty" json:"timeout,omitempty"`
Path string `yaml:"path,omitempty" json:"path,omitempty"`
Config map[string]string `yaml:"config,omitempty" json:"config,omitempty"`
Headers map[string][]string `yaml:"headers,omitempty" json:"headers,omitempty"`
IDLETimeout *int32 `yaml:"idle_timeout,omitempty" json:"idle_timeout,omitempty"`
} }
func (ff *funcfile) FullName() string { func (ff *funcfile) ImageName() string {
fname := ff.Name fname := ff.Name
if !strings.Contains(fname, "/") {
// then we'll prefix FN_REGISTRY
reg := os.Getenv(envFnRegistry)
if reg != "" {
if reg[len(reg)-1] != '/' {
reg += "/"
}
fname = fmt.Sprintf("%s%s", reg, fname)
}
}
if ff.Version != "" { if ff.Version != "" {
fname = fmt.Sprintf("%s:%s", fname, ff.Version) fname = fmt.Sprintf("%s:%s", fname, ff.Version)
} }
@@ -59,11 +76,11 @@ func (ff *funcfile) FullName() string {
} }
func (ff *funcfile) RuntimeTag() (runtime, tag string) { func (ff *funcfile) RuntimeTag() (runtime, tag string) {
if ff.Runtime == nil { if ff.Runtime == "" {
return "", "" return "", ""
} }
rt := *ff.Runtime rt := ff.Runtime
tagpos := strings.Index(rt, ":") tagpos := strings.Index(rt, ":")
if tagpos == -1 { if tagpos == -1 {
return rt, "" return rt, ""
@@ -72,65 +89,6 @@ func (ff *funcfile) RuntimeTag() (runtime, tag string) {
return rt[:tagpos], rt[tagpos+1:] return rt[:tagpos], rt[tagpos+1:]
} }
type flatfuncfile struct {
Name string `yaml:"name,omitempty" json:"name,omitempty"`
Version string `yaml:"version,omitempty" json:"version,omitempty"`
Runtime *string `yaml:"runtime,omitempty" json:"runtime,omitempty"`
Entrypoint string `yaml:"entrypoint,omitempty" json:"entrypoint,omitempty"`
Cmd string `yaml:"cmd,omitempty" json:"cmd,omitempty"`
Build []string `yaml:"build,omitempty" json:"build,omitempty"`
Tests []fftest `yaml:"tests,omitempty" json:"tests,omitempty"`
// route specific
Type string `yaml:"type,omitempty" json:"type,omitempty"`
Memory uint64 `yaml:"memory,omitempty" json:"memory,omitempty"`
Format string `yaml:"format,omitempty" json:"format,omitempty"`
Timeout *int32 `yaml:"timeout,omitempty" json:"timeout,omitempty"`
Path string `yaml:"path,omitempty" json:"path,omitempty"`
Config map[string]string `yaml:"config,omitempty" json:"config,omitempty"`
Headers map[string][]string `yaml:"headers,omitempty" json:"headers,omitempty"`
}
func (ff *funcfile) MakeFlat() flatfuncfile {
return flatfuncfile{
Name: ff.Name,
Version: ff.Version,
Runtime: ff.Runtime,
Entrypoint: ff.Entrypoint,
Cmd: ff.Cmd,
Build: ff.Build,
Tests: ff.Tests,
// route-specific
Type: ff.Type,
Memory: ff.Memory,
Format: ff.Format,
Timeout: ff.Timeout,
Path: ff.Path,
Config: ff.Config,
Headers: ff.Headers,
}
}
func (fff *flatfuncfile) MakeFuncFile() *funcfile {
ff := &funcfile{
Name: fff.Name,
Version: fff.Version,
Runtime: fff.Runtime,
Entrypoint: fff.Entrypoint,
Cmd: fff.Cmd,
Build: fff.Build,
Tests: fff.Tests,
}
ff.Type = fff.Type
ff.Memory = fff.Memory
ff.Format = fff.Format
ff.Timeout = fff.Timeout
ff.Path = fff.Path
ff.Config = fff.Config
ff.Headers = fff.Headers
return ff
}
func findFuncfile(path string) (string, error) { func findFuncfile(path string) (string, error) {
for _, fn := range validfn { for _, fn := range validfn {
fullfn := filepath.Join(path, fn) fullfn := filepath.Join(path, fn)
@@ -176,9 +134,10 @@ func decodeFuncfileJSON(path string) (*funcfile, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("could not open %s for parsing. Error: %v", path, err) return nil, fmt.Errorf("could not open %s for parsing. Error: %v", path, err)
} }
fff := new(flatfuncfile) ff := &funcfile{}
err = json.NewDecoder(f).Decode(fff) // ff.Route = &fnmodels.Route{}
ff := fff.MakeFuncFile() err = json.NewDecoder(f).Decode(ff)
// ff := fff.MakeFuncFile()
return ff, err return ff, err
} }
@@ -187,9 +146,9 @@ func decodeFuncfileYAML(path string) (*funcfile, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("could not open %s for parsing. Error: %v", path, err) return nil, fmt.Errorf("could not open %s for parsing. Error: %v", path, err)
} }
fff := new(flatfuncfile) ff := &funcfile{}
err = yaml.Unmarshal(b, fff) err = yaml.Unmarshal(b, ff)
ff := fff.MakeFuncFile() // ff := fff.MakeFuncFile()
return ff, err return ff, err
} }
@@ -198,11 +157,11 @@ func encodeFuncfileJSON(path string, ff *funcfile) error {
if err != nil { if err != nil {
return fmt.Errorf("could not open %s for encoding. Error: %v", path, err) return fmt.Errorf("could not open %s for encoding. Error: %v", path, err)
} }
return json.NewEncoder(f).Encode(ff.MakeFlat()) return json.NewEncoder(f).Encode(ff)
} }
func encodeFuncfileYAML(path string, ff *funcfile) error { func encodeFuncfileYAML(path string, ff *funcfile) error {
b, err := yaml.Marshal(ff.MakeFlat()) b, err := yaml.Marshal(ff)
if err != nil { if err != nil {
return fmt.Errorf("could not encode function file. Error: %v", err) return fmt.Errorf("could not encode function file. Error: %v", err)
} }

View File

@@ -45,12 +45,8 @@ func init() {
} }
type initFnCmd struct { type initFnCmd struct {
name string force bool
force bool funcfile
runtime string
entrypoint string
cmd string
version string
} }
func initFlags(a *initFnCmd) []cli.Flag { func initFlags(a *initFnCmd) []cli.Flag {
@@ -63,17 +59,22 @@ func initFlags(a *initFnCmd) []cli.Flag {
cli.StringFlag{ cli.StringFlag{
Name: "runtime", Name: "runtime",
Usage: "choose an existing runtime - " + strings.Join(fnInitRuntimes, ", "), Usage: "choose an existing runtime - " + strings.Join(fnInitRuntimes, ", "),
Destination: &a.runtime, Destination: &a.Runtime,
}, },
cli.StringFlag{ cli.StringFlag{
Name: "entrypoint", Name: "entrypoint",
Usage: "entrypoint is the command to run to start this function - equivalent to Dockerfile ENTRYPOINT.", Usage: "entrypoint is the command to run to start this function - equivalent to Dockerfile ENTRYPOINT.",
Destination: &a.entrypoint, Destination: &a.Entrypoint,
},
cli.StringFlag{
Name: "cmd",
Usage: "command to run to start this function - equivalent to Dockerfile CMD.",
Destination: &a.Entrypoint,
}, },
cli.StringFlag{ cli.StringFlag{
Name: "version", Name: "version",
Usage: "function version", Usage: "function version",
Destination: &a.version, Destination: &a.Version,
Value: initialVersion, Value: initialVersion,
}, },
} }
@@ -82,15 +83,16 @@ func initFlags(a *initFnCmd) []cli.Flag {
} }
func initFn() cli.Command { func initFn() cli.Command {
a := initFnCmd{} a := &initFnCmd{}
// funcfile := &funcfile{}
return cli.Command{ return cli.Command{
Name: "init", Name: "init",
Usage: "create a local func.yaml file", Usage: "create a local func.yaml file",
Description: "Creates a func.yaml file in the current directory. ", Description: "Creates a func.yaml file in the current directory.",
ArgsUsage: "<DOCKERHUB_USERNAME/FUNCTION_NAME>", ArgsUsage: "[FUNCTION_NAME]",
Action: a.init, Action: a.init,
Flags: initFlags(&a), Flags: initFlags(a),
} }
} }
@@ -109,13 +111,13 @@ func (a *initFnCmd) init(c *cli.Context) error {
} }
} }
runtimeSpecified := a.runtime != ""
err := a.buildFuncFile(c) err := a.buildFuncFile(c)
if err != nil { if err != nil {
return err return err
} }
runtimeSpecified := a.Runtime != ""
if runtimeSpecified { if runtimeSpecified {
err := a.generateBoilerplate() err := a.generateBoilerplate()
if err != nil { if err != nil {
@@ -123,21 +125,12 @@ func (a *initFnCmd) init(c *cli.Context) error {
} }
} }
ff := &funcfile{ ff := a.funcfile
*rt,
a.name,
a.version,
&a.runtime,
a.entrypoint,
a.cmd,
[]string{},
[]fftest{},
}
_, path := appNamePath(ff.FullName()) _, path := appNamePath(ff.ImageName())
ff.Path = path ff.Path = path
if err := encodeFuncfileYAML("func.yaml", ff); err != nil { if err := encodeFuncfileYAML("func.yaml", &ff); err != nil {
return err return err
} }
@@ -146,7 +139,7 @@ func (a *initFnCmd) init(c *cli.Context) error {
} }
func (a *initFnCmd) generateBoilerplate() error { func (a *initFnCmd) generateBoilerplate() error {
helper := langs.GetLangHelper(a.runtime) helper := langs.GetLangHelper(a.Runtime)
if helper != nil && helper.HasBoilerplate() { if helper != nil && helper.HasBoilerplate() {
if err := helper.GenerateBoilerplate(); err != nil { if err := helper.GenerateBoilerplate(); err != nil {
if err == langs.ErrBoilerplateExists { if err == langs.ErrBoilerplateExists {
@@ -162,47 +155,52 @@ func (a *initFnCmd) generateBoilerplate() error {
func (a *initFnCmd) buildFuncFile(c *cli.Context) error { func (a *initFnCmd) buildFuncFile(c *cli.Context) error {
pwd, err := os.Getwd() pwd, err := os.Getwd()
if err != nil { if err != nil {
return fmt.Errorf("error detecting current working directory: %s", err) return fmt.Errorf("error detecting current working directory: %v", err)
} }
a.name = c.Args().First() a.Name = c.Args().First()
if a.name == "" || strings.Contains(a.name, ":") { // if a.name == "" {
return errors.New("please specify a name for your function in the following format <DOCKERHUB_USERNAME>/<FUNCTION_NAME>.\nTry: fn init <DOCKERHUB_USERNAME>/<FUNCTION_NAME>") // // return errors.New("please specify a name for your function.\nTry: fn init <FUNCTION_NAME>")
// } else
if a.Name == "" {
// then use current directory for name
a.Name = filepath.Base(pwd)
} else if strings.Contains(a.Name, ":") {
return errors.New("function name cannot contain a colon")
} }
if exists("Dockerfile") { if exists("Dockerfile") {
fmt.Println("Dockerfile found. Let's use that to build...") fmt.Println("Dockerfile found. Let's use that to build...")
return nil return nil
} }
var rt string var rt string
if a.runtime == "" { if a.Runtime == "" {
rt, err = detectRuntime(pwd) rt, err = detectRuntime(pwd)
if err != nil { if err != nil {
return err return err
} }
a.runtime = rt a.Runtime = rt
fmt.Printf("Found %v, assuming %v runtime.\n", rt, rt) fmt.Printf("Found %v, assuming %v runtime.\n", rt, rt)
} else { } else {
fmt.Println("Runtime:", a.runtime) fmt.Println("Runtime:", a.Runtime)
} }
helper := langs.GetLangHelper(a.runtime) helper := langs.GetLangHelper(a.Runtime)
if helper == nil { if helper == nil {
fmt.Printf("init does not support the %s runtime, you'll have to create your own Dockerfile for this function", a.runtime) fmt.Printf("init does not support the %s runtime, you'll have to create your own Dockerfile for this function", a.Runtime)
} }
if a.entrypoint == "" { if a.Entrypoint == "" {
if helper != nil { if helper != nil {
a.entrypoint = helper.Entrypoint() a.Entrypoint = helper.Entrypoint()
} }
} }
if a.cmd == "" { if a.Cmd == "" {
if helper != nil { if helper != nil {
a.cmd = helper.Cmd() a.Cmd = helper.Cmd()
} }
} }
if a.entrypoint == "" && a.cmd == "" { if a.Entrypoint == "" && a.Cmd == "" {
return fmt.Errorf("could not detect entrypoint or cmd for %v, use --entrypoint and/or --cmd to set them explicitly", a.runtime) return fmt.Errorf("could not detect entrypoint or cmd for %v, use --entrypoint and/or --cmd to set them explicitly", a.Runtime)
} }
return nil return nil
@@ -221,5 +219,5 @@ func detectRuntime(path string) (runtime string, err error) {
} }
} }
} }
return "", fmt.Errorf("no supported files found to guess runtime, please set runtime explicitly with --runtime flag.") return "", fmt.Errorf("no supported files found to guess runtime, please set runtime explicitly with --runtime flag")
} }

View File

@@ -181,7 +181,7 @@ func createFunctionYaml(opts createImageOptions, functionName string) error {
funcDesc := &funcfile{ funcDesc := &funcfile{
Name: opts.Name, Name: opts.Name,
Version: "0.0.1", Version: "0.0.1",
Runtime: &opts.Base, Runtime: opts.Base,
Cmd: opts.Handler, Cmd: opts.Handler,
} }
funcDesc.Config = opts.Config funcDesc.Config = opts.Config

View File

@@ -41,12 +41,12 @@ func (log *logsCmd) get(ctx *cli.Context) error {
} }
resp, err := log.client.Operations.GetAppsAppCallsCallLog(&params) resp, err := log.client.Operations.GetAppsAppCallsCallLog(&params)
if err != nil { if err != nil {
switch err.(type) { switch e := err.(type) {
case *apicall.GetAppsAppCallsCallLogNotFound: case *apicall.GetAppsAppCallsCallLogNotFound:
return fmt.Errorf("error: %v", err.(*apicall.GetAppsAppCallsCallLogNotFound).Payload.Error.Message) return fmt.Errorf("error: %v", e.Payload.Error.Message)
default:
return fmt.Errorf("unexpected error: %v", err)
} }
return fmt.Errorf("unexpected error: %v", err)
} }
fmt.Print(resp.Payload.Log.Log) fmt.Print(resp.Payload.Log.Log)
return nil return nil

View File

@@ -132,7 +132,7 @@ func main() {
err := app.Run(os.Args) err := app.Run(os.Args)
if err != nil { if err != nil {
// TODO: this doesn't seem to get called even when an error returns from a command, but maybe urfave is doing a non zero exit anyways? nope: https://github.com/urfave/cli/issues/610 // TODO: this doesn't seem to get called even when an error returns from a command, but maybe urfave is doing a non zero exit anyways? nope: https://github.com/urfave/cli/issues/610
fmt.Printf("Error occurred: %v, exiting...\n", err) fmt.Fprintf(os.Stderr, "Error occurred: %v, exiting...\n", err)
os.Exit(1) os.Exit(1)
} }
} }

View File

@@ -20,7 +20,12 @@ func push() cli.Command {
} }
type pushcmd struct { type pushcmd struct {
verbose bool verbose bool
registry string
}
func (cmd *pushcmd) Registry() string {
return cmd.registry
} }
func (p *pushcmd) flags() []cli.Flag { func (p *pushcmd) flags() []cli.Flag {
@@ -30,6 +35,11 @@ func (p *pushcmd) flags() []cli.Flag {
Usage: "verbose mode", Usage: "verbose mode",
Destination: &p.verbose, Destination: &p.verbose,
}, },
cli.StringFlag{
Name: "registry",
Usage: "Sets the Docker owner for images and optionally the registry. This will be prefixed to your function name for pushing to Docker registries. eg: `--registry username` will set your Docker Hub owner. `--registry registry.hub.docker.com/username` will set the registry and owner.",
Destination: &p.registry,
},
} }
} }
@@ -38,7 +48,7 @@ func (p *pushcmd) flags() []cli.Flag {
// push the container, and finally it will update function's route. Optionally, // push the container, and finally it will update function's route. Optionally,
// the route can be overriden inside the functions file. // the route can be overriden inside the functions file.
func (p *pushcmd) push(c *cli.Context) error { func (p *pushcmd) push(c *cli.Context) error {
verbwriter := verbwriter(p.verbose) setRegistryEnv(p)
ff, err := loadFuncfile() ff, err := loadFuncfile()
if err != nil { if err != nil {
@@ -48,12 +58,12 @@ func (p *pushcmd) push(c *cli.Context) error {
return err return err
} }
fmt.Fprintln(verbwriter, "pushing", ff.FullName()) fmt.Println("pushing", ff.ImageName())
if err := dockerpush(ff); err != nil { if err := dockerpush(ff); err != nil {
return err return err
} }
fmt.Printf("Function %v pushed successfully to Docker Hub.\n", ff.FullName()) fmt.Printf("Function %v pushed successfully to Docker Hub.\n", ff.ImageName())
return nil return nil
} }

View File

@@ -181,13 +181,14 @@ func (a *routesCmd) list(c *cli.Context) error {
}) })
if err != nil { if err != nil {
switch err.(type) { switch e := err.(type) {
case *apiroutes.GetAppsAppRoutesNotFound: case *apiroutes.GetAppsAppRoutesNotFound:
return fmt.Errorf("error: %s", err.(*apiroutes.GetAppsAppRoutesNotFound).Payload.Error.Message) return fmt.Errorf("error: %s", e.Payload.Error.Message)
case *apiroutes.GetAppsAppRoutesDefault: case *apiroutes.GetAppsAppRoutesDefault:
return fmt.Errorf("unexpected error: %s", err.(*apiroutes.GetAppsAppRoutesDefault).Payload.Error.Message) return fmt.Errorf("unexpected error: %s", e.Payload.Error.Message)
default:
return fmt.Errorf("unexpected error: %v", err)
} }
return fmt.Errorf("unexpected error: %s", err)
} }
w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0) w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0)
@@ -260,7 +261,7 @@ func routeWithFlags(c *cli.Context, rt *fnmodels.Route) {
} }
} }
func routeWithFuncFile(c *cli.Context, ff *funcfile, rt *fnmodels.Route) error { func routeWithFuncFile(ff *funcfile, rt *fnmodels.Route) error {
var err error var err error
if ff == nil { if ff == nil {
ff, err = loadFuncfile() ff, err = loadFuncfile()
@@ -268,8 +269,8 @@ func routeWithFuncFile(c *cli.Context, ff *funcfile, rt *fnmodels.Route) error {
return err return err
} }
} }
if ff.FullName() != "" { // args take precedence if ff.ImageName() != "" { // args take precedence
rt.Image = ff.FullName() rt.Image = ff.ImageName()
} }
if ff.Format != "" { if ff.Format != "" {
rt.Format = ff.Format rt.Format = ff.Format
@@ -286,7 +287,15 @@ func routeWithFuncFile(c *cli.Context, ff *funcfile, rt *fnmodels.Route) error {
if ff.Memory != 0 { if ff.Memory != 0 {
rt.Memory = ff.Memory rt.Memory = ff.Memory
} }
// TODO idle_timeout? headers? config? why is a func file not a yaml unmarshal of a route? if rt.IDLETimeout != nil {
rt.IDLETimeout = ff.IDLETimeout
}
if len(rt.Headers) != 0 {
rt.Headers = ff.Headers
}
if len(rt.Config) != 0 {
rt.Config = ff.Config
}
return nil return nil
} }
@@ -299,7 +308,7 @@ func (a *routesCmd) create(c *cli.Context) error {
rt.Path = route rt.Path = route
rt.Image = c.Args().Get(2) rt.Image = c.Args().Get(2)
if err := routeWithFuncFile(c, nil, rt); err != nil { if err := routeWithFuncFile(nil, rt); err != nil {
return fmt.Errorf("error getting route info: %s", err) return fmt.Errorf("error getting route info: %s", err)
} }
@@ -328,15 +337,16 @@ func (a *routesCmd) postRoute(c *cli.Context, appName string, rt *fnmodels.Route
}) })
if err != nil { if err != nil {
switch err.(type) { switch e := err.(type) {
case *apiroutes.PostAppsAppRoutesBadRequest: case *apiroutes.PostAppsAppRoutesBadRequest:
return fmt.Errorf("error: %s", err.(*apiroutes.PostAppsAppRoutesBadRequest).Payload.Error.Message) return fmt.Errorf("error: %s", e.Payload.Error.Message)
case *apiroutes.PostAppsAppRoutesConflict: case *apiroutes.PostAppsAppRoutesConflict:
return fmt.Errorf("error: %s", err.(*apiroutes.PostAppsAppRoutesConflict).Payload.Error.Message) return fmt.Errorf("error: %s", e.Payload.Error.Message)
case *apiroutes.PostAppsAppRoutesDefault: case *apiroutes.PostAppsAppRoutesDefault:
return fmt.Errorf("unexpected error: %s", err.(*apiroutes.PostAppsAppRoutesDefault).Payload.Error.Message) return fmt.Errorf("unexpected error: %s", e.Payload.Error.Message)
default:
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)
@@ -352,15 +362,16 @@ func (a *routesCmd) patchRoute(c *cli.Context, appName, routePath string, r *fnm
}) })
if err != nil { if err != nil {
switch err.(type) { switch e := err.(type) {
case *apiroutes.PatchAppsAppRoutesRouteBadRequest: case *apiroutes.PatchAppsAppRoutesRouteBadRequest:
return fmt.Errorf("error: %s", err.(*apiroutes.PatchAppsAppRoutesRouteBadRequest).Payload.Error.Message) return fmt.Errorf("error: %s", e.Payload.Error.Message)
case *apiroutes.PatchAppsAppRoutesRouteNotFound: case *apiroutes.PatchAppsAppRoutesRouteNotFound:
return fmt.Errorf("error: %s", err.(*apiroutes.PatchAppsAppRoutesRouteNotFound).Payload.Error.Message) return fmt.Errorf("error: %s", e.Payload.Error.Message)
case *apiroutes.PatchAppsAppRoutesRouteDefault: case *apiroutes.PatchAppsAppRoutesRouteDefault:
return fmt.Errorf("unexpected error: %s", err.(*apiroutes.PatchAppsAppRoutesRouteDefault).Payload.Error.Message) return fmt.Errorf("unexpected error: %s", e.Payload.Error.Message)
default:
return fmt.Errorf("unexpected error: %v", err)
} }
return fmt.Errorf("unexpected error: %s", err)
} }
return nil return nil
@@ -374,13 +385,14 @@ func (a *routesCmd) putRoute(c *cli.Context, appName, routePath string, r *fnmod
Body: &fnmodels.RouteWrapper{Route: r}, Body: &fnmodels.RouteWrapper{Route: r},
}) })
if err != nil { if err != nil {
switch err.(type) { switch e := err.(type) {
case *apiroutes.PutAppsAppRoutesRouteBadRequest: case *apiroutes.PutAppsAppRoutesRouteBadRequest:
return fmt.Errorf("error: %s", err.(*apiroutes.PutAppsAppRoutesRouteBadRequest).Payload.Error.Message) return fmt.Errorf("error: %s", e.Payload.Error.Message)
case *apiroutes.PutAppsAppRoutesRouteDefault: case *apiroutes.PutAppsAppRoutesRouteDefault:
return fmt.Errorf("unexpected error: %s", err.(*apiroutes.PutAppsAppRoutesRouteDefault).Payload.Error.Message) return fmt.Errorf("unexpected error: %s", e.Payload.Error.Message)
default:
return fmt.Errorf("unexpected error: %v", err)
} }
return fmt.Errorf("unexpected error: %s", err)
} }
return nil return nil
} }
@@ -392,7 +404,7 @@ func (a *routesCmd) update(c *cli.Context) error {
rt := &fnmodels.Route{} rt := &fnmodels.Route{}
if !c.Bool("ignore-fn-file") { if !c.Bool("ignore-fn-file") {
if err := routeWithFuncFile(c, nil, rt); err != nil { if err := routeWithFuncFile(nil, rt); err != nil {
return fmt.Errorf("error updating route: %s", err) return fmt.Errorf("error updating route: %s", err)
} }
} }
@@ -461,13 +473,14 @@ func (a *routesCmd) inspect(c *cli.Context) error {
}) })
if err != nil { if err != nil {
switch err.(type) { switch e := err.(type) {
case *apiroutes.GetAppsAppRoutesRouteNotFound: case *apiroutes.GetAppsAppRoutesRouteNotFound:
return fmt.Errorf("error: %s", err.(*apiroutes.GetAppsAppRoutesRouteNotFound).Payload.Error.Message) return fmt.Errorf("error: %s", e.Payload.Error.Message)
case *apiroutes.GetAppsAppRoutesRouteDefault: case *apiroutes.GetAppsAppRoutesRouteDefault:
return fmt.Errorf("unexpected error: %s", err.(*apiroutes.GetAppsAppRoutesRouteDefault).Payload.Error.Message) return fmt.Errorf("unexpected error: %s", e.Payload.Error.Message)
default:
return fmt.Errorf("unexpected error: %v", err)
} }
return fmt.Errorf("unexpected error: %s", err)
} }
enc := json.NewEncoder(os.Stdout) enc := json.NewEncoder(os.Stdout)
@@ -508,13 +521,14 @@ func (a *routesCmd) delete(c *cli.Context) error {
Route: route, Route: route,
}) })
if err != nil { if err != nil {
switch err.(type) { switch e := err.(type) {
case *apiroutes.DeleteAppsAppRoutesRouteNotFound: case *apiroutes.DeleteAppsAppRoutesRouteNotFound:
return fmt.Errorf("error: %s", err.(*apiroutes.DeleteAppsAppRoutesRouteNotFound).Payload.Error.Message) return fmt.Errorf("error: %s", e.Payload.Error.Message)
case *apiroutes.DeleteAppsAppRoutesRouteDefault: case *apiroutes.DeleteAppsAppRoutesRouteDefault:
return fmt.Errorf("unexpected error: %s", err.(*apiroutes.DeleteAppsAppRoutesRouteDefault).Payload.Error.Message) return fmt.Errorf("unexpected error: %s", e.Payload.Error.Message)
default:
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

@@ -176,7 +176,7 @@ func runff(ff *funcfile, stdin io.Reader, stdout, stderr io.Writer, method strin
stdin = strings.NewReader(body) stdin = strings.NewReader(body)
} }
sh = append(sh, ff.FullName()) sh = append(sh, ff.ImageName())
cmd := exec.Command(sh[0], sh[1:]...) cmd := exec.Command(sh[0], sh[1:]...)
cmd.Stdin = stdin cmd.Stdin = stdin
cmd.Stdout = stdout cmd.Stdout = stdout

View File

@@ -95,7 +95,7 @@ func (t *testcmd) test(c *cli.Context) error {
fmt.Printf("Running %v tests...", len(tests)) fmt.Printf("Running %v tests...", len(tests))
target := ff.FullName() target := ff.ImageName()
runtest := runlocaltest runtest := runlocaltest
if t.remote != "" { if t.remote != "" {
if ff.Path == "" { if ff.Path == "" {
@@ -116,7 +116,7 @@ func (t *testcmd) test(c *cli.Context) error {
} }
errorCount := 0 errorCount := 0
fmt.Println("running tests on", ff.FullName(), ":") fmt.Println("running tests on", ff.ImageName(), ":")
for i, tt := range tests { for i, tt := range tests {
fmt.Printf("\nTest %v\n", i+1) fmt.Printf("\nTest %v\n", i+1)
start := time.Now() start := time.Now()