diff --git a/README.md b/README.md index 9d8678df5..05af69a93 100644 --- a/README.md +++ b/README.md @@ -23,12 +23,10 @@ curl -H "Content-Type: application/json" -X POST -d '{ }' http://localhost:8080/v1/apps ``` -Now that we have an app, we can add routes to functions. +Now that we have an app, we can map routes to functions. ### Add a route to a Function - - ```sh curl -H "Content-Type: application/json" -X POST -d '{ "route": { @@ -70,6 +68,10 @@ And you'll get an ironfunctions.com host for your app: myapp.USER_ID.ironfunctions.com/hello ``` +## API Reference + +https://swaggerhub.com/api/iron/functions + ## Full Documentation http://docs-new.iron.io/docs diff --git a/api/runner/logger.go b/api/runner/logger.go new file mode 100644 index 000000000..ad8042de4 --- /dev/null +++ b/api/runner/logger.go @@ -0,0 +1,37 @@ +package runner + +import ( + "bufio" + "io" + + "github.com/Sirupsen/logrus" +) + +// FuncLogger reads STDERR output from a container and outputs it in a parseable structured log format, see: https://github.com/iron-io/functions/issues/76 +type FuncLogger struct { + r io.Reader + w io.Writer +} + +func NewFuncLogger(appName, path, function, requestID string) io.Writer { + r, w := io.Pipe() + funcLogger := &FuncLogger{ + r: r, + w: w, + } + log := logrus.WithFields(logrus.Fields{"user_log": true, "app_name": appName, "path": path, "function": function, "request_id": requestID}) + go func(reader io.Reader) { + scanner := bufio.NewScanner(reader) + for scanner.Scan() { + log.Println(scanner.Text()) + } + if err := scanner.Err(); err != nil { + log.WithError(err).Println("There was an error with the scanner in attached container") + } + }(r) + return funcLogger +} + +func (l *FuncLogger) Write(p []byte) (n int, err error) { + return l.w.Write(p) +} diff --git a/api/server/apps_create.go b/api/server/apps_create.go index ffbbbac91..3577b0b8e 100644 --- a/api/server/apps_create.go +++ b/api/server/apps_create.go @@ -56,5 +56,5 @@ func handleAppCreate(c *gin.Context) { return } - c.JSON(http.StatusCreated, appResponse{"App successfully created", wapp}) + c.JSON(http.StatusCreated, appResponse{"App successfully created", wapp.App}) } diff --git a/api/server/apps_get.go b/api/server/apps_get.go index 23514f07a..f4cc59c89 100644 --- a/api/server/apps_get.go +++ b/api/server/apps_get.go @@ -29,5 +29,5 @@ func handleAppGet(c *gin.Context) { return } - c.JSON(http.StatusOK, &models.AppWrapper{app}) + c.JSON(http.StatusOK, appResponse{"Successfully loaded app", app}) } diff --git a/api/server/apps_list.go b/api/server/apps_list.go index ad74a7f5a..acce3cb10 100644 --- a/api/server/apps_list.go +++ b/api/server/apps_list.go @@ -23,5 +23,5 @@ func handleAppList(c *gin.Context) { return } - c.JSON(http.StatusOK, &models.AppsWrapper{apps}) + c.JSON(http.StatusOK, appsResponse{"Successfully listed applications", apps}) } diff --git a/api/server/apps_update.go b/api/server/apps_update.go index 22192321a..a805ab2d2 100644 --- a/api/server/apps_update.go +++ b/api/server/apps_update.go @@ -39,5 +39,5 @@ func handleAppUpdate(c *gin.Context) { wapp.App = app // Nothing to update right now in apps - c.JSON(http.StatusOK, appResponse{"App successfully updated", wapp}) + c.JSON(http.StatusOK, appResponse{"App successfully updated", wapp.App}) } diff --git a/api/server/helpers.go b/api/server/helpers.go index be4facbda..561c6f9a1 100644 --- a/api/server/helpers.go +++ b/api/server/helpers.go @@ -17,23 +17,23 @@ import ( ) type appResponse struct { - Message string - App models.AppWrapper + Message string `json:"message"` + App *models.App `json:"app"` } type appsResponse struct { - Message string - Apps models.AppsWrapper + Message string `json:"message"` + Apps models.Apps `json:"apps"` } type routeResponse struct { - Message string - Route models.RouteWrapper + Message string `json:"message"` + Route *models.Route `json:"route"` } type routesResponse struct { - Message string - Routes models.RoutesWrapper + Message string `json:"message"` + Routes models.Routes `json:"routes"` } func testRouter() *gin.Engine { diff --git a/api/server/routes_create.go b/api/server/routes_create.go index f5051725d..eab0f8e31 100644 --- a/api/server/routes_create.go +++ b/api/server/routes_create.go @@ -75,5 +75,5 @@ func handleRouteCreate(c *gin.Context) { return } - c.JSON(http.StatusCreated, routeResponse{"Route successfully created", wroute}) + c.JSON(http.StatusCreated, routeResponse{"Route successfully created", wroute.Route}) } diff --git a/api/server/routes_get.go b/api/server/routes_get.go index 9273a6531..83255a246 100644 --- a/api/server/routes_get.go +++ b/api/server/routes_get.go @@ -33,5 +33,5 @@ func handleRouteGet(c *gin.Context) { log.WithFields(logrus.Fields{"route": route}).Debug("Got route") - c.JSON(http.StatusOK, &models.RouteWrapper{route}) + c.JSON(http.StatusOK, routeResponse{"Successfully loaded route", route}) } diff --git a/api/server/routes_list.go b/api/server/routes_list.go index 5837f49f2..c5aa4d128 100644 --- a/api/server/routes_list.go +++ b/api/server/routes_list.go @@ -37,5 +37,5 @@ func handleRouteList(c *gin.Context) { log.WithFields(logrus.Fields{"routes": routes}).Debug("Got routes") - c.JSON(http.StatusOK, &models.RoutesWrapper{Routes: routes}) + c.JSON(http.StatusOK, routesResponse{"Sucessfully listed routes", routes}) } diff --git a/api/server/routes_update.go b/api/server/routes_update.go index 5424e952e..cd61c2dcd 100644 --- a/api/server/routes_update.go +++ b/api/server/routes_update.go @@ -45,5 +45,5 @@ func handleRouteUpdate(c *gin.Context) { return } - c.JSON(http.StatusOK, routeResponse{"Route successfully updated", wroute}) + c.JSON(http.StatusOK, routeResponse{"Route successfully updated", wroute.Route}) } diff --git a/api/server/runner.go b/api/server/runner.go index 7e02fc468..3295ea0d3 100644 --- a/api/server/runner.go +++ b/api/server/runner.go @@ -106,7 +106,9 @@ func handleRunner(c *gin.Context) { log.WithField("routes", routes).Debug("Got routes from datastore") for _, el := range routes { if params, match := matchRoute(el.Path, route); match { - var stdout, stderr bytes.Buffer + + var stdout bytes.Buffer // TODO: should limit the size of this, error if gets too big. akin to: https://golang.org/pkg/io/#LimitReader + stderr := runner.NewFuncLogger(appName, route, el.Image, reqID) envVars := map[string]string{ "METHOD": c.Request.Method, @@ -130,13 +132,18 @@ func handleRunner(c *gin.Context) { envVars["PARAM_"+strings.ToUpper(param.Key)] = param.Value } + // headers + for header, value := range c.Request.Header { + envVars["HEADER_"+strings.ToUpper(header)] = strings.Join(value, " ") + } + cfg := &runner.Config{ Image: el.Image, Timeout: 30 * time.Second, ID: reqID, AppName: appName, Stdout: &stdout, - Stderr: &stderr, + Stderr: stderr, Env: envVars, } @@ -151,7 +158,7 @@ func handleRunner(c *gin.Context) { if result.Status() == "success" { c.Data(http.StatusOK, "", stdout.Bytes()) } else { - log.WithFields(logrus.Fields{"app": appName, "route": el, "req_id": reqID}).Debug(stderr.String()) + // log.WithFields(logrus.Fields{"app": appName, "route": el, "req_id": reqID}).Debug(stderr.String()) c.AbortWithStatus(http.StatusInternalServerError) } } diff --git a/api/server/version.go b/api/server/version.go index da1f285d8..53b9eea44 100644 --- a/api/server/version.go +++ b/api/server/version.go @@ -7,7 +7,7 @@ import ( ) // Version of IronFunctions -var Version = "0.0.2" +var Version = "0.0.32" func handleVersion(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"version": Version}) diff --git a/examples/hello/hello.rb b/examples/hello/hello.rb index 71ec89bba..f171f4b03 100644 --- a/examples/hello/hello.rb +++ b/examples/hello/hello.rb @@ -6,7 +6,7 @@ name = "World" # or using env vars: ENV['PAYLOAD'] payload = ENV['PAYLOAD'] -puts 'ARGF: ' + payload.inspect +STDERR.puts 'payload: ' + payload.inspect if payload != "" payload = JSON.parse(payload) name = payload['name'] diff --git a/glide.lock b/glide.lock index f4e7f8618..48c05c951 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ hash: 5ccf89905e13b7dc987cd203c1d7c1fddd32dcd776fe2e5f60d9f6f7b9908425 -updated: 2016-08-24T14:50:27.724858484-03:00 +updated: 2016-08-30T10:32:52.850687756-07:00 imports: - name: github.com/amir/raidman version: c74861fe6a7bb8ede0a010ce4485bdbb4fc4c985 @@ -13,10 +13,6 @@ imports: version: 1c27c506c7a0584d017ca479f91b88d6a6538332 subpackages: - statsd -- name: github.com/dgrijalva/jwt-go - version: 63734eae1ef55eaac06fdc0f312615f2e321e273 - subpackages: - - request - name: github.com/docker/distribution version: 9ca7921603852314b18a6ecc19f91806935f34bd subpackages: @@ -29,23 +25,22 @@ imports: - pkg/archive - pkg/fileutils - pkg/homedir - - pkg/stdcopy - - pkg/idtools - pkg/ioutils + - pkg/parsers - pkg/pools - pkg/promise - - pkg/system - - pkg/longpath - pkg/random - - pkg/units + - pkg/stdcopy + - pkg/system - pkg/tarsum + - pkg/ulimit + - pkg/units + - volume - name: github.com/docker/engine-api version: 2f8c367944a28130f3c2fb9f0aad7f1d5db952a9 subpackages: - - types/swarm - - types/filters - types/mount - - types/versions + - types/swarm - name: github.com/docker/go-units version: eb879ae3e2b84e2a142af415b679ddeda47ec71c - name: github.com/docker/libtrust @@ -57,8 +52,8 @@ imports: - name: github.com/garyburd/redigo version: 4ed1111375cbeb698249ffe48dd463e9b0a63a7a subpackages: - - redis - internal + - redis - name: github.com/gin-gonic/gin version: 4a6bc4aac4607e253bcda67c8c5bcda693d2388e subpackages: @@ -97,10 +92,10 @@ imports: subpackages: - hcl/ast - hcl/parser - - hcl/token - - json/parser - hcl/scanner - hcl/strconv + - hcl/token + - json/parser - json/scanner - json/token - name: github.com/heroku/docker-registry-client @@ -108,21 +103,21 @@ imports: subpackages: - registry - name: github.com/iron-io/titan - version: 58d1565025aa045bdf47b44e0eb81a52c70f7958 + version: 3bb6aacb244a24e38bba755cc863533810117a5c repo: https://github.com/iron-io/titan.git vcs: git subpackages: - common + - common/stats - runner/agent - runner/drivers - runner/drivers/docker - runner/drivers/mock - runner/tasker - - common/stats - runner/tasker/client/models - runner/tasker/client/titan - - runner/tasker/client/titan/jobs - runner/tasker/client/titan/groups + - runner/tasker/client/titan/jobs - runner/tasker/client/titan/runner - name: github.com/kr/fs version: 2788f0dbd16903de03cb8186e5c7d97b69ad387b @@ -135,9 +130,9 @@ imports: - name: github.com/mailru/easyjson version: 34560e358dc05e2c28f6fda2f5c9e7494a4b9b19 subpackages: + - buffer - jlexer - jwriter - - buffer - name: github.com/manucorporat/sse version: ee05b128a739a0fb76c7ebd3ae4810c1de808d6d - name: github.com/mitchellh/mapstructure @@ -145,7 +140,6 @@ imports: - name: github.com/opencontainers/runc version: 46d9535096662d8d6a734e4fdfc1c27ab03bc328 subpackages: - - libcontainer/system - libcontainer/user - name: github.com/pelletier/go-buffruneio version: df1e16fde7fc330a0ca68167c23bf7ed6ac31d6d @@ -181,20 +175,19 @@ imports: - name: github.com/spf13/viper version: 7fb2782df3d83e0036cc89f461ed0422628776f4 - name: golang.org/x/crypto - version: c10c31b5e94b6f7a0283272dc2bb27163dcea24b + version: b13fc1fd382d01861b16b2e6474487d3d4d27f20 subpackages: - - bcrypt - - blowfish - - ssh - curve25519 - ed25519 + - ed25519/internal/edwards25519 + - ssh - name: golang.org/x/net version: f315505cf3349909cdf013ea56690da34e96a451 subpackages: - context - context/ctxhttp - - proxy - idna + - proxy - name: golang.org/x/sys version: a646d33e2ee3172a661fc09bca23bb4889a41bc8 subpackages: @@ -202,25 +195,18 @@ imports: - name: golang.org/x/text version: d69c40b4be55797923cec7457fac7a244d91a9b6 subpackages: - - transform - - unicode/norm - - secure/precis - cases + - internal/tag + - language - runes - secure/bidirule - - width - - language + - secure/precis + - transform - unicode/bidi - - internal/tag + - unicode/norm + - width - name: gopkg.in/go-playground/validator.v8 version: c193cecd124b5cc722d7ee5538e945bdb3348435 -- name: gopkg.in/mgo.v2 - version: 3f83fa5005286a7fe593b055f0d7771a7dce4655 - subpackages: - - bson - - internal/sasl - - internal/scram - - internal/json - name: gopkg.in/yaml.v2 version: e4d366fc3c7938e2958e662b4258c7a89e1f0e3e testImports: []