Renamed a bunch of images to use fnproject org. (#239)

* Renamed a bunch of images to use fnproject org.

* Multi-stage build for Docker.

* Added tmp vendor dirs to gitignore.

* Run docker-build at beginning of test.
This commit is contained in:
Travis Reeder
2017-08-23 12:43:53 -07:00
committed by Denis Makogon
parent f90879b751
commit f559acd7ed
56 changed files with 126 additions and 203 deletions

2
.gitignore vendored
View File

@@ -17,6 +17,8 @@ bolt.db
.glide/ .glide/
/fnctl /fnctl
_vendor*/
private.sh private.sh
.env .env
*.pem *.pem

View File

@@ -1,56 +0,0 @@
image: funcy/go-dind:latest
cache:
key: "$CI_COMMIT_REF_NAME"
untracked: true
stages:
# - deps
- build
- test
- deploy
before_script:
- mkdir -p "${GOPATH}/src/gitlab-odx.oracle.com/odx/"
- ln -s `pwd` "${GOPATH}/src/gitlab-odx.oracle.com/odx/"
- cd "${GOPATH}/src/github.com/fnproject/fn"
build_job:
stage: build
script:
- make build
build_job_fn:
stage: build
script:
- cd fn
- make build
formatting:
stage: build
script:
- ./go-fmt.sh
test_job:
stage: test
script:
- DOCKER_LOCATION=container_ip ./test.sh
integration_tests:
stage: test
script:
- DOCKER_LOCATION=container_ip make docker-test-run-with-sqlite3
deploy_job:
only:
- tags
- master
stage: deploy
script:
- ls
- docker build -t ${DOCKER_IMAGE}:latest .
- docker tag ${DOCKER_IMAGE}:latest ${DOCKER_IMAGE}:${CI_COMMIT_REF_NAME}
- docker login -p ${DOCKER_PASSWORD} -u ${DOCKER_USERNAME} ${DOCKER_REGISTRY}
- docker push ${DOCKER_IMAGE}:${CI_COMMIT_REF_NAME}
- docker push ${DOCKER_IMAGE}:latest
- curl -k -X POST -F token=${GITLAB_TRIGGER_TOKEN} -F ref=${BRANCH_TO_DEPLOY} ${GITLAB_TRIGGER_URL}

View File

@@ -1,7 +1,13 @@
FROM funcy/dind # build stage
FROM golang:alpine AS build-env
RUN apk --no-cache add build-base git bzr mercurial gcc
ENV D=/go/src/github.com/fnproject/fn
# TODO: once we get rid of the vendor dirs, add dep step using `dep ensure --vendor-only` from here: https://medium.com/travis-on-docker/triple-stage-docker-builds-with-go-and-angular-1b7d2006cb88
ADD . $D
RUN cd $D && go build -o fn-alpine && cp fn-alpine /tmp/
# final stage
FROM fnproject/dind
WORKDIR /app WORKDIR /app
COPY --from=build-env /tmp/fn-alpine /app/functions
ADD functions-alpine /app/functions
CMD ["./functions"] CMD ["./functions"]

View File

@@ -36,9 +36,7 @@ docker-dep:
docker run --rm -it -v ${CURDIR}:/go/src/github.com/fnproject/fn -w /go/src/github.com/fnproject/fn treeder/glide install -v docker run --rm -it -v ${CURDIR}:/go/src/github.com/fnproject/fn -w /go/src/github.com/fnproject/fn treeder/glide install -v
docker-build: docker-build:
docker pull funcy/go:dev docker build --build-arg HTTP_PROXY -t fnproject/functions:latest .
docker run --rm -v ${CURDIR}:/go/src/github.com/fnproject/fn -w /go/src/github.com/fnproject/fn funcy/go:dev go build -o functions-alpine
docker build --build-arg HTTP_PROXY -t funcy/functions:latest .
docker-run: docker-build docker-run: docker-build
docker run --rm --privileged -it -e NO_PROXY -e HTTP_PROXY -e LOG_LEVEL=debug -e "DB_URL=sqlite3:///app/data/fn.db" -v ${CURDIR}/data:/app/data -p 8080:8080 funcy/functions docker run --rm --privileged -it -e NO_PROXY -e HTTP_PROXY -e LOG_LEVEL=debug -e "DB_URL=sqlite3:///app/data/fn.db" -v ${CURDIR}/data:/app/data -p 8080:8080 funcy/functions

View File

@@ -310,7 +310,7 @@ func Test(t *testing.T, ds models.Datastore) {
// unchanged // unchanged
AppName: testRoute.AppName, AppName: testRoute.AppName,
Path: testRoute.Path, Path: testRoute.Path,
Image: "funcy/hello", Image: "fnproject/hello",
Type: "sync", Type: "sync",
Format: "http", Format: "http",
// updated // updated
@@ -353,7 +353,7 @@ func Test(t *testing.T, ds models.Datastore) {
// unchanged // unchanged
AppName: testRoute.AppName, AppName: testRoute.AppName,
Path: testRoute.Path, Path: testRoute.Path,
Image: "funcy/hello", Image: "fnproject/hello",
Type: "sync", Type: "sync",
Format: "http", Format: "http",
Timeout: 100, Timeout: 100,
@@ -477,7 +477,7 @@ var testApp = &models.App{
var testRoute = &models.Route{ var testRoute = &models.Route{
AppName: testApp.Name, AppName: testApp.Name,
Path: "/test", Path: "/test",
Image: "funcy/hello", Image: "fnproject/hello",
Type: "sync", Type: "sync",
Format: "http", Format: "http",
} }

View File

@@ -18,7 +18,7 @@ var testApp = &models.App{
var testRoute = &models.Route{ var testRoute = &models.Route{
AppName: testApp.Name, AppName: testApp.Name,
Path: "/test", Path: "/test",
Image: "funcy/hello", Image: "fnproject/hello",
Type: "sync", Type: "sync",
Format: "http", Format: "http",
} }

View File

@@ -26,7 +26,7 @@ func (f *taskDockerTest) EnvVars() map[string]string {
func (f *taskDockerTest) Labels() map[string]string { return nil } func (f *taskDockerTest) Labels() map[string]string { return nil }
func (f *taskDockerTest) Id() string { return f.id } func (f *taskDockerTest) Id() string { return f.id }
func (f *taskDockerTest) Group() string { return "" } func (f *taskDockerTest) Group() string { return "" }
func (f *taskDockerTest) Image() string { return "funcy/hello" } func (f *taskDockerTest) Image() string { return "fnproject/hello" }
func (f *taskDockerTest) Timeout() time.Duration { return 30 * time.Second } func (f *taskDockerTest) Timeout() time.Duration { return 30 * time.Second }
func (f *taskDockerTest) Logger() (stdout, stderr io.Writer) { return f.output, nil } func (f *taskDockerTest) Logger() (stdout, stderr io.Writer) { return f.output, nil }
func (f *taskDockerTest) WriteStat(drivers.Stat) { /* TODO */ } func (f *taskDockerTest) WriteStat(drivers.Stat) { /* TODO */ }
@@ -92,7 +92,7 @@ func TestRunnerDockerStdin(t *testing.T) {
} }
func TestRegistry(t *testing.T) { func TestRegistry(t *testing.T) {
image := "funcy/hello" image := "fnproject/hello"
sizer, err := CheckRegistry(context.Background(), image, docker.AuthConfiguration{}) sizer, err := CheckRegistry(context.Background(), image, docker.AuthConfiguration{})
if err != nil { if err != nil {

View File

@@ -94,14 +94,14 @@ func TestDecimate(t *testing.T) {
func TestParseImage(t *testing.T) { func TestParseImage(t *testing.T) {
cases := map[string][]string{ cases := map[string][]string{
"funcy/hello": {"", "funcy/hello", "latest"}, "fnproject/hello": {"", "fnproject/hello", "latest"},
"funcy/hello:v1": {"", "funcy/hello", "v1"}, "fnproject/hello:v1": {"", "fnproject/hello", "v1"},
"my.registry/hello": {"my.registry", "hello", "latest"}, "my.registry/hello": {"my.registry", "hello", "latest"},
"my.registry/hello:v1": {"my.registry", "hello", "v1"}, "my.registry/hello:v1": {"my.registry", "hello", "v1"},
"mongo": {"", "library/mongo", "latest"}, "mongo": {"", "library/mongo", "latest"},
"mongo:v1": {"", "library/mongo", "v1"}, "mongo:v1": {"", "library/mongo", "v1"},
"quay.com/funcy/hello": {"quay.com", "funcy/hello", "latest"}, "quay.com/fnproject/hello": {"quay.com", "fnproject/hello", "latest"},
"quay.com:8080/funcy/hello:v2": {"quay.com:8080", "funcy/hello", "v2"}, "quay.com:8080/fnproject/hello:v2": {"quay.com:8080", "fnproject/hello", "v2"},
"localhost.localdomain:5000/samalba/hipache:latest": {"localhost.localdomain:5000", "samalba/hipache", "latest"}, "localhost.localdomain:5000/samalba/hipache:latest": {"localhost.localdomain:5000", "samalba/hipache", "latest"},
} }

View File

@@ -36,8 +36,8 @@ func TestRunnerHello(t *testing.T) {
expectedErr string expectedErr string
taskID string taskID string
}{ }{
{&models.Route{Image: "funcy/hello"}, ``, "success", "Hello World!", "", id.New().String()}, {&models.Route{Image: "fnproject/hello"}, ``, "success", "Hello World!", "", id.New().String()},
{&models.Route{Image: "funcy/hello"}, `{"name": "test"}`, "success", "Hello test!", "", id.New().String()}, {&models.Route{Image: "fnproject/hello"}, `{"name": "test"}`, "success", "Hello test!", "", id.New().String()},
} { } {
var stdout, stderr bytes.Buffer var stdout, stderr bytes.Buffer
cfg := &task.Config{ cfg := &task.Config{
@@ -96,8 +96,8 @@ func TestRunnerError(t *testing.T) {
expectedErr string expectedErr string
taskID string taskID string
}{ }{
{&models.Route{Image: "funcy/error"}, ``, "error", "", "", id.New().String()}, {&models.Route{Image: "fnproject/error"}, ``, "error", "", "", id.New().String()},
{&models.Route{Image: "funcy/error"}, `{"name": "test"}`, "error", "", "", id.New().String()}, {&models.Route{Image: "fnproject/error"}, `{"name": "test"}`, "error", "", "", id.New().String()},
} { } {
var stdout, stderr bytes.Buffer var stdout, stderr bytes.Buffer
cfg := &task.Config{ cfg := &task.Config{

View File

@@ -61,9 +61,9 @@ func TestRouteCreate(t *testing.T) {
{datastore.NewMock(), logs.NewMock(), http.MethodPost, "/v1/apps/a/routes", `{ "path": "/myroute", "type": "sync" }`, http.StatusBadRequest, models.ErrRoutesMissingNew}, {datastore.NewMock(), logs.NewMock(), http.MethodPost, "/v1/apps/a/routes", `{ "path": "/myroute", "type": "sync" }`, http.StatusBadRequest, models.ErrRoutesMissingNew},
{datastore.NewMock(), logs.NewMock(), http.MethodPost, "/v1/apps/a/routes", `{ "route": { } }`, http.StatusBadRequest, models.ErrRoutesValidationMissingPath}, {datastore.NewMock(), logs.NewMock(), http.MethodPost, "/v1/apps/a/routes", `{ "route": { } }`, http.StatusBadRequest, models.ErrRoutesValidationMissingPath},
{datastore.NewMock(), logs.NewMock(), http.MethodPost, "/v1/apps/a/routes", `{ "route": { "path": "/myroute", "type": "sync" } }`, http.StatusBadRequest, models.ErrRoutesValidationMissingImage}, {datastore.NewMock(), logs.NewMock(), http.MethodPost, "/v1/apps/a/routes", `{ "route": { "path": "/myroute", "type": "sync" } }`, http.StatusBadRequest, models.ErrRoutesValidationMissingImage},
{datastore.NewMock(), logs.NewMock(), http.MethodPost, "/v1/apps/a/routes", `{ "route": { "image": "funcy/hello", "type": "sync" } }`, http.StatusBadRequest, models.ErrRoutesValidationMissingPath}, {datastore.NewMock(), logs.NewMock(), http.MethodPost, "/v1/apps/a/routes", `{ "route": { "image": "fnproject/hello", "type": "sync" } }`, http.StatusBadRequest, models.ErrRoutesValidationMissingPath},
{datastore.NewMock(), logs.NewMock(), http.MethodPost, "/v1/apps/a/routes", `{ "route": { "image": "funcy/hello", "path": "myroute", "type": "sync" } }`, http.StatusBadRequest, models.ErrRoutesValidationInvalidPath}, {datastore.NewMock(), logs.NewMock(), http.MethodPost, "/v1/apps/a/routes", `{ "route": { "image": "fnproject/hello", "path": "myroute", "type": "sync" } }`, http.StatusBadRequest, models.ErrRoutesValidationInvalidPath},
{datastore.NewMock(), logs.NewMock(), http.MethodPost, "/v1/apps/$/routes", `{ "route": { "image": "funcy/hello", "path": "/myroute", "type": "sync" } }`, http.StatusBadRequest, models.ErrAppsValidationInvalidName}, {datastore.NewMock(), logs.NewMock(), http.MethodPost, "/v1/apps/$/routes", `{ "route": { "image": "fnproject/hello", "path": "/myroute", "type": "sync" } }`, http.StatusBadRequest, models.ErrAppsValidationInvalidName},
{datastore.NewMockInit(nil, {datastore.NewMockInit(nil,
[]*models.Route{ []*models.Route{
{ {
@@ -71,10 +71,10 @@ func TestRouteCreate(t *testing.T) {
Path: "/myroute", Path: "/myroute",
}, },
}, nil, nil, }, nil, nil,
), logs.NewMock(), http.MethodPost, "/v1/apps/a/routes", `{ "route": { "image": "funcy/hello", "path": "/myroute", "type": "sync" } }`, http.StatusConflict, models.ErrRoutesAlreadyExists}, ), logs.NewMock(), http.MethodPost, "/v1/apps/a/routes", `{ "route": { "image": "fnproject/hello", "path": "/myroute", "type": "sync" } }`, http.StatusConflict, models.ErrRoutesAlreadyExists},
// success // success
{datastore.NewMock(), logs.NewMock(), http.MethodPost, "/v1/apps/a/routes", `{ "route": { "image": "funcy/hello", "path": "/myroute", "type": "sync" } }`, http.StatusOK, nil}, {datastore.NewMock(), logs.NewMock(), http.MethodPost, "/v1/apps/a/routes", `{ "route": { "image": "fnproject/hello", "path": "/myroute", "type": "sync" } }`, http.StatusOK, nil},
} { } {
test.run(t, i, buf) test.run(t, i, buf)
} }
@@ -89,15 +89,15 @@ func TestRoutePut(t *testing.T) {
{datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "path": "/myroute", "type": "sync" }`, http.StatusBadRequest, models.ErrRoutesMissingNew}, {datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "path": "/myroute", "type": "sync" }`, http.StatusBadRequest, models.ErrRoutesMissingNew},
{datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "route": { "type": "sync" } }`, http.StatusBadRequest, models.ErrRoutesValidationMissingImage}, {datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "route": { "type": "sync" } }`, http.StatusBadRequest, models.ErrRoutesValidationMissingImage},
{datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "route": { "path": "/myroute", "type": "sync" } }`, http.StatusBadRequest, models.ErrRoutesValidationMissingImage}, {datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "route": { "path": "/myroute", "type": "sync" } }`, http.StatusBadRequest, models.ErrRoutesValidationMissingImage},
{datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "route": { "image": "funcy/hello", "path": "myroute", "type": "sync" } }`, http.StatusConflict, models.ErrRoutesPathImmutable}, {datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "route": { "image": "fnproject/hello", "path": "myroute", "type": "sync" } }`, http.StatusConflict, models.ErrRoutesPathImmutable},
{datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "route": { "image": "funcy/hello", "path": "diffRoute", "type": "sync" } }`, http.StatusConflict, models.ErrRoutesPathImmutable}, {datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "route": { "image": "fnproject/hello", "path": "diffRoute", "type": "sync" } }`, http.StatusConflict, models.ErrRoutesPathImmutable},
{datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/$/routes/myroute", `{ "route": { "image": "funcy/hello", "path": "/myroute", "type": "sync" } }`, http.StatusBadRequest, models.ErrAppsValidationInvalidName}, {datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/$/routes/myroute", `{ "route": { "image": "fnproject/hello", "path": "/myroute", "type": "sync" } }`, http.StatusBadRequest, models.ErrAppsValidationInvalidName},
{datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "route": { "image": "funcy/hello", "path": "/myroute", "type": "invalid-type" } }`, http.StatusBadRequest, models.ErrRoutesValidationInvalidType}, {datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "route": { "image": "fnproject/hello", "path": "/myroute", "type": "invalid-type" } }`, http.StatusBadRequest, models.ErrRoutesValidationInvalidType},
{datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "route": { "image": "funcy/hello", "path": "/myroute", "format": "invalid-format", "type": "sync" } }`, http.StatusBadRequest, models.ErrRoutesValidationInvalidFormat}, {datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "route": { "image": "fnproject/hello", "path": "/myroute", "format": "invalid-format", "type": "sync" } }`, http.StatusBadRequest, models.ErrRoutesValidationInvalidFormat},
// success // success
{datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "route": { "image": "funcy/hello", "path": "/myroute", "type": "sync" } }`, http.StatusOK, nil}, {datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "route": { "image": "fnproject/hello", "path": "/myroute", "type": "sync" } }`, http.StatusOK, nil},
{datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "route": { "image": "funcy/hello", "type": "sync" } }`, http.StatusOK, nil}, {datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "route": { "image": "fnproject/hello", "type": "sync" } }`, http.StatusOK, nil},
} { } {
test.run(t, i, buf) test.run(t, i, buf)
} }
@@ -239,7 +239,7 @@ func TestRouteUpdate(t *testing.T) {
Path: "/myroute/do", Path: "/myroute/do",
}, },
}, nil, nil, }, nil, nil,
), logs.NewMock(), http.MethodPatch, "/v1/apps/a/routes/myroute/do", `{ "route": { "image": "funcy/hello" } }`, http.StatusOK, nil}, ), logs.NewMock(), http.MethodPatch, "/v1/apps/a/routes/myroute/do", `{ "route": { "image": "fnproject/hello" } }`, http.StatusOK, nil},
// Addresses #381 // Addresses #381
{datastore.NewMockInit(nil, {datastore.NewMockInit(nil,

View File

@@ -43,9 +43,9 @@ func TestRouteRunnerAsyncExecution(t *testing.T) {
{Name: "myapp", Config: map[string]string{"app": "true"}}, {Name: "myapp", Config: map[string]string{"app": "true"}},
}, },
[]*models.Route{ []*models.Route{
{Type: "async", Path: "/myroute", AppName: "myapp", Image: "funcy/hello", Config: map[string]string{"test": "true"}}, {Type: "async", Path: "/myroute", AppName: "myapp", Image: "fnproject/hello", Config: map[string]string{"test": "true"}},
{Type: "async", Path: "/myerror", AppName: "myapp", Image: "funcy/error", Config: map[string]string{"test": "true"}}, {Type: "async", Path: "/myerror", AppName: "myapp", Image: "fnproject/error", Config: map[string]string{"test": "true"}},
{Type: "async", Path: "/myroute/:param", AppName: "myapp", Image: "funcy/hello", Config: map[string]string{"test": "true"}}, {Type: "async", Path: "/myroute/:param", AppName: "myapp", Image: "fnproject/hello", Config: map[string]string{"test": "true"}},
}, nil, nil, }, nil, nil,
) )
mq := &mqs.Mock{} mq := &mqs.Mock{}

View File

@@ -125,9 +125,9 @@ func TestRouteRunnerExecution(t *testing.T) {
{Name: "myapp", Config: models.Config{}}, {Name: "myapp", Config: models.Config{}},
}, },
[]*models.Route{ []*models.Route{
{Path: "/", AppName: "myapp", Image: "funcy/hello", Headers: map[string][]string{"X-Function": {"Test"}}}, {Path: "/", AppName: "myapp", Image: "fnproject/hello", Headers: map[string][]string{"X-Function": {"Test"}}},
{Path: "/myroute", AppName: "myapp", Image: "funcy/hello", Headers: map[string][]string{"X-Function": {"Test"}}}, {Path: "/myroute", AppName: "myapp", Image: "fnproject/hello", Headers: map[string][]string{"X-Function": {"Test"}}},
{Path: "/myerror", AppName: "myapp", Image: "funcy/error", Headers: map[string][]string{"X-Function": {"Test"}}}, {Path: "/myerror", AppName: "myapp", Image: "fnproject/error", Headers: map[string][]string{"X-Function": {"Test"}}},
}, nil, nil, }, nil, nil,
) )
@@ -223,7 +223,7 @@ func TestRouteRunnerTimeout(t *testing.T) {
{Name: "myapp", Config: models.Config{}}, {Name: "myapp", Config: models.Config{}},
}, },
[]*models.Route{ []*models.Route{
{Path: "/sleeper", AppName: "myapp", Image: "funcy/sleeper", Timeout: 1}, {Path: "/sleeper", AppName: "myapp", Image: "fnproject/sleeper", Timeout: 1},
}, nil, nil, }, nil, nil,
) )
fnl := logs.NewMock() fnl := logs.NewMock()

