diff --git a/api/datastore/sql/sql.go b/api/datastore/sql/sql.go index 660bf79db..f6fbd7e9d 100644 --- a/api/datastore/sql/sql.go +++ b/api/datastore/sql/sql.go @@ -13,6 +13,7 @@ import ( "strings" "github.com/Sirupsen/logrus" + "github.com/fnproject/fn/api/models" "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql" "github.com/jmoiron/sqlx" @@ -20,7 +21,6 @@ import ( _ "github.com/lib/pq" "github.com/mattn/go-sqlite3" _ "github.com/mattn/go-sqlite3" - "github.com/fnproject/fn/api/models" ) // this aims to be an ANSI-SQL compliant package that uses only question @@ -736,9 +736,12 @@ func buildFilterCallQuery(filter *models.CallFilter) (string, []interface{}) { } } - where("path=", filter.Path) where("app_name=", filter.AppName) + if filter.Path != "" { + where("path=", filter.Path) + } + return b.String(), args } diff --git a/api/server/call_list.go b/api/server/call_list.go index e151f58ff..120acc856 100644 --- a/api/server/call_list.go +++ b/api/server/call_list.go @@ -3,38 +3,22 @@ package server import ( "net/http" - "github.com/gin-gonic/gin" "github.com/fnproject/fn/api" "github.com/fnproject/fn/api/models" + "github.com/gin-gonic/gin" ) func (s *Server) handleCallList(c *gin.Context) { ctx := c.Request.Context() - appName, ok := c.MustGet(api.AppName).(string) - if ok && appName == "" { + name, ok := c.Get(api.AppName) + appName, conv := name.(string) + if ok && conv && appName == "" { handleErrorResponse(c, models.ErrRoutesValidationMissingAppName) return } - _, err := s.Datastore.GetApp(c, appName) - if err != nil { - handleErrorResponse(c, err) - return - } - - appRoute, ok := c.MustGet(api.Path).(string) - if ok && appRoute == "" { - handleErrorResponse(c, models.ErrRoutesValidationMissingPath) - return - } - _, err = s.Datastore.GetRoute(c, appName, appRoute) - if err != nil { - handleErrorResponse(c, err) - return - } - - filter := models.CallFilter{AppName: appName, Path: appRoute} + filter := models.CallFilter{AppName: appName, Path: c.Query(api.CRoute)} calls, err := s.Datastore.GetTasks(ctx, &filter) if err != nil { @@ -42,5 +26,21 @@ func (s *Server) handleCallList(c *gin.Context) { return } + if len(calls) == 0 { + _, err = s.Datastore.GetApp(c, appName) + if err != nil { + handleErrorResponse(c, err) + return + } + + if filter.Path != "" { + _, err = s.Datastore.GetRoute(c, appName, filter.Path) + if err != nil { + handleErrorResponse(c, err) + return + } + } + } + c.JSON(http.StatusOK, fnCallsResponse{"Successfully listed calls", calls}) } diff --git a/api/server/server.go b/api/server/server.go index 7bf693e1f..e5c5dadd8 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -14,12 +14,6 @@ import ( "github.com/Sirupsen/logrus" "github.com/ccirello/supervisor" - "github.com/gin-gonic/gin" - "github.com/opentracing/opentracing-go" - "github.com/opentracing/opentracing-go/ext" - "github.com/openzipkin/zipkin-go-opentracing" - "github.com/patrickmn/go-cache" - "github.com/spf13/viper" "github.com/fnproject/fn/api" "github.com/fnproject/fn/api/datastore" "github.com/fnproject/fn/api/id" @@ -28,6 +22,12 @@ import ( "github.com/fnproject/fn/api/mqs" "github.com/fnproject/fn/api/runner" "github.com/fnproject/fn/api/runner/common" + "github.com/gin-gonic/gin" + "github.com/opentracing/opentracing-go" + "github.com/opentracing/opentracing-go/ext" + "github.com/openzipkin/zipkin-go-opentracing" + "github.com/patrickmn/go-cache" + "github.com/spf13/viper" ) const ( @@ -350,12 +350,6 @@ func (s *Server) bindHandlers(ctx context.Context) { v1.PATCH("/apps/:app", s.handleAppUpdate) v1.DELETE("/apps/:app", s.handleAppDelete) - v1.GET("/routes", s.handleRouteList) - - v1.GET("/calls/:call", s.handleCallGet) - v1.GET("/calls/:call/log", s.handleCallLogGet) - v1.DELETE("/calls/:call/log", s.handleCallLogDelete) - apps := v1.Group("/apps/:app") { apps.GET("/routes", s.handleRouteList) @@ -364,7 +358,13 @@ func (s *Server) bindHandlers(ctx context.Context) { apps.PATCH("/routes/*route", s.handleRouteCreateOrUpdate) apps.PUT("/routes/*route", s.handleRouteCreateOrUpdate) apps.DELETE("/routes/*route", s.handleRouteDelete) - apps.GET("/calls/*route", s.handleCallList) + + apps.GET("/calls", s.handleCallList) + + apps.GET("/calls/:call", s.handleCallGet) + apps.GET("/calls/:call/log", s.handleCallLogGet) + apps.DELETE("/calls/:call/log", s.handleCallLogDelete) + } } diff --git a/cli/calls.go b/cli/calls.go index e9cd2b64d..9cbdfe57c 100644 --- a/cli/calls.go +++ b/cli/calls.go @@ -4,11 +4,11 @@ import ( "context" "fmt" + client "github.com/fnproject/fn/cli/client" fnclient "github.com/funcy/functions_go/client" apicall "github.com/funcy/functions_go/client/call" "github.com/funcy/functions_go/models" "github.com/urfave/cli" - client "github.com/fnproject/fn/cli/client" ) type callsCmd struct { @@ -20,20 +20,20 @@ func calls() cli.Command { return cli.Command{ Name: "calls", - Usage: "manage function calls", + Usage: "manage function calls for apps", Subcommands: []cli.Command{ { Name: "get", Aliases: []string{"g"}, - Usage: "get function call info", - ArgsUsage: "", + Usage: "get function call info per app", + ArgsUsage: " ", Action: c.get, }, { Name: "list", Aliases: []string{"l"}, - Usage: "list all calls for specific route", - ArgsUsage: " ", + Usage: "list all calls for specific app / route route is optional", + ArgsUsage: " [route]", Action: c.list, }, }, @@ -56,16 +56,17 @@ func printCalls(calls []*models.Call) { } func (call *callsCmd) get(ctx *cli.Context) error { - callID := ctx.Args().Get(0) - params := apicall.GetCallsCallParams{ + app, callID := ctx.Args().Get(0), ctx.Args().Get(1) + params := apicall.GetAppsAppCallsCallParams{ Call: callID, + App: app, Context: context.Background(), } - resp, err := call.client.Call.GetCallsCall(¶ms) + resp, err := call.client.Call.GetAppsAppCallsCall(¶ms) if err != nil { switch err.(type) { - case *apicall.GetCallsCallNotFound: - return fmt.Errorf("error: %v", err.(*apicall.GetCallsCallNotFound).Payload.Error.Message) + case *apicall.GetAppsAppCallsCallNotFound: + return fmt.Errorf("error: %v", err.(*apicall.GetAppsAppCallsCallNotFound).Payload.Error.Message) } return fmt.Errorf("unexpected error: %v", err) @@ -75,13 +76,16 @@ func (call *callsCmd) get(ctx *cli.Context) error { } func (call *callsCmd) list(ctx *cli.Context) error { - app, route := ctx.Args().Get(0), ctx.Args().Get(1) - params := apicall.GetAppsAppCallsRouteParams{ + app := ctx.Args().Get(0) + params := apicall.GetAppsAppCallsParams{ App: app, - Route: route, Context: context.Background(), } - resp, err := call.client.Call.GetAppsAppCallsRoute(¶ms) + if ctx.Args().Get(1) != "" { + route := ctx.Args().Get(1) + params.Route = &route + } + resp, err := call.client.Call.GetAppsAppCalls(¶ms) if err != nil { switch err.(type) { case *apicall.GetCallsCallNotFound: diff --git a/cli/glide.yaml b/cli/glide.yaml index 91b3ac7b2..a57c13dbd 100644 --- a/cli/glide.yaml +++ b/cli/glide.yaml @@ -18,7 +18,7 @@ import: subpackages: - semver - package: github.com/funcy/functions_go - version: ^0.1.34 + version: ^0.1.35 subpackages: - client - client/apps diff --git a/docs/swagger.yml b/docs/swagger.yml index 9e914d53c..84a24f4a0 100644 --- a/docs/swagger.yml +++ b/docs/swagger.yml @@ -6,7 +6,7 @@ swagger: '2.0' info: title: Oracle Functions description: The open source serverless platform. - version: "0.1.34" + version: "0.1.35" # the domain of the service host: "127.0.0.1:8080" # array of all schemes that your API supports @@ -352,7 +352,7 @@ paths: schema: $ref: '#/definitions/Error' - /calls/{call}/log: + /apps/{app}/calls/{call}/log: get: summary: Get call logs description: Get call logs @@ -360,6 +360,11 @@ paths: - Call - Log parameters: + - name: app + description: App Name + required: true + type: string + in: path - name: call description: Call ID. required: true @@ -386,6 +391,11 @@ paths: required: true type: string in: path + - name: app + description: App name. + required: true + type: string + in: path responses: 202: description: Log delete request accepted @@ -398,13 +408,18 @@ paths: schema: $ref: '#/definitions/Error' - /calls/{call}: + /apps/{app}/calls/{call}: get: summary: Get call information description: Get call information tags: - Call parameters: + - name: app + description: app name + required: true + type: string + in: path - name: call description: Call ID. required: true @@ -420,10 +435,10 @@ paths: schema: $ref: '#/definitions/Error' - /apps/{app}/calls/{route}: + /apps/{app}/calls/: get: - summary: Get route-bound calls. - description: Get route-bound calls. + summary: Get app-bound calls. + description: Get app-bound calls can filter to route-bound calls. tags: - Call parameters: @@ -434,9 +449,9 @@ paths: in: path - name: route description: App route. - required: true + required: false type: string - in: path + in: query responses: 200: description: Calls found diff --git a/glide.yaml b/glide.yaml index c7a2e957c..438f13464 100644 --- a/glide.yaml +++ b/glide.yaml @@ -4,6 +4,7 @@ excludeDirs: import: - package: code.cloudfoundry.org/bytefmt - package: github.com/funcy/functions_go + version: ^0.1.35 subpackages: - models - package: github.com/Sirupsen/logrus @@ -28,7 +29,7 @@ import: subpackages: - cli/config/configfile - package: github.com/docker/distribution - branch: master + branch: master - package: github.com/fsouza/go-dockerclient - package: github.com/garyburd/redigo subpackages: diff --git a/test/fn-api-tests/calls_test.go b/test/fn-api-tests/calls_test.go index 043524d37..febdac0e3 100644 --- a/test/fn-api-tests/calls_test.go +++ b/test/fn-api-tests/calls_test.go @@ -15,12 +15,12 @@ func TestCalls(t *testing.T) { t.Run("list-calls-for-missing-app", func(t *testing.T) { t.Parallel() s := SetupDefaultSuite() - cfg := &call.GetAppsAppCallsRouteParams{ + cfg := &call.GetAppsAppCallsParams{ App: s.AppName, - Route: s.RoutePath, + Route: &s.RoutePath, Context: s.Context, } - _, err := s.Client.Call.GetAppsAppCallsRoute(cfg) + _, err := s.Client.Call.GetAppsAppCalls(cfg) if err == nil { t.Errorf("Must fail with missing app error, but got %s", err) } @@ -31,12 +31,12 @@ func TestCalls(t *testing.T) { s := SetupDefaultSuite() CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{}) - cfg := &call.GetAppsAppCallsRouteParams{ + cfg := &call.GetAppsAppCallsParams{ App: s.AppName, - Route: s.RoutePath, + Route: &s.RoutePath, Context: s.Context, } - _, err := s.Client.Call.GetAppsAppCallsRoute(cfg) + _, err := s.Client.Call.GetAppsAppCalls(cfg) if err == nil { t.Errorf("Must fail with missing route error, but got %s", err) } @@ -51,12 +51,13 @@ func TestCalls(t *testing.T) { CreateRoute(t, s.Context, s.Client, s.AppName, s.RoutePath, s.Image, s.RouteType, s.RouteConfig, s.RouteHeaders) - cfg := &call.GetCallsCallParams{ + cfg := &call.GetAppsAppCallsCallParams{ Call: "dummy", + App: s.AppName, Context: s.Context, } cfg.WithTimeout(time.Second * 60) - _, err := s.Client.Call.GetCallsCall(cfg) + _, err := s.Client.Call.GetAppsAppCallsCall(cfg) if err == nil { t.Error("Must fail because `dummy` call does not exist.") } @@ -85,7 +86,10 @@ func TestCalls(t *testing.T) { Context: s.Context, } cfg.WithTimeout(time.Second * 60) - _, err := s.Client.Call.GetCallsCall(cfg) + _, err := s.Client.Call.GetAppsAppCalls(&call.GetAppsAppCallsParams{ + App: s.AppName, + Route: &s.RoutePath, + }) if err != nil { switch err.(type) { case *call.GetCallsCallNotFound: @@ -113,17 +117,18 @@ func TestCalls(t *testing.T) { CallAsync(t, u, &bytes.Buffer{}) time.Sleep(time.Second * 8) - cfg := &call.GetAppsAppCallsRouteParams{ + cfg := &call.GetAppsAppCallsParams{ App: s.AppName, - Route: s.RoutePath, + Route: &s.RoutePath, Context: s.Context, } - calls, err := s.Client.Call.GetAppsAppCallsRoute(cfg) + calls, err := s.Client.Call.GetAppsAppCalls(cfg) if err != nil { t.Errorf("Unexpected error: %s", err) } - if len(calls.Payload.Calls) == 0 { + if calls == nil || calls.Payload == nil || calls.Payload.Calls == nil || len(calls.Payload.Calls) == 0 { t.Errorf("Must fail. There should be at least one call to `%v` route.", s.RoutePath) + return } for _, c := range calls.Payload.Calls { if c.Path != s.RoutePath { diff --git a/test/fn-api-tests/exec_test.go b/test/fn-api-tests/exec_test.go index 766efcc9d..edd9a9031 100644 --- a/test/fn-api-tests/exec_test.go +++ b/test/fn-api-tests/exec_test.go @@ -159,12 +159,13 @@ func TestRouteExecutions(t *testing.T) { callID := CallAsync(t, u, &bytes.Buffer{}) time.Sleep(time.Second * 10) - cfg := &call.GetCallsCallParams{ + cfg := &call.GetAppsAppCallsCallParams{ Call: callID, + App: s.AppName, Context: s.Context, } cfg.WithTimeout(time.Second * 60) - callResponse, err := s.Client.Call.GetCallsCall(cfg) + callResponse, err := s.Client.Call.GetAppsAppCallsCall(cfg) if err != nil { switch err.(type) { case *call.GetCallsCallNotFound: @@ -224,12 +225,13 @@ func TestRouteExecutions(t *testing.T) { json.NewDecoder(output).Decode(tB) - cfg := &call.GetCallsCallParams{ + cfg := &call.GetAppsAppCallsCallParams{ Call: tB.CallID, + App: s.AppName, Context: s.Context, } cfg.WithTimeout(time.Second * 60) - callObj, err := s.Client.Call.GetCallsCall(cfg) + callObj, err := s.Client.Call.GetAppsAppCallsCall(cfg) if err != nil { t.Errorf("Unexpected error: %s", err) } @@ -262,12 +264,13 @@ func TestRouteExecutions(t *testing.T) { callID := CallAsync(t, u, &bytes.Buffer{}) time.Sleep(15 * time.Second) - cfg := &operations.GetCallsCallLogParams{ + cfg := &operations.GetAppsAppCallsCallLogParams{ Call: callID, + App: s.AppName, Context: s.Context, } - logObj, err := s.Client.Operations.GetCallsCallLog(cfg) + logObj, err := s.Client.Operations.GetAppsAppCallsCallLog(cfg) if err != nil { t.Errorf("Unexpected error: %s", err) } @@ -312,7 +315,7 @@ func TestRouteExecutions(t *testing.T) { res := output.String() if !strings.Contains("application/xml, application/json; q=0.2", res) { t.Errorf("HEADER_ACCEPT='application/xml, application/json; q=0.2' "+ - "should be in output, have:\n%", res) + "should be in output, have:%s\n", res) } DeleteRoute(t, s.Context, s.Client, s.AppName, routePath) DeleteApp(t, s.Context, s.Client, s.AppName) @@ -342,12 +345,13 @@ func TestRouteExecutions(t *testing.T) { callID := CallAsync(t, u, content) time.Sleep(10 * time.Second) - cfg := &operations.GetCallsCallLogParams{ + cfg := &operations.GetAppsAppCallsCallLogParams{ Call: callID, + App: s.AppName, Context: s.Context, } - _, err := s.Client.Operations.GetCallsCallLog(cfg) + _, err := s.Client.Operations.GetAppsAppCallsCallLog(cfg) if err != nil { t.Errorf("Unexpected error: %s", err) @@ -359,7 +363,7 @@ func TestRouteExecutions(t *testing.T) { t.Run("exec-oversized-log-test", func(t *testing.T) { t.Parallel() - t.Skip("Skipped until fix for https://github.com/fnproject/fn/issues/86.") + t.Skip("Skipped until fix for https://gitlab-odx.oracle.com/odx/functions/issues/86.") s := SetupDefaultSuite() routePath := "/log" @@ -384,12 +388,13 @@ func TestRouteExecutions(t *testing.T) { callID := CallAsync(t, u, content) time.Sleep(5 * time.Second) - cfg := &operations.GetCallsCallLogParams{ + cfg := &operations.GetAppsAppCallsCallLogParams{ Call: callID, + App: s.AppName, Context: s.Context, } - logObj, err := s.Client.Operations.GetCallsCallLog(cfg) + logObj, err := s.Client.Operations.GetAppsAppCallsCallLog(cfg) if err != nil { t.Errorf("Unexpected error: %s", err) }