From b747828baac25d79bc6915025dc79a6ac293130b Mon Sep 17 00:00:00 2001 From: liuxiran Date: Mon, 7 Sep 2020 21:53:14 +0800 Subject: [PATCH] feat: add publish status to route in manager api --- api/errno/error.go | 1 + api/route/route.go | 147 ++++++++++++++++++++++++++++++++++----- api/script/db/schema.sql | 2 +- api/service/route.go | 7 ++ 4 files changed, 138 insertions(+), 19 deletions(-) diff --git a/api/errno/error.go b/api/errno/error.go index 68f313d028..b9a2631833 100644 --- a/api/errno/error.go +++ b/api/errno/error.go @@ -57,6 +57,7 @@ var ( DBRouteUpdateError = Message{"010206", "Route update failed: %s", 500} DBRouteDeleteError = Message{"010207", "Route deletion failed: %s", 500} DBRouteReduplicateError = Message{"010208", "Route name is reduplicate : %s", 400} + RoutePublishError = Message{"010209", "Route publish error", 400} // 03 plugins ApisixPluginListError = Message{"010301", "find APISIX plugin list failed: %s", 500} diff --git a/api/route/route.go b/api/route/route.go index b6ace35e9e..5826ad63b8 100644 --- a/api/route/route.go +++ b/api/route/route.go @@ -34,11 +34,100 @@ func AppendRoute(r *gin.Engine) *gin.Engine { r.GET("/apisix/admin/routes/:rid", findRoute) r.GET("/apisix/admin/routes", listRoute) r.PUT("/apisix/admin/routes/:rid", updateRoute) + r.PUT("/apisix/admin/publishroutes/:rid", publishRoute) r.DELETE("/apisix/admin/routes/:rid", deleteRoute) r.GET("/apisix/admin/notexist/routes", isRouteExist) + r.PUT("/apisix/admin/offlineroutes/:rid", offlineRoute) return r } +func publishRoute(c *gin.Context) { + rid := c.Param("rid") + r := &service.Route{} + tx := conf.DB().Begin() + if err := tx.Model(&service.Route{}).Where("id = ?", rid).Update("status", true).Find(&r).Error; err != nil { + tx.Rollback() + e := errno.FromMessage(errno.RoutePublishError, err.Error()) + logger.Error(e.Msg) + c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response()) + return + } else { + routeRequest := &service.RouteRequest{} + if err := json.Unmarshal([]byte(r.Content), routeRequest); err != nil { + tx.Rollback() + e := errno.FromMessage(errno.RoutePublishError, err.Error()) + logger.Error(e.Msg) + c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response()) + return + } + arr := service.ToApisixRequest(routeRequest) + var resp *service.ApisixRouteResponse + if resp, err = arr.Create(rid); err != nil { + tx.Rollback() + if httpError, ok := err.(*errno.HttpError); ok { + c.AbortWithStatusJSON(httpError.Code, httpError.Msg) + return + } else { + e := errno.FromMessage(errno.ApisixRouteCreateError, err.Error()) + logger.Error(e.Msg) + c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response()) + return + } + } else { + resp.Node.Value.Name = r.Name + resp.Node.Value.Status = r.Status + if respStr, err := json.Marshal(resp); err != nil { + e := errno.FromMessage(errno.RoutePublishError, err.Error()) + logger.Error(e.Msg) + c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response()) + return + } else { + r.ContentAdminApi = string(respStr) + } + } + if err := tx.Commit().Error; err == nil { + // update content_admin_api + if err := conf.DB().Model(&service.Route{}).Update(r).Error; err != nil { + e := errno.FromMessage(errno.DBRouteUpdateError, err.Error()) + logger.Error(e.Msg) + } + } + } + c.Data(http.StatusOK, service.ContentType, errno.Success()) +} + +func offlineRoute(c *gin.Context) { + rid := c.Param("rid") + db := conf.DB() + tx := db.Begin() + if err := tx.Model(&service.Route{}).Where("id = ?", rid).Update(map[string]interface{}{"status": 0, "content_admin_api": ""}).Error; err != nil { + tx.Rollback() + e := errno.FromMessage(errno.RoutePublishError, err.Error()) + logger.Error(e.Msg) + c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response()) + return + } else { + request := &service.ApisixRouteRequest{} + if _, err := request.Delete(rid); err != nil { + tx.Rollback() + if httpError, ok := err.(*errno.HttpError); ok { + c.AbortWithStatusJSON(httpError.Code, httpError.Msg) + return + } else { + e := errno.FromMessage(errno.ApisixRouteDeleteError, err.Error()) + logger.Error(e.Msg) + c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response()) + return + } + } + } + if err := tx.Commit().Error; err != nil { + e := errno.FromMessage(errno.ApisixRouteDeleteError, err.Error()) + logger.Error(e.Msg) + } + c.Data(http.StatusOK, service.ContentType, errno.Success()) +} + func isRouteExist(c *gin.Context) { if name, exist := c.GetQuery("name"); exist { db := conf.DB() @@ -156,13 +245,19 @@ func deleteRoute(c *gin.Context) { // delete from mysql rd := &service.Route{} rd.ID = uuid.FromStringOrNil(rid) + if err := db.Table("routes").Where("id=?", rid).First(&rd).Error; err != nil { + e := errno.FromMessage(errno.RouteRequestError, err.Error()+" route ID: "+rid) + logger.Error(e.Msg) + c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response()) + return + } if err := conf.DB().Delete(rd).Error; err != nil { tx.Rollback() e := errno.FromMessage(errno.DBRouteDeleteError, err.Error()) logger.Error(e.Msg) c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response()) return - } else { + } else if rd.Status { request := &service.ApisixRouteRequest{} if _, err := request.Delete(rid); err != nil { tx.Rollback() @@ -212,10 +307,12 @@ func updateRoute(c *gin.Context) { db := conf.DB() arr := service.ToApisixRequest(routeRequest) var resp *service.ApisixRouteResponse + var r *service.Route if rd, err := service.ToRoute(routeRequest, arr, uuid.FromStringOrNil(rid), nil); err != nil { c.AbortWithStatusJSON(http.StatusInternalServerError, err.Response()) return } else { + r = rd tx := db.Begin() defer func() { if r := recover(); r != nil { @@ -239,7 +336,7 @@ func updateRoute(c *gin.Context) { logger.Error(e.Msg) c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response()) return - } else { + } else if rd.Status { if resp, err = arr.Update(rid); err != nil { tx.Rollback() if httpError, ok := err.(*errno.HttpError); ok { @@ -253,7 +350,7 @@ func updateRoute(c *gin.Context) { } } } - if err := tx.Commit().Error; err == nil { + if err := tx.Commit().Error; err == nil && r.Status { // update content_admin_api if rd, err := service.ToRoute(routeRequest, arr, uuid.FromStringOrNil(rid), resp); err != nil { e := errno.FromMessage(errno.DBRouteUpdateError, err.Error()) @@ -271,8 +368,9 @@ func updateRoute(c *gin.Context) { func findRoute(c *gin.Context) { rid := c.Param("rid") + route := &service.Route{} var count int - if err := conf.DB().Table("routes").Where("id=?", rid).Count(&count).Error; err != nil { + if err := conf.DB().Table("routes").Where("id=?", rid).Count(&count).First(&route).Error; err != nil { e := errno.FromMessage(errno.RouteRequestError, err.Error()+" route ID: "+rid) logger.Error(e.Msg) c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response()) @@ -285,28 +383,39 @@ func findRoute(c *gin.Context) { return } } - // find from apisix - request := &service.ApisixRouteRequest{} - if response, err := request.FindById(rid); err != nil { - e := errno.FromMessage(errno.RouteRequestError, err.Error()+" route ID: "+rid) - logger.Error(e.Msg) - c.AbortWithStatusJSON(http.StatusBadRequest, e.Response()) - return + if !route.Status { + routeRequest := &service.RouteRequest{} + if err := json.Unmarshal([]byte(route.Content), &routeRequest); err != nil { + e := errno.FromMessage(errno.RouteRequestError, " route ID: "+rid+" not exist") + logger.Error(e.Msg) + c.AbortWithStatusJSON(e.Status, e.Response()) + return + } else { + routeRequest.Name = route.Name + resp, _ := json.Marshal(routeRequest) + c.Data(http.StatusOK, service.ContentType, resp) + } } else { - // transfer response to dashboard struct - if result, err := response.Parse(); err != nil { + // find from apisix + request := &service.ApisixRouteRequest{} + if response, err := request.FindById(rid); err != nil { e := errno.FromMessage(errno.RouteRequestError, err.Error()+" route ID: "+rid) logger.Error(e.Msg) c.AbortWithStatusJSON(http.StatusBadRequest, e.Response()) return } else { - // need to find name from mysql temporary - route := &service.Route{} - if err := conf.DB().Table("routes").Where("id=?", rid).First(&route).Error; err != nil { + // transfer response to dashboard struct + if result, err := response.Parse(); err != nil { e := errno.FromMessage(errno.RouteRequestError, err.Error()+" route ID: "+rid) logger.Error(e.Msg) c.AbortWithStatusJSON(http.StatusBadRequest, e.Response()) return + } else { + // need to find name from mysql temporary + result.Name = route.Name + result.Status = true + resp, _ := json.Marshal(result) + c.Data(http.StatusOK, service.ContentType, resp) } result.Name = route.Name var script map[string]interface{} @@ -353,10 +462,12 @@ func createRoute(c *gin.Context) { db := conf.DB() arr := service.ToApisixRequest(routeRequest) var resp *service.ApisixRouteResponse + var r *service.Route if rd, err := service.ToRoute(routeRequest, arr, u4, nil); err != nil { c.AbortWithStatusJSON(http.StatusInternalServerError, err.Response()) return } else { + r = rd tx := db.Begin() defer func() { if r := recover(); r != nil { @@ -380,7 +491,7 @@ func createRoute(c *gin.Context) { logger.Error(e.Msg) c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response()) return - } else { + } else if rd.Status { if resp, err = arr.Create(rid); err != nil { tx.Rollback() if httpError, ok := err.(*errno.HttpError); ok { @@ -394,7 +505,7 @@ func createRoute(c *gin.Context) { } } } - if err := tx.Commit().Error; err == nil { + if err := tx.Commit().Error; err == nil && r.Status { // update content_admin_api if rd, err := service.ToRoute(routeRequest, arr, u4, resp); err != nil { e := errno.FromMessage(errno.DBRouteUpdateError, err.Error()) diff --git a/api/script/db/schema.sql b/api/script/db/schema.sql index af839299c9..8c476c3f62 100644 --- a/api/script/db/schema.sql +++ b/api/script/db/schema.sql @@ -18,7 +18,7 @@ CREATE TABLE `routes` ( `update_time` bigint(20), `route_group_id` varchar(64) NOT NULL, `route_group_name` varchar(64) NOT NULL, - + `status` tinyint(1), PRIMARY KEY (`id`) ) DEFAULT CHARSET=utf8; diff --git a/api/service/route.go b/api/service/route.go index 5a88af945c..edea8e23b4 100644 --- a/api/service/route.go +++ b/api/service/route.go @@ -82,6 +82,7 @@ func (rd *Route) Parse(r *RouteRequest, arr *ApisixRouteRequest) error { rd.UpstreamId = r.UpstreamId rd.RouteGroupId = r.RouteGroupId rd.RouteGroupName = r.RouteGroupName + rd.Status = r.Status if content, err := json.Marshal(r); err != nil { return err } else { @@ -192,6 +193,7 @@ type RouteRequest struct { Script map[string]interface{} `json:"script"` RouteGroupId string `json:"route_group_id"` RouteGroupName string `json:"route_group_name"` + Status bool `json:"status"` } func (r *ApisixRouteResponse) Parse() (*RouteRequest, error) { @@ -414,6 +416,7 @@ type Value struct { Plugins map[string]interface{} `json:"plugins"` RouteGroupId string `json:"route_group_id"` RouteGroupName string `json:"route_group_name"` + Status bool `json:"status"` } type Route struct { @@ -430,6 +433,7 @@ type Route struct { ContentAdminApi string `json:"content_admin_api"` RouteGroupId string `json:"route_group_id"` RouteGroupName string `json:"route_group_name"` + Status bool `json:"status"` } type RouteResponse struct { @@ -443,6 +447,7 @@ type RouteResponse struct { Priority int64 `json:"priority"` RouteGroupId string `json:"route_group_id"` RouteGroupName string `json:"route_group_name"` + Status bool `json:"status"` } type ListResponse struct { @@ -458,6 +463,7 @@ func (rr *RouteResponse) Parse(r *Route) { rr.Priority = r.Priority rr.RouteGroupId = r.RouteGroupId rr.RouteGroupName = r.RouteGroupName + rr.Status = r.Status // hosts if len(r.Hosts) > 0 { var hosts []string @@ -597,6 +603,7 @@ func ToRoute(routeRequest *RouteRequest, // content_admin_api if resp != nil { resp.Node.Value.RouteGroupId = rd.RouteGroupId + resp.Node.Value.Status = rd.Status if respStr, err := json.Marshal(resp); err != nil { e := errno.FromMessage(errno.DBRouteCreateError, err.Error()) return nil, e