From d336035678c4004e3464a31abf5331efc6bdb2a8 Mon Sep 17 00:00:00 2001 From: James Jeffrey Date: Tue, 21 Aug 2018 02:26:36 -0700 Subject: [PATCH] Add annotation to trigger on create if endpoints are enabled (#1177) * Add annotations for creation of triggers and fns along with the test for them fixes #1178 * Log errors and still return created resource for annotation failures --- api/server/fns_create.go | 19 ++++++++++++++- api/server/fns_test.go | 47 +++++++++++++++++++++++++++--------- api/server/trigger_create.go | 19 ++++++++++++++- api/server/trigger_test.go | 37 ++++++++++++++++++++++------ 4 files changed, 101 insertions(+), 21 deletions(-) diff --git a/api/server/fns_create.go b/api/server/fns_create.go index 3cc1ca861..ddaa063ce 100644 --- a/api/server/fns_create.go +++ b/api/server/fns_create.go @@ -3,12 +3,14 @@ package server import ( "net/http" + "github.com/fnproject/fn/api/common" "github.com/fnproject/fn/api/models" "github.com/gin-gonic/gin" ) func (s *Server) handleFnCreate(c *gin.Context) { ctx := c.Request.Context() + log := common.Logger(ctx) fn := &models.Fn{} err := c.BindJSON(fn) @@ -24,7 +26,22 @@ func (s *Server) handleFnCreate(c *gin.Context) { fnCreated, err := s.datastore.InsertFn(ctx, fn) if err != nil { handleErrorResponse(c, err) + return } - c.JSON(http.StatusOK, fnCreated) + app, err := s.datastore.GetAppByID(ctx, fnCreated.AppID) + if err != nil { + log.Debugln("Failed to lookup app.") + c.JSON(http.StatusOK, fnCreated) + return + } + + fnAnnotated, err := s.fnAnnotator.AnnotateFn(c, app, fnCreated) + if err != nil { + log.Debugln("Failed to annotate fn") + c.JSON(http.StatusOK, fnCreated) + return + } + + c.JSON(http.StatusOK, fnAnnotated) } diff --git a/api/server/fns_test.go b/api/server/fns_test.go index e1dd76e3e..5a5ac2591 100644 --- a/api/server/fns_test.go +++ b/api/server/fns_test.go @@ -361,29 +361,52 @@ func TestFnGet(t *testing.T) { func TestFnInvokeEndpointAnnotations(t *testing.T) { a := &models.App{ID: "app_id", Name: "myapp"} - fn := &models.Fn{ID: "fnid", AppID: a.ID, Name: "fnname"} + fn := &models.Fn{AppID: a.ID, Name: "fnname", Image: "fnproject/image"} - commonDS := datastore.NewMockInit([]*models.App{a}, []*models.Fn{fn}) + commonDS := datastore.NewMockInit([]*models.App{a}) srv := testServer(commonDS, &mqs.Mock{}, logs.NewMock(), nil, ServerTypeAPI) - - _, rec := routerRequest(t, srv.Router, "GET", "/v2/fns/fnid", bytes.NewBuffer([]byte(""))) - - if rec.Code != http.StatusOK { - t.Fatalf("expected code %d != 200", rec.Code) + body, err := json.Marshal(fn) + if err != nil { + t.Fatalf("Failed to marshal json to create fn %s", err) } - var fnGet models.Fn - err := json.NewDecoder(rec.Body).Decode(&fnGet) + + _, createFN := routerRequest(t, srv.Router, "POST", "/v2/fns", bytes.NewReader(body)) + if createFN.Code != http.StatusOK { + t.Fatalf("expected code %d != 200 %s", createFN.Code, createFN.Body.String()) + } + + var fnCreate models.Fn + err = json.NewDecoder(createFN.Body).Decode(&fnCreate) if err != nil { t.Fatalf("Invalid json from server %s", err) } const fnEndpoint = "fnproject.io/fn/invokeEndpoint" - v, err := fnGet.Annotations.GetString(fnEndpoint) + v, err := fnCreate.Annotations.GetString(fnEndpoint) + if err != nil { + t.Errorf("failed to get fn %s", err) + } + if v != "http://127.0.0.1:8080/invoke/"+fnCreate.ID { + t.Errorf("unexpected fn val %s", v) + } + + _, rec := routerRequest(t, srv.Router, "GET", "/v2/fns/"+fnCreate.ID, bytes.NewBuffer([]byte(""))) + + if rec.Code != http.StatusOK { + t.Fatalf("expected code %d != 200", rec.Code) + } + var fnGet models.Fn + err = json.NewDecoder(rec.Body).Decode(&fnGet) + if err != nil { + t.Fatalf("Invalid json from server %s", err) + } + + v, err = fnGet.Annotations.GetString(fnEndpoint) if err != nil { t.Fatalf("failed to get fn %s", err) } - if v != "http://127.0.0.1:8080/invoke/fnid" { + if v != "http://127.0.0.1:8080/invoke/"+fnCreate.ID { t.Errorf("unexpected fn val %s", v) } @@ -404,7 +427,7 @@ func TestFnInvokeEndpointAnnotations(t *testing.T) { } v, err = resp.Items[0].Annotations.GetString(fnEndpoint) - if v != "http://127.0.0.1:8080/invoke/fnid" { + if v != "http://127.0.0.1:8080/invoke/"+fnCreate.ID { t.Errorf("unexpected fn val %s", v) } } diff --git a/api/server/trigger_create.go b/api/server/trigger_create.go index e5b020e4b..36c784b7a 100644 --- a/api/server/trigger_create.go +++ b/api/server/trigger_create.go @@ -1,8 +1,10 @@ package server import ( + "fmt" "net/http" + "github.com/fnproject/fn/api/common" "github.com/fnproject/fn/api/models" "github.com/gin-gonic/gin" ) @@ -10,6 +12,7 @@ import ( func (s *Server) handleTriggerCreate(c *gin.Context) { ctx := c.Request.Context() trigger := &models.Trigger{} + log := common.Logger(ctx) err := c.BindJSON(trigger) if err != nil { @@ -27,5 +30,19 @@ func (s *Server) handleTriggerCreate(c *gin.Context) { return } - c.JSON(http.StatusOK, triggerCreated) + app, err := s.datastore.GetAppByID(ctx, triggerCreated.AppID) + if err != nil { + log.Debugln(fmt.Errorf("unexpected error - trigger app not available: %s", err)) + c.JSON(http.StatusOK, triggerCreated) + return + } + + triggerAnnotated, err := s.triggerAnnotator.AnnotateTrigger(c, app, triggerCreated) + if err != nil { + log.Debugln("Failed to annotate trigger on cration") + c.JSON(http.StatusOK, triggerCreated) + return + } + + c.JSON(http.StatusOK, triggerAnnotated) } diff --git a/api/server/trigger_test.go b/api/server/trigger_test.go index 66750923f..36e2be92f 100644 --- a/api/server/trigger_test.go +++ b/api/server/trigger_test.go @@ -315,24 +315,47 @@ func TestHTTPTriggerEndpointAnnotations(t *testing.T) { a := &models.App{ID: "appid", Name: "myapp"} fn := &models.Fn{ID: "fnid", AppID: a.ID} fn.SetDefaults() - trig := &models.Trigger{ID: "triggerid", FnID: fn.ID, AppID: a.ID, Type: "http", Source: "/myt"} - commonDS := datastore.NewMockInit([]*models.App{a}, []*models.Fn{fn}, []*models.Trigger{trig}) - + trig := &models.Trigger{Name: "thetrigger", FnID: fn.ID, AppID: a.ID, Type: "http", Source: "/myt"} + commonDS := datastore.NewMockInit([]*models.App{a}, []*models.Fn{fn}) + triggerBody, err := json.Marshal(trig) + if err != nil { + t.Fatalf("Failed to marshal triggerbody: %s", err) + } srv := testServer(commonDS, &mqs.Mock{}, logs.NewMock(), nil, ServerTypeAPI) - _, rec := routerRequest(t, srv.Router, "GET", "/v2/triggers/triggerid", bytes.NewBuffer([]byte(""))) + _, createTrigger := routerRequest(t, srv.Router, "POST", BaseRoute, bytes.NewReader(triggerBody)) + + if createTrigger.Code != http.StatusOK { + t.Fatalf("expected code %d != 200 %s", createTrigger.Code, createTrigger.Body.String()) + } + + var triggerCreate models.Trigger + err = json.NewDecoder(createTrigger.Body).Decode(&triggerCreate) + if err != nil { + t.Fatalf("Invalid json from server on trigger create: %s", err) + } + + const triggerEndpoint = "fnproject.io/trigger/httpEndpoint" + v, err := triggerCreate.Annotations.GetString(triggerEndpoint) + if err != nil { + t.Fatalf("failed to get trigger %s", err) + } + if v != "http://127.0.0.1:8080/t/myapp/myt" { + t.Errorf("unexpected trigger val %s", v) + } + + _, rec := routerRequest(t, srv.Router, "GET", "/v2/triggers/"+triggerCreate.ID, bytes.NewBuffer([]byte(""))) if rec.Code != http.StatusOK { t.Fatalf("expected code %d != 200", rec.Code) } var triggerGet models.Trigger - err := json.NewDecoder(rec.Body).Decode(&triggerGet) + err = json.NewDecoder(rec.Body).Decode(&triggerGet) if err != nil { t.Fatalf("Invalid json from server %s", err) } - const triggerEndpoint = "fnproject.io/trigger/httpEndpoint" - v, err := triggerGet.Annotations.GetString(triggerEndpoint) + v, err = triggerGet.Annotations.GetString(triggerEndpoint) if err != nil { t.Fatalf("failed to get trigger %s", err) }