You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by ju...@apache.org on 2020/09/11 02:51:11 UTC

[apisix-dashboard] branch master updated: feat: support ungroup in manager api (#460)

This is an automated email from the ASF dual-hosted git repository.

juzhiyuan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-dashboard.git


The following commit(s) were added to refs/heads/master by this push:
     new 66709c4  feat: support ungroup in manager api (#460)
66709c4 is described below

commit 66709c48749305608c33047af1ba10b3cc602cc1
Author: liuxiran <be...@126.com>
AuthorDate: Fri Sep 11 10:51:03 2020 +0800

    feat: support ungroup in manager api (#460)
    
    * feat: support ungroup in manager api
    
    * fix: synchronize route group to route
    
    * fix: update test case
---
 api/errno/error.go              |   1 +
 api/route/route.go              |  34 +++++++---
 api/route/route_group_test.go   |  92 ++++++++++++++++++++++----
 api/route/route_test.go         | 143 ++++++++++++++++++++++++++++++++++++++++
 api/service/route_group.go      |  20 +++++-
 api/service/route_group_test.go | 120 +++++++++++++++++++++++++++++++++
 6 files changed, 389 insertions(+), 21 deletions(-)

diff --git a/api/errno/error.go b/api/errno/error.go
index 68f313d..1004085 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}
+	SetRouteUngroupError    = Message{"010209", "Set route ungroup err", 500}
 
 	// 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 b6ace35..5be339f 100644
--- a/api/route/route.go
+++ b/api/route/route.go
@@ -201,12 +201,17 @@ func updateRoute(c *gin.Context) {
 	}
 	routeGroup := &service.RouteGroupDao{}
 	isCreateGroup := false
+	isUngroup := false
 	if len(strings.Trim(routeRequest.RouteGroupId, "")) == 0 {
-		isCreateGroup = true
-		routeGroup.ID = uuid.NewV4()
-		// create route group
-		routeGroup.Name = routeRequest.RouteGroupName
-		routeRequest.RouteGroupId = routeGroup.ID.String()
+		if len(strings.Trim(routeRequest.RouteGroupName, "")) > 0 {
+			isCreateGroup = true
+			routeGroup.ID = uuid.NewV4()
+			// create route group
+			routeGroup.Name = routeRequest.RouteGroupName
+			routeRequest.RouteGroupId = routeGroup.ID.String()
+		} else {
+			isUngroup = true
+		}
 	}
 	logger.Info(routeRequest.Plugins)
 	db := conf.DB()
@@ -253,6 +258,15 @@ func updateRoute(c *gin.Context) {
 				}
 			}
 		}