View File

@@ -116,8 +116,8 @@ func TestFullStack(t *testing.T) {
{"list apps", "GET", "/v1/apps", ``, http.StatusOK, 0}, {"list apps", "GET", "/v1/apps", ``, http.StatusOK, 0},
{"get app", "GET", "/v1/apps/myapp", ``, http.StatusOK, 0}, {"get app", "GET", "/v1/apps/myapp", ``, http.StatusOK, 0},
// NOTE: cache is lazy, loads when a request comes in for the route, not when added // NOTE: cache is lazy, loads when a request comes in for the route, not when added
{"add myroute", "POST", "/v1/apps/myapp/routes", `{ "route": { "name": "myroute", "path": "/myroute", "image": "funcy/hello", "type": "sync" } }`, http.StatusOK, 0}, {"add myroute", "POST", "/v1/apps/myapp/routes", `{ "route": { "name": "myroute", "path": "/myroute", "image": "fnproject/hello", "type": "sync" } }`, http.StatusOK, 0},
{"add myroute2", "POST", "/v1/apps/myapp/routes", `{ "route": { "name": "myroute2", "path": "/myroute2", "image": "funcy/error", "type": "sync" } }`, http.StatusOK, 0}, {"add myroute2", "POST", "/v1/apps/myapp/routes", `{ "route": { "name": "myroute2", "path": "/myroute2", "image": "fnproject/error", "type": "sync" } }`, http.StatusOK, 0},
{"get myroute", "GET", "/v1/apps/myapp/routes/myroute", ``, http.StatusOK, 0}, {"get myroute", "GET", "/v1/apps/myapp/routes/myroute", ``, http.StatusOK, 0},
{"get myroute2", "GET", "/v1/apps/myapp/routes/myroute2", ``, http.StatusOK, 0}, {"get myroute2", "GET", "/v1/apps/myapp/routes/myroute2", ``, http.StatusOK, 0},
{"get all routes", "GET", "/v1/apps/myapp/routes", ``, http.StatusOK, 0}, {"get all routes", "GET", "/v1/apps/myapp/routes", ``, http.StatusOK, 0},

View File

@@ -1,49 +0,0 @@
machine:
environment:
CHECKOUT_DIR: $HOME/$CIRCLE_PROJECT_REPONAME
GOPATH: $HOME/go
GOROOT: $HOME/golang/go
PATH: $GOROOT/bin:$GOPATH/bin:/$PATH
GH_OWNER: $GOPATH/src/github.com/treeder
GO_PROJECT: ../go/src/github.com/treeder/$CIRCLE_PROJECT_REPONAME
services:
- docker
checkout:
post:
- mkdir -p "$GH_OWNER"
- cp -R "$CHECKOUT_DIR" "$GH_OWNER/$CIRCLE_PROJECT_REPONAME"
dependencies:
pre:
- wget https://storage.googleapis.com/golang/go1.8.linux-amd64.tar.gz
- mkdir -p $HOME/golang
- tar -C $HOME/golang -xvzf go1.8.linux-amd64.tar.gz
- go get -u github.com/golang/dep/...
override:
- which go && go version
- make dep:
pwd: $GO_PROJECT
test:
override:
- make fmt:
pwd: $GO_PROJECT
- make test:
pwd: $GO_PROJECT
- make test-build-arm:
pwd: $GO_PROJECT
- go build:
pwd: $GO_PROJECT/examples/middleware
- go build:
pwd: $GO_PROJECT/examples/extensions
deployment:
release:
branch: master
owner: treeder
commands:
- git config --global user.email "treeder+circle@gmail.com"
- git config --global user.name "CircleCI"
- docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS
- cd $GO_PROJECT && ./release.sh

View File

@@ -9,8 +9,8 @@ install:
docker: vendor docker: vendor
GOOS=linux go build -o fn GOOS=linux go build -o fn
docker build -t treeder/fn . docker build -t fnproject/fn .
docker push treeder/fn docker push fnproject/fn
dep: dep:
glide install -v glide install -v

View File

@@ -71,10 +71,10 @@ otherapp
$ fn routes list myapp # list routes of an app $ fn routes list myapp # list routes of an app
path image path image
/hello funcy/hello /hello fnproject/hello
$ fn routes create otherapp /hello funcy/hello # create route $ fn routes create otherapp /hello fnproject/hello # create route
/hello created with funcy/hello /hello created with fnproject/hello
$ fn routes delete otherapp hello # delete route $ fn routes delete otherapp hello # delete route
/hello deleted /hello deleted
@@ -131,7 +131,7 @@ choices are: `memory`, `type` and `config`.
Thus a more complete example of route creation will look like: Thus a more complete example of route creation will look like:
```sh ```sh
fn routes create --memory 256 --type async --config DB_URL=http://example.org/ otherapp /hello funcy/hello fn routes create --memory 256 --type async --config DB_URL=http://example.org/ otherapp /hello fnproject/hello
``` ```
You can also update existent routes configurations using the command `fn routes update` You can also update existent routes configurations using the command `fn routes update`
@@ -139,7 +139,7 @@ You can also update existent routes configurations using the command `fn routes
For example: For example:
```sh ```sh
fn routes update --memory 64 --type sync --image funcy/hello fn routes update --memory 64 --type sync --image fnproject/hello
``` ```
To know exactly what configurations you can update just use the command To know exactly what configurations you can update just use the command
@@ -215,7 +215,7 @@ $ fn test --remote myapp
### Creating a new function from source ### Creating a new function from source
``` ```
fn init funcy/hello --runtime ruby fn init fnproject/hello --runtime ruby
fn deploy myapp /hello fn deploy myapp /hello
``` ```
@@ -226,7 +226,7 @@ fn deploy myapp (discover route path if available in func.yaml)
### Testing function locally ### Testing function locally
``` ```
fn run funcy/hello fn run fnproject/hello
``` ```
### Testing route ### Testing route
@@ -245,7 +245,7 @@ fn apps delete myapp
### Route management ### Route management
``` ```
fn routes create myapp /hello funcy/hello fn routes create myapp /hello fnproject/hello
# routes update will also update any changes in the func.yaml file too. # 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

View File

@@ -21,7 +21,7 @@ import (
) )
const ( const (
functionsDockerImage = "funcy/functions" functionsDockerImage = "fnproject/functions"
minRequiredDockerVersion = "17.5.0" minRequiredDockerVersion = "17.5.0"
envFnRegistry = "FN_REGISTRY" envFnRegistry = "FN_REGISTRY"
) )

View File

@@ -46,6 +46,7 @@ html_url=$(echo "$output" | python -c 'import json,sys;obj=json.load(sys.stdin);
curl --data-binary "@fn_linux" -H "Content-Type: application/octet-stream" -u $GH_DEPLOY_USER:$GH_DEPLOY_KEY $upload_url\?name\=fn_linux >/dev/null curl --data-binary "@fn_linux" -H "Content-Type: application/octet-stream" -u $GH_DEPLOY_USER:$GH_DEPLOY_KEY $upload_url\?name\=fn_linux >/dev/null
curl --data-binary "@fn_mac" -H "Content-Type: application/octet-stream" -u $GH_DEPLOY_USER:$GH_DEPLOY_KEY $upload_url\?name\=fn_mac >/dev/null curl --data-binary "@fn_mac" -H "Content-Type: application/octet-stream" -u $GH_DEPLOY_USER:$GH_DEPLOY_KEY $upload_url\?name\=fn_mac >/dev/null
curl --data-binary "@fn.exe" -H "Content-Type: application/octet-stream" -u $GH_DEPLOY_USER:$GH_DEPLOY_KEY $upload_url\?name\=fn.exe >/dev/null curl --data-binary "@fn.exe" -H "Content-Type: application/octet-stream" -u $GH_DEPLOY_USER:$GH_DEPLOY_KEY $upload_url\?name\=fn.exe >/dev/null
curl --data-binary "@fn_alpine" -H "Content-Type: application/octet-stream" -u $GH_DEPLOY_USER:$GH_DEPLOY_KEY $upload_url\?name\=fn_alpine >/dev/null
# TODO: Add the download URLS to install.sh. Maybe we should make a template to generate install.sh # TODO: Add the download URLS to install.sh. Maybe we should make a template to generate install.sh
# TODO: Download URL's are in the output vars above under "url". Eg: "url":"/uploads/9a1848c5ebf2b83f8b055ac0e50e5232/fn.exe" # TODO: Download URL's are in the output vars above under "url". Eg: "url":"/uploads/9a1848c5ebf2b83f8b055ac0e50e5232/fn.exe"

View File

@@ -16,7 +16,7 @@ $fn test
someport=50080 someport=50080
docker rm --force functions || true # just in case docker rm --force functions || true # just in case
docker run --name functions -d -v /var/run/docker.sock:/var/run/docker.sock -p $someport:8080 funcy/functions docker run --name functions -d -v /var/run/docker.sock:/var/run/docker.sock -p $someport:8080 fnproject/functions
sleep 10 sleep 10
docker logs functions docker logs functions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 361 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 361 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -58,7 +58,7 @@ Note: Route level configuration overrides app level configuration.
Using `fn`: Using `fn`:
```sh ```sh
fn routes create myapp /path --config k1=v1 --config k2=v2 --image funcy/hello fn routes create myapp /path --config k1=v1 --config k2=v2 --image fnproject/hello
``` ```
Or using cURL: Or using cURL:
@@ -80,7 +80,7 @@ curl -H "Content-Type: application/json" -X POST -d '{
```json ```json
{ {
"path": "/hello", "path": "/hello",
"image": "funcy/hello", "image": "fnproject/hello",
"type": "sync", "type": "sync",
"memory": 128, "memory": 128,
"config": { "config": {

View File

@@ -10,7 +10,7 @@ The files can be named as:
An example of a function file: An example of a function file:
```yaml ```yaml
name: funcy/hello name: fnproject/hello
version: 0.0.1 version: 0.0.1
type: sync type: sync
memory: 128 memory: 128

View File

@@ -45,8 +45,8 @@ $ export FUNCTIONS=$(docker port functions | cut -d ' ' -f3)
$ curl -H "Content-Type: application/json" -X POST -d '{ "app": { "name":"myapp" } }' http://$FUNCTIONS/v1/apps $ curl -H "Content-Type: application/json" -X POST -d '{ "app": { "name":"myapp" } }' http://$FUNCTIONS/v1/apps
{"message":"App successfully created","app":{"name":"myapp","config":null}} {"message":"App successfully created","app":{"name":"myapp","config":null}}
$ curl -H "Content-Type: application/json" -X POST -d '{ "route": { "type": "sync", "path":"/hello-sync", "image":"funcy/hello" } }' http://$FUNCTIONS/v1/apps/myapp/routes $ curl -H "Content-Type: application/json" -X POST -d '{ "route": { "type": "sync", "path":"/hello-sync", "image":"fnproject/hello" } }' http://$FUNCTIONS/v1/apps/myapp/routes
{"message":"Route successfully created","route":{"app_name":"myapp","path":"/hello-sync","image":"funcy/hello","memory":128,"type":"sync","config":null}} {"message":"Route successfully created","route":{"app_name":"myapp","path":"/hello-sync","image":"fnproject/hello","memory":128,"type":"sync","config":null}}
$ curl -H "Content-Type: application/json" -X POST -d '{ "name":"Johnny" }' http://$FUNCTIONS/r/myapp/hello-sync $ curl -H "Content-Type: application/json" -X POST -d '{ "name":"Johnny" }' http://$FUNCTIONS/r/myapp/hello-sync
Hello Johnny! Hello Johnny!
@@ -125,8 +125,8 @@ $ export FUNCTIONS=$(docker port functions-lb | cut -d ' ' -f3)
$ curl -H "Content-Type: application/json" -X POST -d '{ "app": { "name":"myapp" } }' http://$FUNCTIONS/v1/apps $ curl -H "Content-Type: application/json" -X POST -d '{ "app": { "name":"myapp" } }' http://$FUNCTIONS/v1/apps
{"message":"App successfully created","app":{"name":"myapp","config":null}} {"message":"App successfully created","app":{"name":"myapp","config":null}}
$ curl -H "Content-Type: application/json" -X POST -d '{ "route": { "type": "sync", "path":"/hello-sync", "image":"funcy/hello" } }' http://$FUNCTIONS/v1/apps/myapp/routes $ curl -H "Content-Type: application/json" -X POST -d '{ "route": { "type": "sync", "path":"/hello-sync", "image":"fnproject/hello" } }' http://$FUNCTIONS/v1/apps/myapp/routes
{"message":"Route successfully created","route":{"app_name":"myapp","path":"/hello-sync","image":"funcy/hello","memory":128,"type":"sync","config":null}} {"message":"Route successfully created","route":{"app_name":"myapp","path":"/hello-sync","image":"fnproject/hello","memory":128,"type":"sync","config":null}}
$ curl -H "Content-Type: application/json" -X POST -d '{ "name":"Johnny" }' http://$FUNCTIONS/r/myapp/hello-sync $ curl -H "Content-Type: application/json" -X POST -d '{ "name":"Johnny" }' http://$FUNCTIONS/r/myapp/hello-sync
Hello Johnny! Hello Johnny!

View File

@@ -60,8 +60,8 @@ Now setup the functions:
$ curl -H "Content-Type: application/json" -X POST -d '{ "app": { "name":"myapp" } }' http://$FUNCTIONS/v1/apps $ curl -H "Content-Type: application/json" -X POST -d '{ "app": { "name":"myapp" } }' http://$FUNCTIONS/v1/apps
{"message":"App successfully created","app":{"name":"myapp","config":null}} {"message":"App successfully created","app":{"name":"myapp","config":null}}
$ curl -H "Content-Type: application/json" -X POST -d '{ "route": { "type": "sync", "path":"/hello-sync", "image":"funcy/hello" } }' http://$FUNCTIONS/v1/apps/myapp/routes $ curl -H "Content-Type: application/json" -X POST -d '{ "route": { "type": "sync", "path":"/hello-sync", "image":"fnproject/hello" } }' http://$FUNCTIONS/v1/apps/myapp/routes
{"message":"Route successfully created","route":{"app_name":"myapp","path":"/hello-sync","image":"funcy/hello","memory":128,"type":"sync","config":null}} {"message":"Route successfully created","route":{"app_name":"myapp","path":"/hello-sync","image":"fnproject/hello","memory":128,"type":"sync","config":null}}
$ curl -H "Content-Type: application/json" -X POST -d '{ "name":"Johnny" }' http://$FUNCTIONS/r/myapp/hello-sync $ curl -H "Content-Type: application/json" -X POST -d '{ "name":"Johnny" }' http://$FUNCTIONS/r/myapp/hello-sync
Hello Johnny! Hello Johnny!
@@ -113,8 +113,8 @@ $ export FUNCTIONS=$(kubectl get -o json svc functions | jq -r '.status.loadBala
$ curl -H "Content-Type: application/json" -X POST -d '{ "app": { "name":"myapp" } }' http://$FUNCTIONS/v1/apps $ curl -H "Content-Type: application/json" -X POST -d '{ "app": { "name":"myapp" } }' http://$FUNCTIONS/v1/apps
{"message":"App successfully created","app":{"name":"myapp","config":null}} {"message":"App successfully created","app":{"name":"myapp","config":null}}
$ curl -H "Content-Type: application/json" -X POST -d '{ "route": { "type": "sync", "path":"/hello-sync", "image":"funcy/hello" } }' http://$FUNCTIONS/v1/apps/myapp/routes $ curl -H "Content-Type: application/json" -X POST -d '{ "route": { "type": "sync", "path":"/hello-sync", "image":"fnproject/hello" } }' http://$FUNCTIONS/v1/apps/myapp/routes
{"message":"Route successfully created","route":{"app_name":"myapp","path":"/hello-sync","image":"funcy/hello","memory":128,"type":"sync","config":null}} {"message":"Route successfully created","route":{"app_name":"myapp","path":"/hello-sync","image":"fnproject/hello","memory":128,"type":"sync","config":null}}
$ curl -H "Content-Type: application/json" -X POST -d '{ "name":"Johnny" }' http://$FUNCTIONS/r/myapp/hello-sync $ curl -H "Content-Type: application/json" -X POST -d '{ "name":"Johnny" }' http://$FUNCTIONS/r/myapp/hello-sync
Hello Johnny! Hello Johnny!

View File

@@ -56,7 +56,7 @@ some container configuration values.
curl -H "Content-Type: application/json" -X POST -d '{ curl -H "Content-Type: application/json" -X POST -d '{
"route": { "route": {
"path":"/hello", "path":"/hello",
"image":"funcy/hello", "image":"fnproject/hello",
"memory": 100, "memory": 100,
"type": "sync", "type": "sync",
"config": {"APPLOG": "stderr"} "config": {"APPLOG": "stderr"}

View File

@@ -25,12 +25,12 @@ Now that we have an app, we can route endpoints to functions.
### Add a Route ### Add a Route
A route is a way to define a path in your application that maps to a function. In this example, we'll map A route is a way to define a path in your application that maps to a function. In this example, we'll map
`/hello` to a simple `Hello World!` function called `funcy/hello` which is a function we already made that you `/hello` to a simple `Hello World!` function called `fnproject/hello` which is a function we already made that you
can use -- yes, you can share functions! The source code for this function is in the [examples directory](examples/hello/go). can use -- yes, you can share functions! The source code for this function is in the [examples directory](examples/hello/go).
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 -i funcy/hello fn routes create myapp /hello -i fnproject/hello
``` ```
Or using cURL: Or using cURL:
@@ -39,7 +39,7 @@ Or using cURL:
curl -H "Content-Type: application/json" -X POST -d '{ curl -H "Content-Type: application/json" -X POST -d '{
"route": { "route": {
"path":"/hello", "path":"/hello",
"image":"funcy/hello" "image":"fnproject/hello"
} }
}' http://localhost:8080/v1/apps/myapp/routes }' http://localhost:8080/v1/apps/myapp/routes
``` ```
@@ -101,7 +101,7 @@ curl -H "Content-Type: application/json" -X POST -d '{
"route": { "route": {
"type": "async", "type": "async",
"path":"/hello-async", "path":"/hello-async",
"image":"funcy/hello" "image":"fnproject/hello"
} }
}' http://localhost:8080/v1/apps/myapp/routes }' http://localhost:8080/v1/apps/myapp/routes
``` ```

View File

@@ -16,7 +16,7 @@ A simple serverless blog API
USERNAME=YOUR_DOCKER_HUB_USERNAME USERNAME=YOUR_DOCKER_HUB_USERNAME
# build it # build it
docker run --rm -v "$PWD":/go/src/github.com/funcy/hello -w /go/src/github.com/funcy/hello funcy/go:dev go build -o function docker run --rm -v "$PWD":/go/src/github.com/fnproject/hello -w /go/src/github.com/fnproject/hello funcy/go:dev go build -o function
docker build -t $USERNAME/func-blog . docker build -t $USERNAME/func-blog .
``` ```

View File

@@ -1,4 +0,0 @@
#!/bin/bash
set -ex
docker build -t funcy/error .

View File

@@ -1,5 +0,0 @@
name: funcy/error
version: 0.0.2
runtime: ruby
entrypoint: ruby func.rb
path: /error

View File

@@ -1,2 +0,0 @@
name: username/sleeper
version: 0.0.3

View File

@@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
set -ex set -ex
user="funcy" user="fnproject"
service="fnlb" service="fnlb"
tag="latest" tag="latest"

View File

@@ -1 +1 @@
0.1.3 0.1.4

View File

@@ -1,3 +1,3 @@
set -ex set -ex
docker build --build-arg HTTP_PROXY -t funcy/dind:latest . docker build --build-arg HTTP_PROXY -t fnproject/dind:latest .

View File

@@ -6,7 +6,7 @@ docker run --rm -v "$PWD":/app treeder/bump patch
version=`cat VERSION` version=`cat VERSION`
echo "version $version" echo "version $version"
docker tag funcy/dind:latest funcy/dind:$version docker tag fnproject/dind:latest fnproject/dind:$version
docker push funcy/dind:latest docker push fnproject/dind:latest
docker push funcy/dind:$version docker push fnproject/dind:$version

View File

@@ -6,4 +6,4 @@ RUN bundle install
ADD . /function/ ADD . /function/
ENTRYPOINT ["ruby", "function.rb"] ENTRYPOINT ["ruby", "func.rb"]

4
images/error/build.sh Executable file
View File

@@ -0,0 +1,4 @@
#!/bin/bash
set -ex
docker build -t fnproject/error .

9
images/error/release.sh Executable file
View File

@@ -0,0 +1,9 @@
set -e
fn bump
fn build
fn push
docker build -t fnproject/error:latest .
docker push fnproject/error:latest

4
images/hello/release.sh Normal file → Executable file
View File

@@ -1,5 +1,5 @@
set -e set -e
docker build -t funcy/hello:latest . docker build -t fnproject/hello:latest .
docker push funcy/hello:latest docker push fnproject/hello:latest

View File

@@ -0,0 +1,9 @@
FROM funcy/ruby:dev
WORKDIR /function
ADD Gemfile* /function/
RUN bundle install
ADD . /function/
ENTRYPOINT ["ruby", "func.rb"]

2
images/sleeper/func.yaml Normal file
View File

@@ -0,0 +1,2 @@
name: fnproject/sleeper
version: 0.0.4

5
images/sleeper/release.sh Executable file
View File

@@ -0,0 +1,5 @@
set -e
docker build -t fnproject/sleeper:latest .
docker push fnproject/sleeper:latest

View File

@@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
set -ex set -ex
user="funcy" user="fnproject"
service="functions" service="functions"
tag="latest" tag="latest"

View File

@@ -3,6 +3,7 @@
set -ex set -ex
make build make build
make docker-build
docker rm -fv func-postgres-test || echo No prev test db container docker rm -fv func-postgres-test || echo No prev test db container
docker run --name func-postgres-test -p 15432:5432 -d postgres docker run --name func-postgres-test -p 15432:5432 -d postgres
@@ -39,6 +40,8 @@ esac
go test -v $(go list ./... | grep -v vendor | grep -v examples | grep -v tool | grep -v cli | grep -v tmp/go/src) go test -v $(go list ./... | grep -v vendor | grep -v examples | grep -v tool | grep -v cli | grep -v tmp/go/src)
# go test -v github.com/fnproject/fn/api/runner/drivers/docker # go test -v github.com/fnproject/fn/api/runner/drivers/docker
docker rm --force func-postgres-test
docker rm --force func-mysql-test
cd cli && make build && make test cd cli && make build && make test
# TODO: should we install fn here to use throughout? # TODO: should we install fn here to use throughout?

View File

@@ -52,7 +52,7 @@ func CallAsync(t *testing.T, u url.URL, content io.Reader) string {
func TestRouteExecutions(t *testing.T) { func TestRouteExecutions(t *testing.T) {
newRouteType := "async" newRouteType := "async"
t.Run("run-sync-funcy/hello-no-input", func(t *testing.T) { t.Run("run-sync-fnproject/hello-no-input", func(t *testing.T) {
t.Parallel() t.Parallel()
s := SetupDefaultSuite() s := SetupDefaultSuite()
CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{}) CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{})
@@ -79,7 +79,7 @@ func TestRouteExecutions(t *testing.T) {
DeleteApp(t, s.Context, s.Client, s.AppName) DeleteApp(t, s.Context, s.Client, s.AppName)
}) })
t.Run("run-sync-funcy/hello-with-input", func(t *testing.T) { t.Run("run-sync-fnproject/hello-with-input", func(t *testing.T) {
t.Parallel() t.Parallel()
s := SetupDefaultSuite() s := SetupDefaultSuite()
CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{}) CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{})
@@ -110,7 +110,7 @@ func TestRouteExecutions(t *testing.T) {
}) })
t.Run("run-async-funcy/hello", func(t *testing.T) { t.Run("run-async-fnproject/hello", func(t *testing.T) {
t.Parallel() t.Parallel()
s := SetupDefaultSuite() s := SetupDefaultSuite()
CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{}) CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{})
@@ -136,7 +136,7 @@ func TestRouteExecutions(t *testing.T) {
DeleteApp(t, s.Context, s.Client, s.AppName) DeleteApp(t, s.Context, s.Client, s.AppName)
}) })
t.Run("run-async-funcy/hello-with-status-check", func(t *testing.T) { t.Run("run-async-fnproject/hello-with-status-check", func(t *testing.T) {
t.Parallel() t.Parallel()
s := SetupDefaultSuite() s := SetupDefaultSuite()
CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{}) CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{})

View File

@@ -127,7 +127,7 @@ func SetupDefaultSuite() *SuiteSetup {
Client: APIClient(), Client: APIClient(),
AppName: "fnintegrationtestapp" + RandStringBytes(10), AppName: "fnintegrationtestapp" + RandStringBytes(10),
RoutePath: "/fnintegrationtestroute" + RandStringBytes(10), RoutePath: "/fnintegrationtestroute" + RandStringBytes(10),
Image: "funcy/hello", Image: "fnproject/hello",
Format: "default", Format: "default",
RouteType: "async", RouteType: "async",
RouteConfig: map[string]string{}, RouteConfig: map[string]string{},