You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by ti...@apache.org on 2021/05/26 02:27:42 UTC

[servicecomb-service-center] branch master updated: SCB-2176 Add response filter (#1005)

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

tianxiaoliang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-service-center.git


The following commit(s) were added to refs/heads/master by this push:
     new 170a318  SCB-2176 Add response filter (#1005)
170a318 is described below

commit 170a3185652a3ab8a02b7959f9c06794b900a829
Author: little-cui <su...@qq.com>
AuthorDate: Wed May 26 10:27:36 2021 +0800

    SCB-2176 Add response filter (#1005)
    
    * SCB-2176 Add response filter
    
    * SCB-2176 Resolve comments
    
    * SCB-2176 Resolve comments
    
    * SCB-2176 Resolve comments
---
 server/handler/auth/auth.go                        |  25 +++-
 server/resource/register.go                        |   2 +-
 .../{resource/register.go => response/filter.go}   |  24 ++--
 server/response/response.go                        | 123 ++++++++++++++++++
 server/response/response_test.go                   | 137 +++++++++++++++++++++
 5 files changed, 290 insertions(+), 21 deletions(-)

diff --git a/server/handler/auth/auth.go b/server/handler/auth/auth.go
index bfbabce..32b5597 100644
--- a/server/handler/auth/auth.go
+++ b/server/handler/auth/auth.go
@@ -18,6 +18,9 @@
 package auth
 
 import (
+	"github.com/apache/servicecomb-service-center/pkg/util"
+	"github.com/apache/servicecomb-service-center/server/response"
+	"github.com/apache/servicecomb-service-center/server/rest/controller"
 	"net/http"
 
 	"github.com/apache/servicecomb-service-center/pkg/chain"
@@ -27,6 +30,8 @@ import (
 	"github.com/go-chassis/cari/discovery"
 )
 
+const CtxResourceLabels util.CtxKey = "_resource_labels"
+
 type Handler struct {
 }
 
@@ -43,16 +48,24 @@ func (h *Handler) Handle(i *chain.Invocation) {
 		if !ret.OK {
 			return
 		}
-
-		obj := i.Context().Value(rest.CtxResponseObject)
+		apiPath, obj := i.Context().Value(rest.CtxMatchPattern).(string),
+			i.Context().Value(rest.CtxResponseObject)
 		if obj == nil {
 			return
 		}
 
-		// TODO filter and rewrite here!
-		// data, _ := json.Marshal(obj)
-		// w := i.Context().Value(rest.CtxResponse).(http.ResponseWriter)
-		// w.Write(data)
+		labels, ok := i.Context().Value(CtxResourceLabels).([]map[string]string)
+		if !ok {
+			return
+		}
+		if len(labels) == 0 {
+			// all allowed
+			return
+		}
+		obj = response.Filter(apiPath, obj, labels)
+
+		w := i.Context().Value(rest.CtxResponse).(http.ResponseWriter)
+		controller.WriteResponse(w, r, nil, obj)
 	}))
 }
 
diff --git a/server/resource/register.go b/server/resource/register.go
index be0ceea..026b770 100644
--- a/server/resource/register.go
+++ b/server/resource/register.go
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package v4
+package resource
 
 import (
 	roa "github.com/apache/servicecomb-service-center/pkg/rest"
diff --git a/server/resource/register.go b/server/response/filter.go
similarity index 62%
copy from server/resource/register.go
copy to server/response/filter.go
index be0ceea..667c280 100644
--- a/server/resource/register.go
+++ b/server/response/filter.go
@@ -15,23 +15,19 @@
  * limitations under the License.
  */
 
-package v4
+package response
 
-import (
-	roa "github.com/apache/servicecomb-service-center/pkg/rest"
-	v1 "github.com/apache/servicecomb-service-center/server/resource/v1"
-	v4 "github.com/apache/servicecomb-service-center/server/resource/v4"
-	"github.com/apache/servicecomb-service-center/server/service/rbac"
-)
+var filters = map[string]FilterFunc{}
 
-func init() {
-	initRouter()
+type FilterFunc func(obj interface{}, filters []map[string]string) interface{}
+
+func RegisterFilter(apiPath string, f FilterFunc) {
+	filters[apiPath] = f
 }
 
-func initRouter() {
-	if rbac.Enabled() {
-		roa.RegisterServant(&v4.AuthResource{})
-		roa.RegisterServant(&v4.RoleResource{})
+func Filter(apiPath string, obj interface{}, labels []map[string]string) interface{} {
+	if f, ok := filters[apiPath]; ok {
+		return f(obj, labels)
 	}
-	roa.RegisterServant(&v1.Governance{})
+	return obj
 }
diff --git a/server/response/response.go b/server/response/response.go
new file mode 100644
index 0000000..3c01f10
--- /dev/null
+++ b/server/response/response.go
@@ -0,0 +1,123 @@
+/*
+ * 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 response
+
+import (
+	"github.com/go-chassis/cari/discovery"
+)
+
+func init() {
+	RegisterFilter("/v4/:project/registry/microservices", MicroserviceListFilter)
+	//response.RegisterFilter("/v4/:project/registry/instances", )
+	RegisterFilter("/v4/:project/registry/microservices/:providerId/consumers", ProvidersListFilter)
+	RegisterFilter("/v4/:project/registry/microservices/:consumerId/providers", ConsumersListFilter)
+	// control panel apis
+	RegisterFilter("/v4/:project/govern/microservices", MicroServiceInfoListFilter)
+	RegisterFilter("/v4/:project/govern/apps", AppIdListFilter)
+}
+
+func MicroserviceListFilter(obj interface{}, labels []map[string]string) interface{} {
+	servicesResponse, ok := obj.(*discovery.GetServicesResponse)
+	if !ok {
+		return obj
+	}
+	servicesResponse.Services = filterMicroservices(servicesResponse.Services, labels)
+	return servicesResponse
+}
+
+func filterMicroservices(sources []*discovery.MicroService, labelsList []map[string]string) []*discovery.MicroService {
+	var services []*discovery.MicroService
+	for _, service := range sources {
+		for _, labels := range labelsList {
+			if env, ok := labels["environment"]; ok && service.Environment != env {
+				continue
+			}
+			if app, ok := labels["appId"]; ok && service.AppId != app {
+				continue
+			}
+			if name, ok := labels["serviceName"]; ok && service.ServiceName != name {
+				continue
+			}
+			services = append(services, service)
+			break
+		}
+	}
+	return services
+}
+
+func ProvidersListFilter(obj interface{}, labels []map[string]string) interface{} {
+	servicesResponse, ok := obj.(*discovery.GetConDependenciesResponse)
+	if !ok {
+		return obj
+	}
+	servicesResponse.Providers = filterMicroservices(servicesResponse.Providers, labels)
+	return servicesResponse
+}
+
+func ConsumersListFilter(obj interface{}, labels []map[string]string) interface{} {
+	servicesResponse, ok := obj.(*discovery.GetProDependenciesResponse)
+	if !ok {
+		return obj
+	}
+	servicesResponse.Consumers = filterMicroservices(servicesResponse.Consumers, labels)
+	return servicesResponse
+}
+
+func MicroServiceInfoListFilter(obj interface{}, labelsList []map[string]string) interface{} {
+	servicesResponse, ok := obj.(*discovery.GetServicesInfoResponse)
+	if !ok {
+		return obj
+	}
+	var services []*discovery.ServiceDetail
+	for _, service := range servicesResponse.AllServicesDetail {
+		for _, labels := range labelsList {
+			if env, ok := labels["environment"]; ok && service.MicroService.Environment != env {
+				continue
+			}
+			if app, ok := labels["appId"]; ok && service.MicroService.AppId != app {
+				continue
+			}
+			if name, ok := labels["serviceName"]; ok && service.MicroService.ServiceName != name {
+				continue
+			}
+			services = append(services, service)
+			break
+		}
+	}
+	servicesResponse.AllServicesDetail = services
+	return servicesResponse
+}
+
+func AppIdListFilter(obj interface{}, labelsList []map[string]string) interface{} {
+	appsResponse, ok := obj.(*discovery.GetAppsResponse)
+	if !ok {
+		return obj
+	}
+	var apps []string
+	for _, appId := range appsResponse.AppIds {
+		for _, labels := range labelsList {
+			if app, ok := labels["appId"]; ok && appId != app {
+				continue
+			}
+			apps = append(apps, appId)
+			break
+		}
+	}
+	appsResponse.AppIds = apps
+	return appsResponse
+}
diff --git a/server/response/response_test.go b/server/response/response_test.go
new file mode 100644
index 0000000..233a764
--- /dev/null
+++ b/server/response/response_test.go
@@ -0,0 +1,137 @@
+/*
+ * 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 response_test
+
+import (
+	"github.com/apache/servicecomb-service-center/server/response"
+	"github.com/go-chassis/cari/discovery"
+	"github.com/stretchr/testify/assert"
+	"testing"
+)
+
+func TestMicroServiceInfoListFilter(t *testing.T) {
+	t.Run("obj is invalid, should do nothing", func(t *testing.T) {
+		other := &discovery.MicroService{}
+		assert.Equal(t, other, response.MicroServiceInfoListFilter(other, nil))
+	})
+
+	t.Run("labels is empty, should return empty resources", func(t *testing.T) {
+		rs := response.MicroServiceInfoListFilter(&discovery.GetServicesInfoResponse{
+			AllServicesDetail: []*discovery.ServiceDetail{
+				{MicroService: &discovery.MicroService{ServiceName: "A"}}, {MicroService: &discovery.MicroService{ServiceName: "B"}},
+			},
+		}, nil)
+		assert.Equal(t, 0, len(rs.(*discovery.GetServicesInfoResponse).AllServicesDetail))
+	})
+
+	t.Run("not match name, should return empty resources", func(t *testing.T) {
+		rs := response.MicroServiceInfoListFilter(&discovery.GetServicesInfoResponse{
+			AllServicesDetail: []*discovery.ServiceDetail{
+				{MicroService: &discovery.MicroService{ServiceName: "A"}}, {MicroService: &discovery.MicroService{ServiceName: "B"}},
+			},
+		}, []map[string]string{{"serviceName": "NONE"}})
+		assert.Equal(t, 0, len(rs.(*discovery.GetServicesInfoResponse).AllServicesDetail))
+	})
+
+	t.Run("match A, should return A resources", func(t *testing.T) {
+		rs := response.MicroServiceInfoListFilter(&discovery.GetServicesInfoResponse{
+			AllServicesDetail: []*discovery.ServiceDetail{
+				{MicroService: &discovery.MicroService{ServiceName: "A"}}, {MicroService: &discovery.MicroService{ServiceName: "B"}},
+			},
+		}, []map[string]string{{"serviceName": "A"}})
+		mss := rs.(*discovery.GetServicesInfoResponse).AllServicesDetail
+		assert.Equal(t, 1, len(mss))
+		assert.Equal(t, "A", mss[0].MicroService.ServiceName)
+	})
+
+	t.Run("not match name & appId, should return empty resources", func(t *testing.T) {
+		rs := response.MicroServiceInfoListFilter(&discovery.GetServicesInfoResponse{
+			AllServicesDetail: []*discovery.ServiceDetail{
+				{MicroService: &discovery.MicroService{ServiceName: "A"}}, {MicroService: &discovery.MicroService{ServiceName: "B"}},
+			},
+		}, []map[string]string{{"serviceName": "A", "appId": "A"}})
+		mss := rs.(*discovery.GetServicesInfoResponse).AllServicesDetail
+		assert.Equal(t, 0, len(mss))
+	})
+
+	t.Run("match name & appId, should return empty resources", func(t *testing.T) {
+		rs := response.MicroServiceInfoListFilter(&discovery.GetServicesInfoResponse{
+			AllServicesDetail: []*discovery.ServiceDetail{
+				{MicroService: &discovery.MicroService{AppId: "A", ServiceName: "A"}}, {MicroService: &discovery.MicroService{ServiceName: "B"}},
+			},
+		}, []map[string]string{{"serviceName": "A", "appId": "A"}})
+		mss := rs.(*discovery.GetServicesInfoResponse).AllServicesDetail
+		assert.Equal(t, 1, len(mss))
+	})
+}
+
+func TestMicroserviceListFilter(t *testing.T) {
+	t.Run("obj is invalid, should do nothing", func(t *testing.T) {
+		other := &discovery.MicroService{}
+		assert.Equal(t, other, response.MicroserviceListFilter(other, nil))
+	})
+
+	t.Run("labels is empty, should return empty resources", func(t *testing.T) {
+		rs := response.MicroserviceListFilter(&discovery.GetServicesResponse{
+			Services: []*discovery.MicroService{
+				{ServiceName: "A"}, {ServiceName: "B"},
+			},
+		}, nil)
+		assert.Equal(t, 0, len(rs.(*discovery.GetServicesResponse).Services))
+	})
+
+	t.Run("not match name, should return empty resources", func(t *testing.T) {
+		rs := response.MicroserviceListFilter(&discovery.GetServicesResponse{
+			Services: []*discovery.MicroService{
+				{ServiceName: "A"}, {ServiceName: "B"},
+			},
+		}, []map[string]string{{"serviceName": "NONE"}})
+		assert.Equal(t, 0, len(rs.(*discovery.GetServicesResponse).Services))
+	})
+
+	t.Run("match A, should return A resources", func(t *testing.T) {
+		rs := response.MicroserviceListFilter(&discovery.GetServicesResponse{
+			Services: []*discovery.MicroService{
+				{ServiceName: "A"}, {ServiceName: "B"},
+			},
+		}, []map[string]string{{"serviceName": "A"}})
+		mss := rs.(*discovery.GetServicesResponse).Services
+		assert.Equal(t, 1, len(mss))
+		assert.Equal(t, "A", mss[0].ServiceName)
+	})
+
+	t.Run("not match name & appId, should return empty resources", func(t *testing.T) {
+		rs := response.MicroserviceListFilter(&discovery.GetServicesResponse{
+			Services: []*discovery.MicroService{
+				{ServiceName: "A"}, {ServiceName: "B"},
+			},
+		}, []map[string]string{{"serviceName": "A", "appId": "A"}})
+		mss := rs.(*discovery.GetServicesResponse).Services
+		assert.Equal(t, 0, len(mss))
+	})
+
+	t.Run("match name & appId, should return empty resources", func(t *testing.T) {
+		rs := response.MicroserviceListFilter(&discovery.GetServicesResponse{
+			Services: []*discovery.MicroService{
+				{AppId: "A", ServiceName: "A"}, {ServiceName: "B"},
+			},
+		}, []map[string]string{{"serviceName": "A", "appId": "A"}})
+		mss := rs.(*discovery.GetServicesResponse).Services
+		assert.Equal(t, 1, len(mss))
+	})
+}