+		if isUngroup {
+			if err := tx.Model(&service.Route{}).Where("id = ?", rid).Update(map[string]interface{}{"route_group_id": "", "route_group_name": ""}).Error; err != nil {
+				tx.Rollback()
+				e := errno.FromMessage(errno.SetRouteUngroupError)
+				logger.Error(e.Msg)
+				c.AbortWithStatusJSON(http.StatusInternalServerError, e.Response())
+				return
+			}
+		}
 		if err := tx.Commit().Error; err == nil {
 			// update content_admin_api
 			if rd, err := service.ToRoute(routeRequest, arr, uuid.FromStringOrNil(rid), resp); err != nil {
@@ -343,11 +357,13 @@ func createRoute(c *gin.Context) {
 	routeGroup := &service.RouteGroupDao{}
 	isCreateGroup := false
 	if len(strings.Trim(routeRequest.RouteGroupId, "")) == 0 {
-		isCreateGroup = true
-		routeGroup.ID = uuid.NewV4()
 		// create route group
-		routeGroup.Name = routeRequest.RouteGroupName
-		routeRequest.RouteGroupId = routeGroup.ID.String()
+		if len(strings.Trim(routeRequest.RouteGroupName, "")) > 0 {
+			isCreateGroup = true
+			routeGroup.ID = uuid.NewV4()
+			routeGroup.Name = routeRequest.RouteGroupName
+			routeRequest.RouteGroupId = routeGroup.ID.String()
+		}
 	}
 	logger.Info(routeRequest.Plugins)
 	db := conf.DB()
diff --git a/api/route/route_group_test.go b/api/route/route_group_test.go
index ce939db..9b6f0ff 100644
--- a/api/route/route_group_test.go
+++ b/api/route/route_group_test.go
@@ -17,45 +17,115 @@
 package route
 
 import (
+	"github.com/apisix/manager-api/conf"
+	"github.com/apisix/manager-api/service"
 	"net/http"
 	"testing"
 )
 
-func TestRouteGroupCurd(t *testing.T) {
+func TestCreateRouteGroup(t *testing.T) {
 	// create ok
 	handler.
 		Post(uriPrefix+"/routegroups").
 		Header("Authorization", token).
 		JSON(`{
-			"name": "routegroup_test",
+			"name": "create_route_group_test",
 			"description": "test description"
 		}`).
 		Expect(t).
 		Status(http.StatusOK).
 		End()
+}
 
-	//c1, _ := service.GetConsumerByUserName("e2e_test_consumer1")
-	id := "8954a39b-330e-4b85-89f5-d1bbfd785b5b"
-	//update ok
+func TestDuplicateGroupName(t *testing.T) {
+	 // duplicate name
 	handler.
-		Put(uriPrefix+"/routegroups/"+id).
+		Post(uriPrefix+"/routegroups").
 		Header("Authorization", token).
 		JSON(`{
-			"name": "routegroup_test2",
+			"name": "create_route_group_test",
 			"description": "test description"
 		}`).
 		Expect(t).
-		Status(http.StatusOK).
+		Status(http.StatusInternalServerError).
 		End()
-	// duplicate username
+}
+
+func TestUpdateRouteGroup(t *testing.T) {
+	routeGroup, _ := getRouteGroupByName("create_route_group_test")
+	//update ok
 	handler.
-		Post(uriPrefix+"/routegroups").
+		Put(uriPrefix+"/routegroups/"+routeGroup.ID.String()).
 		Header("Authorization", token).
 		JSON(`{
-			"name": "routegroup_test",
+			"name": "update_route_group_test",
 			"description": "test description"
 		}`).
 		Expect(t).
+		Status(http.StatusOK).
+		End()
+}
+
+func TestDeleteRouteGroupHasRoutes(t *testing.T) {
+	routeGroup, _ := getRouteGroupByName("update_route_group_test")
+	// create route
+	handler.Post(uriPrefix+"/routes").
+		Header("Authorization", token).
+		JSON(`{
+			"name":"api-test-for-delete-group",
+			"desc":"api-test",
+			"priority":0,
+			"protocols":["http"],
+			"hosts":["test.com"],
+			"paths":["/*"],
+			"methods":["GET","HEAD","POST","PUT","DELETE","OPTIONS","PATCH"],
+			"status":false,
+			"upstream_protocol":"keep",
+			"plugins":{},
+			"uris":["/*"],
+			"vars":[],
+			"upstream":{"type":"roundrobin","nodes":{"127.0.0.1:443":1},
+			"timeout":{"connect":6000,"send":6000,"read":6000}},
+			"upstream_header":{},
+			"route_group_id":"` + routeGroup.ID.String() + `",
+			"route_group_name":"` + routeGroup.Name + `"
+}`).Expect(t).
+		Status(http.StatusOK).
+		End()
+	// delete fail
+	handler.
+		Delete(uriPrefix+"/routegroups/"+routeGroup.ID.String()).
+		Header("Authorization", token).
+		Expect(t).
 		Status(http.StatusInternalServerError).
 		End()
+	// get api-test-for-group
+	route, _ := getRouteByName("api-test-for-delete-group")
+	// delete route
+	handler.
+		Delete(uriPrefix+"/routes/"+route.ID.String()).
+		Header("Authorization", token).
+		Expect(t).
+		Status(http.StatusOK).
+		End()
+}
+
+func TestDeleteRouteGroup(t *testing.T) {
+	routeGroup, _ := getRouteGroupByName("update_route_group_test")
+	// delete ok
+	handler.
+		Delete(uriPrefix+"/routegroups/"+routeGroup.ID.String()).
+		Header("Authorization", token).
+		Expect(t).
+		Status(http.StatusOK).
+		End()
+}
+
+func getRouteGroupByName(name string) (*service.RouteGroupDao, error) {
+	db := conf.DB()
+	routeGroup := &service.RouteGroupDao{}
+	if err := db.Table("route_group").Where("name = ?", name).First(&routeGroup).Error; err != nil {
+		return nil, err
+	}
+	return routeGroup, nil
 }
diff --git a/api/route/route_test.go b/api/route/route_test.go
new file mode 100644
index 0000000..97442c0
--- /dev/null
+++ b/api/route/route_test.go
@@ -0,0 +1,143 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package route
+
+import (
+	"net/http"
+	"testing"
+	"github.com/apisix/manager-api/conf"
+	"github.com/apisix/manager-api/service"
+)
+
+func TestCreateRouteForUngroup(t *testing.T) {
+	// create route with no route group -- test ungroup
+	handler.Post(uriPrefix+"/routes").
+		Header("Authorization", token).
+		JSON(`{
+      "name":"api-test-no-group",
+      "desc":"api-test-no-group",
+      "priority":0,
+      "protocols":["http"],
+      "hosts":["test.com"],
+      "paths":["/*"],
+      "methods":["GET","HEAD","POST","PUT","DELETE","OPTIONS","PATCH"],
+      "status":false,
+      "upstream_protocol":"keep",
+      "plugins":{},
+      "uris":["/*"],
+      "vars":[],
+      "upstream":{"type":"roundrobin","nodes":{"127.0.0.1:443":1},
+      "timeout":{"connect":6000,"send":6000,"read":6000}},
+      "upstream_header":{},
+      "route_group_id":"",
+      "route_group_name":""
+}`).Expect(t).
+		Status(http.StatusOK).
+		End()
+}
+
+func TestUpdateRouteWithCreateRouteGroup(t *testing.T) {
+	route, _ := getRouteByName("api-test-no-group")
+
+	// update route for create route group
+	handler.Put(uriPrefix+"/routes/"+route.ID.String()).
+		Header("Authorization", token).
+		JSON(`{
+      "name":"api-test-no-group",
+      "desc":"api-test-no-group",
+      "priority":0,
+      "protocols":["http"],
+      "hosts":["test.com"],
+      "paths":["/*"],
+      "methods":["GET","HEAD","POST","PUT","DELETE","OPTIONS","PATCH"],
+      "status":false,
+      "upstream_protocol":"keep",
+      "plugins":{},
+      "uris":["/*"],
+      "vars":[],
+      "upstream":{"type":"roundrobin","nodes":{"127.0.0.1:443":1},
+      "timeout":{"connect":6000,"send":6000,"read":6000}},
+      "upstream_header":{},
+      "route_group_id":"",
+      "route_group_name":"route-update-test-create-group"
+}`).Expect(t).
+		Status(http.StatusOK).
+		End()
+}
+
+func TestCreateRouteWithCreateNewGroup(t *testing.T) {
+	// create route with new route group
+	handler.Post(uriPrefix+"/routes").
+		Header("Authorization", token).
+		JSON(`{
+      "name":"api-test-new-group",
+      "desc":"api-test-new-group",
+      "priority":0,
+      "protocols":["http"],
+      "hosts":["test.com"],
+      "paths":["/*"],
+      "methods":["GET","HEAD","POST","PUT","DELETE","OPTIONS","PATCH"],
+      "status":false,
+      "upstream_protocol":"keep",
+      "plugins":{},
+      "uris":["/*"],
+      "vars":[],
+      "upstream":{"type":"roundrobin","nodes":{"127.0.0.1:443":1},
+      "timeout":{"connect":6000,"send":6000,"read":6000}},
+      "upstream_header":{},
+      "route_group_id":"",
+      "route_group_name":"route-create-test-create-group"
+}`).Expect(t).
+		Status(http.StatusOK).
+		End()
+}
+
+func TestCreateRouteWithDuplicateGroupName(t *testing.T) {
+	// create route with duplicate route group name
+	handler.Post(uriPrefix+"/routes").
+		Header("Authorization", token).
+		JSON(`{
+      "name":"api-test",
+      "desc":"api-test",
+      "priority":0,
+      "protocols":["http"],
+      "hosts":["test.com"],
+      "paths":["/*"],
+      "methods":["GET","HEAD","POST","PUT","DELETE","OPTIONS","PATCH"],
+      "status":false,
+      "upstream_protocol":"keep",
+      "plugins":{},
+      "uris":["/*"],
+      "vars":[],
+      "upstream":{"type":"roundrobin","nodes":{"127.0.0.1:443":1},
+      "timeout":{"connect":6000,"send":6000,"read":6000}},
+      "upstream_header":{},
+      "route_group_id":"",
+      "route_group_name":"route-create-test-create-group"
+}`).Expect(t).
+		Status(http.StatusInternalServerError).
+		End()
+}
+
+func getRouteByName(name string) (*service.Route, error) {
+	db := conf.DB()
+	route := &service.Route{}
+	if err := db.Table("routes").Where("name = ?", name).First(&route).Error; err != nil {
+		return nil, err
+	}
+	return route, nil
+}
diff --git a/api/service/route_group.go b/api/service/route_group.go
index b016883..8eb9a4d 100644
--- a/api/service/route_group.go
+++ b/api/service/route_group.go
@@ -66,7 +66,25 @@ func (rd *RouteGroupDao) GetRouteGroupList(routeGroupList *[]RouteGroupDao, sear
 
 func (rd *RouteGroupDao) UpdateRouteGroup() error {
 	db := conf.DB()
-	return db.Model(&RouteGroupDao{}).Update(rd).Error
+	tx := db.Begin()
+	defer func() {
+		if r := recover(); r != nil {
+			tx.Rollback()
+		}
+	}()
+	if err := tx.Model(&RouteGroupDao{}).Update(rd).Error; err != nil {
+		tx.Rollback()
+		return err
+	}
+	if err := tx.Table("routes").Where("route_group_id = ?", rd.ID.String()).Update("route_group_name", rd.Name).Error; err != nil {
+		tx.Rollback()
+		return err
+	}
+	if err := tx.Commit().Error; err != nil {
+		tx.Rollback()
+		return err
+	}
+	return nil
 }
 
 func (rd *RouteGroupDao) DeleteRouteGroup() error {
diff --git a/api/service/route_group_test.go b/api/service/route_group_test.go
new file mode 100644
index 0000000..cb656b3
--- /dev/null
+++ b/api/service/route_group_test.go
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package service
+
+import (
+	"testing"
+
+	uuid "github.com/satori/go.uuid"
+	"github.com/stretchr/testify/assert"
+)
+
+var gid = uuid.NewV4()
+var gid2 = uuid.NewV4()
+
+func TestCreateRouteGroup(t *testing.T) {
+	routeGroup := &RouteGroupDao{
+		Base:        Base{},
+		Name:        "route_group_test",
+		Description: "route_group_test",
+	}
+	routeGroup.ID = gid
+	// create ok
+	err := routeGroup.CreateRouteGroup()
+	as := assert.New(t)
+	as.Nil(err)
+}
+
+func TestGetRouteGroup(t *testing.T) {
+	// get group ok
+	as := assert.New(t)
+	getGroup := &RouteGroupDao{}
+	err, i := getGroup.FindRouteGroup(gid.String())
+	as.Nil(err)
+	as.Equal("route_group_test", getGroup.Name)
+	as.Equal(1, i)
+}
+
+func TestRouteGroupNameDuplicate(t *testing.T) {
+	// name duplicate
+	as := assert.New(t)
+	routeGroup2 := &RouteGroupDao{
+		Base:        Base{},
+		Name:        "route_group_test",
+		Description: "route_group_test",
+	}
+	routeGroup2.ID = gid2
+	err := routeGroup2.CreateRouteGroup()
+	as.NotNil(err)
+	// ok
+	routeGroup2.Name = "route_group_test2"
+	err = routeGroup2.CreateRouteGroup()
+	as.Nil(err)
+}
+
+func TestGetRouteGupList(t *testing.T) {
+	as := assert.New(t)
+	// list ok
+	routeGroups := []RouteGroupDao{}
+	routeGroup := &RouteGroupDao{}
+	err, i3 := routeGroup.GetRouteGroupList(&routeGroups, "", 1, 2)
+	as.Nil(err)
+	as.Equal(true, i3 >= 2)
+	as.Equal(2, len(routeGroups))
+}
+
+func TestUpdateRouteGroup(t *testing.T) {
+	as := assert.New(t)
+	// update ok
+	routeGroup := &RouteGroupDao{
+		Base:        Base{},
+		Name:        "route_group_test_update",
+		Description: "route_group_test_update",
+	}
+	routeGroup.ID = gid
+	err := routeGroup.UpdateRouteGroup()
+	as.Nil(err)
+}
+
+func TestDeleteRouteGroup(t *testing.T) {
+	as := assert.New(t)
+	routeGroup := &RouteGroupDao{
+		Base:        Base{},
+		Name:        "route_group_test_update",
+		Description: "route_group_test_update",
+	}
+	routeGroup.ID = gid
+	// delete ok
+	err := routeGroup.DeleteRouteGroup()
+	as.Nil(err)
+
+	deleteGroup := &RouteGroupDao{}
+	err, i2 := deleteGroup.FindRouteGroup(gid.String())
+	as.Nil(err)
+	as.Equal("", deleteGroup.Name)
+	as.Equal(0, i2)
+
+	routeGroup2 := &RouteGroupDao{
+		Base:        Base{},
+		Name:        "route_group_test",
+		Description: "route_group_test",
+	}
+	routeGroup2.ID = gid2
+	err = routeGroup2.DeleteRouteGroup()
+	as.Nil(err)
+}