From 70eb25c873438ce2aac81757bc0f3fc2d6dd4da0 Mon Sep 17 00:00:00 2001 From: James Jeffrey Date: Fri, 30 Jun 2017 16:46:03 -0700 Subject: [PATCH] Change logic behind put post and patch for routes --- api/server/routes_create.go | 96 --------------------- api/server/routes_create_update.go | 132 +++++++++++++++++++++++++++++ api/server/routes_update.go | 77 ----------------- api/server/server.go | 25 +++--- 4 files changed, 145 insertions(+), 185 deletions(-) delete mode 100644 api/server/routes_create.go create mode 100644 api/server/routes_create_update.go delete mode 100644 api/server/routes_update.go diff --git a/api/server/routes_create.go b/api/server/routes_create.go deleted file mode 100644 index ddbaa2140..000000000 --- a/api/server/routes_create.go +++ /dev/null @@ -1,96 +0,0 @@ -package server - -import ( - "context" - "net/http" - - "github.com/gin-gonic/gin" - "gitlab-odx.oracle.com/odx/functions/api" - "gitlab-odx.oracle.com/odx/functions/api/models" - "gitlab-odx.oracle.com/odx/functions/api/runner/common" -) - -func (s *Server) handleRouteCreate(c *gin.Context) { - ctx := c.MustGet("ctx").(context.Context) - log := common.Logger(ctx) - - var wroute models.RouteWrapper - - err := c.BindJSON(&wroute) - if err != nil { - log.WithError(err).Debug(models.ErrInvalidJSON) - c.JSON(http.StatusBadRequest, simpleError(models.ErrInvalidJSON)) - return - } - - if wroute.Route == nil { - log.WithError(err).Debug(models.ErrInvalidJSON) - c.JSON(http.StatusBadRequest, simpleError(models.ErrRoutesMissingNew)) - return - } - - wroute.Route.AppName = c.MustGet(api.AppName).(string) - - wroute.Route.SetDefaults() - - if err := wroute.Validate(false); err != nil { - log.WithError(err).Debug(models.ErrRoutesCreate) - c.JSON(http.StatusBadRequest, simpleError(err)) - return - } - - // err = s.Runner.EnsureImageExists(ctx, &task.Config{ - // Image: wroute.Route.Image, - // }) - // if err != nil { - // c.JSON(http.StatusBadRequest, simpleError(models.ErrUsableImage)) - // return - // } - - app, err := s.Datastore.GetApp(ctx, wroute.Route.AppName) - if err != nil && err != models.ErrAppsNotFound { - log.WithError(err).Error(models.ErrAppsGet) - c.JSON(http.StatusInternalServerError, simpleError(models.ErrAppsGet)) - return - } else if app == nil { - // Create a new application and add the route to that new application - newapp := &models.App{Name: wroute.Route.AppName} - if err := newapp.Validate(); err != nil { - log.Error(err) - c.JSON(http.StatusInternalServerError, simpleError(err)) - return - } - - err = s.FireBeforeAppCreate(ctx, newapp) - if err != nil { - log.WithError(err).Error(models.ErrAppsCreate) - c.JSON(http.StatusInternalServerError, simpleError(ErrInternalServerError)) - return - } - - _, err = s.Datastore.InsertApp(ctx, newapp) - if err != nil { - log.WithError(err).Error(models.ErrRoutesCreate) - c.JSON(http.StatusInternalServerError, simpleError(ErrInternalServerError)) - return - } - - err = s.FireAfterAppCreate(ctx, newapp) - if err != nil { - log.WithError(err).Error(models.ErrRoutesCreate) - c.JSON(http.StatusInternalServerError, simpleError(ErrInternalServerError)) - return - } - - } - - route, err := s.Datastore.InsertRoute(ctx, wroute.Route) - if err != nil { - handleErrorResponse(c, err) - return - } - - s.cacheRefresh(route) - - c.JSON(http.StatusOK, routeResponse{"Route successfully created", route}) -} diff --git a/api/server/routes_create_update.go b/api/server/routes_create_update.go new file mode 100644 index 000000000..fee1773e7 --- /dev/null +++ b/api/server/routes_create_update.go @@ -0,0 +1,132 @@ +package server + +import ( + "context" + "fmt" + "net/http" + "path" + "strings" + + "github.com/gin-gonic/gin" + "gitlab-odx.oracle.com/odx/functions/api" + "gitlab-odx.oracle.com/odx/functions/api/models" + "gitlab-odx.oracle.com/odx/functions/api/runner/common" +) + +/* handleRouteCreateOrUpdate is used to handle POST PUT and PATCH for routes. + Post will only create route if its not there and create app if its not. + create only + Put will create app if its not there and if route is there update if not it will create new route. + update if exists or create if not exists + Patch will not create app if it does not exist since the route needs to exist as well... + update only +*/ +func (s *Server) handleRouteCreateOrUpdate(c *gin.Context) { + ctx := c.MustGet("ctx").(context.Context) + log := common.Logger(ctx) + method := strings.ToLower(c.Request.Method) + switch method { + case "post", "put", "patch": + default: + c.JSON(http.StatusMethodNotAllowed, simpleError(fmt.Errorf(http.StatusText(http.StatusMethodNotAllowed)))) + return + } + var wroute models.RouteWrapper + + err := c.BindJSON(&wroute) + if err != nil { + log.WithError(err).Debug(models.ErrInvalidJSON) + c.JSON(http.StatusBadRequest, simpleError(models.ErrInvalidJSON)) + return + } + + if wroute.Route == nil { + log.WithError(err).Debug(models.ErrRoutesMissingNew) + c.JSON(http.StatusBadRequest, simpleError(models.ErrRoutesMissingNew)) + return + } + + wroute.Route.AppName = c.MustGet(api.AppName).(string) + + if method == "put" || method == "patch" { + p := path.Clean(c.MustGet(api.Path).(string)) + + if wroute.Route.Path != "" && wroute.Route.Path != p { + log.Debug(models.ErrRoutesPathImmutable) + c.JSON(http.StatusBadRequest, simpleError(models.ErrRoutesPathImmutable)) + return + } + wroute.Route.Path = p + } + + wroute.Route.SetDefaults() + + if err = wroute.Validate(method == "post"); err != nil { + log.WithError(err).Debug(models.ErrRoutesCreate) + c.JSON(http.StatusBadRequest, simpleError(err)) + return + } + + if method == "post" || method == "put" { + app, err := s.Datastore.GetApp(ctx, wroute.Route.AppName) + if err != nil && err != models.ErrAppsNotFound { + log.WithError(err).Error(models.ErrAppsGet) + c.JSON(http.StatusInternalServerError, simpleError(models.ErrAppsGet)) + return + } else if app == nil { + // Create a new application and add the route to that new application + newapp := &models.App{Name: wroute.Route.AppName} + if err = newapp.Validate(); err != nil { + log.Error(err) + c.JSON(http.StatusInternalServerError, simpleError(err)) + return + } + + err = s.FireBeforeAppCreate(ctx, newapp) + if err != nil { + log.WithError(err).Error(models.ErrAppsCreate) + c.JSON(http.StatusInternalServerError, simpleError(ErrInternalServerError)) + return + } + + _, err = s.Datastore.InsertApp(ctx, newapp) + if err != nil { + log.WithError(err).Error(models.ErrRoutesCreate) + c.JSON(http.StatusInternalServerError, simpleError(ErrInternalServerError)) + return + } + + err = s.FireAfterAppCreate(ctx, newapp) + if err != nil { + log.WithError(err).Error(models.ErrRoutesCreate) + c.JSON(http.StatusInternalServerError, simpleError(ErrInternalServerError)) + return + } + + } + } + + var route *models.Route + + switch method { + case "post": + route, err = s.Datastore.InsertRoute(ctx, wroute.Route) + case "put": + route, err = s.Datastore.UpdateRoute(ctx, wroute.Route) + if err == models.ErrRoutesNotFound { + // try insert then + route, err = s.Datastore.InsertRoute(ctx, wroute.Route) + } + case "patch": + route, err = s.Datastore.UpdateRoute(ctx, wroute.Route) + } + + if err != nil { + handleErrorResponse(c, err) + return + } + + s.cacheRefresh(route) + + c.JSON(http.StatusOK, routeResponse{"Route successfully created", route}) +} diff --git a/api/server/routes_update.go b/api/server/routes_update.go deleted file mode 100644 index dc38e4ec0..000000000 --- a/api/server/routes_update.go +++ /dev/null @@ -1,77 +0,0 @@ -package server - -import ( - "context" - "net/http" - "path" - - "github.com/gin-gonic/gin" - "gitlab-odx.oracle.com/odx/functions/api" - "gitlab-odx.oracle.com/odx/functions/api/models" - "gitlab-odx.oracle.com/odx/functions/api/runner/common" -) - -func (s *Server) handleRouteUpdate(c *gin.Context) { - ctx := c.MustGet("ctx").(context.Context) - log := common.Logger(ctx) - - var wroute models.RouteWrapper - - err := c.BindJSON(&wroute) - if err != nil { - log.WithError(err).Debug(models.ErrInvalidJSON) - c.JSON(http.StatusBadRequest, simpleError(models.ErrInvalidJSON)) - return - } - - if wroute.Route == nil { - log.Debug(models.ErrRoutesMissingNew) - c.JSON(http.StatusBadRequest, simpleError(models.ErrRoutesMissingNew)) - return - } - - if wroute.Route.Path != "" { - log.Debug(models.ErrRoutesPathImmutable) - c.JSON(http.StatusBadRequest, simpleError(models.ErrRoutesPathImmutable)) - return - } - - // fmt.Printf("ROUTE BOUND: %+v", *wroute.Route) - - wroute.Route.AppName = c.MustGet(api.AppName).(string) - wroute.Route.Path = path.Clean(c.MustGet(api.Path).(string)) - - wroute.Route.SetDefaults() - - if err := wroute.Validate(true); err != nil { - log.WithError(err).Debug(models.ErrRoutesUpdate) - c.JSON(http.StatusBadRequest, simpleError(err)) - return - } - - if wroute.Route.Image != "" { - // This was checking that an image exists, but it's too slow of an operation. Checks at runtime now. - // err = s.Runner.EnsureImageExists(ctx, &task.Config{ - // Image: wroute.Route.Image, - // }) - // if err != nil { - // log.WithError(err).Debug(models.ErrRoutesUpdate) - // c.JSON(http.StatusBadRequest, simpleError(models.ErrUsableImage)) - // return - // } - } - - route, err := s.Datastore.UpdateRoute(ctx, wroute.Route) - if err == models.ErrRoutesNotFound { - // try insert then - route, err = s.Datastore.InsertRoute(ctx, wroute.Route) - } - if err != nil { - handleErrorResponse(c, err) - return - } - - s.cacheRefresh(route) - - c.JSON(http.StatusOK, routeResponse{"Route successfully updated", route}) -} diff --git a/api/server/server.go b/api/server/server.go index 3273c80b0..1f7a9fe34 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -19,30 +19,30 @@ import ( "gitlab-odx.oracle.com/odx/functions/api" "gitlab-odx.oracle.com/odx/functions/api/datastore" "gitlab-odx.oracle.com/odx/functions/api/id" + "gitlab-odx.oracle.com/odx/functions/api/logs" "gitlab-odx.oracle.com/odx/functions/api/models" "gitlab-odx.oracle.com/odx/functions/api/mqs" "gitlab-odx.oracle.com/odx/functions/api/runner" "gitlab-odx.oracle.com/odx/functions/api/runner/common" "gitlab-odx.oracle.com/odx/functions/api/server/internal/routecache" - "gitlab-odx.oracle.com/odx/functions/api/logs" ) const ( EnvLogLevel = "log_level" EnvMQURL = "mq_url" EnvDBURL = "db_url" - EnvLOGDBURL = "logstore_url" + EnvLOGDBURL = "logstore_url" EnvPort = "port" // be careful, Gin expects this variable to be "port" EnvAPIURL = "api_url" ) type Server struct { - Datastore models.Datastore - Runner *runner.Runner - Router *gin.Engine - MQ models.MessageQueue - Enqueue models.Enqueue - LogDB models.FnLog + Datastore models.Datastore + Runner *runner.Runner + Router *gin.Engine + MQ models.MessageQueue + Enqueue models.Enqueue + LogDB models.FnLog apiURL string @@ -317,9 +317,10 @@ func (s *Server) bindHandlers(ctx context.Context) { apps := v1.Group("/apps/:app") { apps.GET("/routes", s.handleRouteList) - apps.POST("/routes", s.handleRouteCreate) + apps.POST("/routes", s.handleRouteCreateOrUpdate) apps.GET("/routes/*route", s.handleRouteGet) - apps.PATCH("/routes/*route", s.handleRouteUpdate) + apps.PATCH("/routes/*route", s.handleRouteCreateOrUpdate) + apps.PUT("/routes/*route", s.handleRouteCreateOrUpdate) apps.DELETE("/routes/*route", s.handleRouteDelete) apps.GET("/calls/*route", s.handleCallList) } @@ -369,6 +370,6 @@ type fnCallsResponse struct { } type fnCallLogResponse struct { - Message string `json:"message"` - Log *models.FnCallLog `json:"log"` + Message string `json:"message"` + Log *models.FnCallLog `json:"log"` }