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

littlecui 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 bfaa1e6  SCB-2176 Fix: Remove config when delete gov match-group (#957)
bfaa1e6 is described below

commit bfaa1e64846e04c17685c16f5e03289a1a67301d
Author: little-cui <[email protected]>
AuthorDate: Thu Apr 22 22:35:11 2021 +0800

    SCB-2176 Fix: Remove config when delete gov match-group (#957)
    
    * SCB-2176 Fix: Remove config when delete gov match-group
    
    * SCB-2176 Delete all policies of match-group
---
 pkg/gov/governance.go                         |  12 +--
 pkg/gov/governance_test.go                    |   2 +-
 server/resource/v1/gov_resource.go            |  18 ++--
 server/service/gov/config_distributor.go      |  12 +--
 server/service/gov/config_distributor_test.go |  17 +++-
 server/service/gov/kie/kie_distributor.go     | 124 ++++++++++++++++++--------
 server/service/gov/mock/mock.go               |   6 +-
 7 files changed, 129 insertions(+), 62 deletions(-)

diff --git a/pkg/gov/governance.go b/pkg/gov/governance.go
index dd8682a..a30b39c 100644
--- a/pkg/gov/governance.go
+++ b/pkg/gov/governance.go
@@ -22,12 +22,12 @@ package gov
 //Name is the policy name, for example: "rate-limit-payment-api"
 //MD is metadata.
 type GovernancePolicy struct {
-       Name       string   `json:"name,omitempty"`
-       ID         string   `json:"id,omitempty"`
-       Status     string   `json:"status,omitempty"`
-       CreatTime  int64    `json:"creatTime,omitempty"`
-       UpdateTime int64    `json:"updateTime,omitempty"`
-       Selector   Selector `json:"selector,omitempty"`
+       Name       string    `json:"name,omitempty"`
+       ID         string    `json:"id,omitempty"`
+       Status     string    `json:"status,omitempty"`
+       CreatTime  int64     `json:"creatTime,omitempty"`
+       UpdateTime int64     `json:"updateTime,omitempty"`
+       Selector   *Selector `json:"selector,omitempty"`
 }
 
 //DisplayData define display data
diff --git a/pkg/gov/governance_test.go b/pkg/gov/governance_test.go
index fbc9d3a..5e19d8d 100644
--- a/pkg/gov/governance_test.go
+++ b/pkg/gov/governance_test.go
@@ -47,7 +47,7 @@ func TestNewInstance(t *testing.T) {
                GovernancePolicy: &gov.GovernancePolicy{
                        Name: "traffic2adminAPI",
                        ID:   "",
-                       Selector: gov.Selector{
+                       Selector: &gov.Selector{
                                App:         "default",
                                Environment: "development",
                        },
diff --git a/server/resource/v1/gov_resource.go 
b/server/resource/v1/gov_resource.go
index 601ec3d..706e841 100644
--- a/server/resource/v1/gov_resource.go
+++ b/server/resource/v1/gov_resource.go
@@ -18,15 +18,16 @@
 package v1
 
 import (
+       "encoding/json"
        "io/ioutil"
        "net/http"
 
-       "github.com/apache/servicecomb-service-center/server/service/gov/kie"
-
+       model "github.com/apache/servicecomb-service-center/pkg/gov"
        "github.com/apache/servicecomb-service-center/pkg/log"
        "github.com/apache/servicecomb-service-center/pkg/rest"
        "github.com/apache/servicecomb-service-center/server/rest/controller"
        "github.com/apache/servicecomb-service-center/server/service/gov"
+       "github.com/apache/servicecomb-service-center/server/service/gov/kie"
        "github.com/go-chassis/cari/discovery"
 )
 
@@ -62,12 +63,14 @@ func (t *Governance) Create(w http.ResponseWriter, req 
*http.Request) {
                processError(w, err, "create gov data err")
                return
        }
-       _, err = w.Write(id)
+
+       policy := &model.Policy{GovernancePolicy: &model.GovernancePolicy{ID: 
string(id)}}
+       b, err := json.Marshal(policy)
        if err != nil {
-               processError(w, err, "")
+               processError(w, err, "marshal policy id response failed")
                return
        }
-       w.WriteHeader(http.StatusOK)
+       controller.WriteJSON(w, b)
 }
 
 //Put gov config
@@ -81,7 +84,7 @@ func (t *Governance) Put(w http.ResponseWriter, req 
*http.Request) {
                controller.WriteError(w, discovery.ErrInternal, err.Error())
                return
        }
-       err = gov.Update(id, kind, project, body)
+       err = gov.Update(kind, id, project, body)
        if err != nil {
                if _, ok := err.(*kie.ErrIllegalItem); ok {
                        log.Error("", err)
@@ -143,9 +146,10 @@ func (t *Governance) Get(w http.ResponseWriter, req 
*http.Request) {
 
 //Delete delete gov config
 func (t *Governance) Delete(w http.ResponseWriter, req *http.Request) {
+       kind := req.URL.Query().Get(KindKey)
        id := req.URL.Query().Get(IDKey)
        project := req.URL.Query().Get(ProjectKey)
-       err := gov.Delete(id, project)
+       err := gov.Delete(kind, id, project)
        if err != nil {
                processError(w, err, "delete gov err")
                return
diff --git a/server/service/gov/config_distributor.go 
b/server/service/gov/config_distributor.go
index 45d4c7e..d263715 100644
--- a/server/service/gov/config_distributor.go
+++ b/server/service/gov/config_distributor.go
@@ -39,8 +39,8 @@ var distributorPlugins = map[string]NewDistributors{}
 //ConfigDistributor will convert standard servicecomb gov config to concrete 
spec, that data plane can recognize.
 type ConfigDistributor interface {
        Create(kind, project string, spec []byte) ([]byte, error)
-       Update(id, kind, project string, spec []byte) error
-       Delete(id, project string) error
+       Update(kind, id, project string, spec []byte) error
+       Delete(kind, id, project string) error
        Display(project, app, env string) ([]byte, error)
        List(kind, project, app, env string) ([]byte, error)
        Get(kind, id, project string) ([]byte, error)
@@ -103,16 +103,16 @@ func Get(kind, id, project string) ([]byte, error) {
        return nil, nil
 }
 
-func Delete(id, project string) error {
+func Delete(kind, id, project string) error {
        for _, cd := range distributors {
-               return cd.Delete(id, project)
+               return cd.Delete(kind, id, project)
        }
        return nil
 }
 
-func Update(id, kind, project string, spec []byte) error {
+func Update(kind, id, project string, spec []byte) error {
        for _, cd := range distributors {
-               return cd.Update(id, kind, project, spec)
+               return cd.Update(kind, id, project, spec)
        }
        return nil
 }
diff --git a/server/service/gov/config_distributor_test.go 
b/server/service/gov/config_distributor_test.go
index 250f00c..d2e4529 100644
--- a/server/service/gov/config_distributor_test.go
+++ b/server/service/gov/config_distributor_test.go
@@ -57,22 +57,31 @@ func TestCreate(t *testing.T) {
        b, _ := json.MarshalIndent(&gov.Policy{
                GovernancePolicy: &gov.GovernancePolicy{
                        Name: "Traffic2adminAPI",
+                       Selector: &gov.Selector{
+                               App:         MockApp,
+                               Environment: MockEnv,
+                       },
                },
                Spec: &gov.LBSpec{RetryNext: 3, MarkerName: "traffic2adminAPI"},
        }, "", "  ")
        res, err := svc.Create(MockKind, Project, b)
        id = string(res)
        assert.NoError(t, err)
+       assert.NotEmpty(t, id)
 }
 
 func TestUpdate(t *testing.T) {
        b, _ := json.MarshalIndent(&gov.Policy{
                GovernancePolicy: &gov.GovernancePolicy{
                        Name: "Traffic2adminAPI",
+                       Selector: &gov.Selector{
+                               App:         MockApp,
+                               Environment: MockEnv,
+                       },
                },
                Spec: &gov.LBSpec{RetryNext: 3, MarkerName: "traffic2adminAPI"},
        }, "", "  ")
-       err := svc.Update(id, MockKind, Project, b)
+       err := svc.Update(MockKind, id, Project, b)
        assert.NoError(t, err)
 }
 
@@ -80,6 +89,10 @@ func TestDisplay(t *testing.T) {
        b, _ := json.MarshalIndent(&gov.Policy{
                GovernancePolicy: &gov.GovernancePolicy{
                        Name: "Traffic2adminAPI",
+                       Selector: &gov.Selector{
+                               App:         MockApp,
+                               Environment: MockEnv,
+                       },
                },
        }, "", "  ")
        res, err := svc.Create(MatchGroup, Project, b)
@@ -112,7 +125,7 @@ func TestGet(t *testing.T) {
 }
 
 func TestDelete(t *testing.T) {
-       err := svc.Delete(id, Project)
+       err := svc.Delete(MockKind, id, Project)
        assert.NoError(t, err)
        res, _ := svc.Get(MockKind, id, Project)
        assert.Nil(t, res)
diff --git a/server/service/gov/kie/kie_distributor.go 
b/server/service/gov/kie/kie_distributor.go
index fab563f..0d52473 100644
--- a/server/service/gov/kie/kie_distributor.go
+++ b/server/service/gov/kie/kie_distributor.go
@@ -38,20 +38,19 @@ import (
 )
 
 type Distributor struct {
-       lbPolicies map[string]*gov.Policy
-       name       string
-       client     *kie.Client
+       name   string
+       client *kie.Client
 }
 
 const (
-       PREFIX         = "servicecomb."
-       MatchGroup     = "match-group"
-       EnableStatus   = "enabled"
-       ValueType      = "text"
-       AppKey         = "app"
-       EnvironmentKey = "environment"
-       EnvAll         = "all"
-       BusinessPrefix = "scene-"
+       KeyPrefix       = "servicecomb."
+       KindMatchGroup  = "match-group"
+       GroupNamePrefix = "scene-"
+       StatusEnabled   = "enabled"
+       TypeText        = "text"
+       KeyApp          = "app"
+       KeyEnvironment  = "environment"
+       EnvAll          = "all"
 )
 
 var PolicyNames = []string{"retry", "rateLimiting", "circuitBreaker", 
"bulkhead"}
@@ -64,13 +63,13 @@ func (d *Distributor) Create(kind, project string, spec 
[]byte) ([]byte, error)
        if err != nil {
                return nil, err
        }
-       if kind == MatchGroup {
+       if kind == KindMatchGroup {
                err = d.generateID(project, p)
                if err != nil {
                        return nil, err
                }
        }
-       log.Info(fmt.Sprintf("create %v", &p))
+       log.Info(fmt.Sprintf("create %+v", p))
        err = rule.Validate(kind, p.Spec)
        if err != nil {
                return nil, err
@@ -80,23 +79,21 @@ func (d *Distributor) Create(kind, project string, spec 
[]byte) ([]byte, error)
                return nil, err
        }
        kv := kie.KVRequest{
-               Key:       PREFIX + toSnake(kind) + "." + p.Name,
+               Key:       toGovKeyPrefix(kind) + p.Name,
                Value:     string(yamlByte),
-               Status:    EnableStatus,
-               ValueType: ValueType,
-               Labels:    map[string]string{AppKey: p.Selector.App, 
EnvironmentKey: p.Selector.Environment},
+               Status:    StatusEnabled,
+               ValueType: TypeText,
+               Labels:    map[string]string{KeyApp: p.Selector.App, 
KeyEnvironment: p.Selector.Environment},
        }
        res, err := d.client.Create(context.TODO(), kv, 
kie.WithProject(project))
        if err != nil {
                log.Error("kie create failed", err)
                return nil, err
        }
-       d.lbPolicies[p.GovernancePolicy.Name] = p
-       b, _ := json.MarshalIndent(res.ID, "", "  ")
-       return b, nil
+       return []byte(res.ID), nil
 }
 
-func (d *Distributor) Update(id, kind, project string, spec []byte) error {
+func (d *Distributor) Update(kind, id, project string, spec []byte) error {
        p := &gov.Policy{}
        err := json.Unmarshal(spec, p)
        if err != nil {
@@ -121,11 +118,15 @@ func (d *Distributor) Update(id, kind, project string, 
spec []byte) error {
                log.Error("kie update failed", err)
                return err
        }
-       d.lbPolicies[p.GovernancePolicy.Name] = p
        return nil
 }
 
-func (d *Distributor) Delete(id, project string) error {
+func (d *Distributor) Delete(kind, id, project string) error {
+       if kind == KindMatchGroup {
+               // should remove all policies of this group
+               return d.DeleteMatchGroup(id, project)
+       }
+
        err := d.client.Delete(context.TODO(), id, kie.WithProject(project))
        if err != nil {
                log.Error("kie delete failed", err)
@@ -134,8 +135,41 @@ func (d *Distributor) Delete(id, project string) error {
        return nil
 }
 
+func (d *Distributor) DeleteMatchGroup(id string, project string) error {
+       policy, err := d.getPolicy(KindMatchGroup, id, project)
+       if err != nil {
+               log.Error("kie get failed", err)
+               return err
+       }
+
+       ops := []kie.GetOption{
+               kie.WithKey("wildcard(" + KeyPrefix + "*." + policy.Name + ")"),
+               kie.WithRevision(0),
+               kie.WithGetProject(project),
+       }
+       idList, _, err := d.client.List(context.TODO(), ops...)
+       if err != nil {
+               log.Error("kie list failed", err)
+               return err
+       }
+       var ids string
+       for _, res := range idList.Data {
+               ids += res.ID + ","
+       }
+       if len(ids) == 0 {
+               return nil
+       }
+
+       err = d.client.Delete(context.TODO(), ids[:len(ids)-1])
+       if err != nil {
+               log.Error("kie list failed", err)
+               return err
+       }
+       return nil
+}
+
 func (d *Distributor) Display(project, app, env string) ([]byte, error) {
-       list, _, err := d.listDataByKind(MatchGroup, project, app, env)
+       list, _, err := d.listDataByKind(KindMatchGroup, project, app, env)
        if err != nil {
                return nil, err
        }
@@ -155,7 +189,7 @@ func (d *Distributor) Display(project, app, env string) 
([]byte, error) {
        }
        r := make([]*gov.DisplayData, 0, list.Total)
        for _, item := range list.Data {
-               match, err := d.transform(item, MatchGroup)
+               match, err := d.transform(item, KindMatchGroup)
                if err != nil {
                        return nil, err
                }
@@ -193,6 +227,15 @@ func (d *Distributor) List(kind, project, app, env string) 
([]byte, error) {
 }
 
 func (d *Distributor) Get(kind, id, project string) ([]byte, error) {
+       policy, err := d.getPolicy(kind, id, project)
+       if err != nil {
+               return nil, err
+       }
+       b, _ := json.MarshalIndent(policy, "", "  ")
+       return b, nil
+}
+
+func (d *Distributor) getPolicy(kind string, id string, project string) 
(*gov.Policy, error) {
        kv, err := d.client.Get(context.TODO(), id, kie.WithGetProject(project))
        if err != nil {
                return nil, err
@@ -201,8 +244,7 @@ func (d *Distributor) Get(kind, id, project string) 
([]byte, error) {
        if err != nil {
                return nil, err
        }
-       b, _ := json.MarshalIndent(policy, "", "  ")
-       return b, nil
+       return policy, nil
 }
 
 func (d *Distributor) Type() string {
@@ -224,7 +266,7 @@ func initClient(endpoint string) *kie.Client {
 }
 
 func new(opts config.DistributorOptions) (svc.ConfigDistributor, error) {
-       return &Distributor{name: opts.Name, lbPolicies: 
map[string]*gov.Policy{}, client: initClient(opts.Endpoint)}, nil
+       return &Distributor{name: opts.Name, client: 
initClient(opts.Endpoint)}, nil
 }
 
 func toSnake(name string) string {
@@ -251,16 +293,16 @@ func toSnake(name string) string {
 
 func (d *Distributor) listDataByKind(kind, project, app, env string) 
(*kie.KVResponse, int, error) {
        ops := []kie.GetOption{
-               kie.WithKey("beginWith(" + PREFIX + toSnake(kind) + ")"),
+               kie.WithKey("beginWith(" + toGovKeyPrefix(kind) + ")"),
                kie.WithRevision(0),
                kie.WithGetProject(project),
        }
        labels := map[string]string{}
        if env != EnvAll {
-               labels[EnvironmentKey] = env
+               labels[KeyEnvironment] = env
        }
        if app != "" {
-               labels[AppKey] = app
+               labels[KeyApp] = app
        }
        if len(labels) > 0 {
                ops = append(ops, kie.WithLabels(labels))
@@ -272,7 +314,8 @@ func (d *Distributor) generateID(project string, p 
*gov.Policy) error {
        if p.Name != "" {
                return nil
        }
-       list, _, err := d.listDataByKind(MatchGroup, project, p.Selector.App, 
p.Selector.Environment)
+       kind := KindMatchGroup
+       list, _, err := d.listDataByKind(kind, project, p.Selector.App, 
p.Selector.Environment)
        if err != nil {
                return err
        }
@@ -280,8 +323,9 @@ func (d *Distributor) generateID(project string, p 
*gov.Policy) error {
        for {
                var repeat bool
                id = getID()
+               govKey := toGovKeyPrefix(kind) + id
                for _, datum := range list.Data {
-                       if id == MatchGroup+datum.Key {
+                       if govKey == datum.Key {
                                repeat = true
                                break
                        }
@@ -302,12 +346,14 @@ func getID() string {
        for i := 0; i < 4; i++ {
                result = append(result, b[r.Intn(len(b))])
        }
-       return BusinessPrefix + string(result)
+       return GroupNamePrefix + string(result)
 }
 
 func (d *Distributor) transform(kv *kie.KVDoc, kind string) (*gov.Policy, 
error) {
        goc := &gov.Policy{
-               GovernancePolicy: &gov.GovernancePolicy{},
+               GovernancePolicy: &gov.GovernancePolicy{
+                       Selector: &gov.Selector{},
+               },
        }
        spec := make(map[string]interface{})
        specJSON, _ := yaml.YAMLToJSON([]byte(kv.Value))
@@ -321,13 +367,17 @@ func (d *Distributor) transform(kv *kie.KVDoc, kind 
string) (*gov.Policy, error)
        goc.Status = kv.Status
        goc.Name = kv.Key[strings.LastIndex(kv.Key, ".")+1 : len(kv.Key)]
        goc.Spec = spec
-       goc.Selector.App = kv.Labels[AppKey]
-       goc.Selector.Environment = kv.Labels[EnvironmentKey]
+       goc.Selector.App = kv.Labels[KeyApp]
+       goc.Selector.Environment = kv.Labels[KeyEnvironment]
        goc.CreatTime = kv.CreatTime
        goc.UpdateTime = kv.UpdateTime
        return goc, nil
 }
 
+func toGovKeyPrefix(kind string) string {
+       return KeyPrefix + toSnake(kind) + "."
+}
+
 func init() {
        svc.InstallDistributor(svc.ConfigDistributorKie, new)
 }
diff --git a/server/service/gov/mock/mock.go b/server/service/gov/mock/mock.go
index bdf34ca..3432c85 100644
--- a/server/service/gov/mock/mock.go
+++ b/server/service/gov/mock/mock.go
@@ -48,7 +48,7 @@ func (d *Distributor) Create(kind, project string, spec 
[]byte) ([]byte, error)
        return []byte(p.ID), err
 }
 
-func (d *Distributor) Update(id, kind, project string, spec []byte) error {
+func (d *Distributor) Update(kind, id, project string, spec []byte) error {
        if d.lbPolicies[id] == nil {
                return fmt.Errorf("id not exsit")
        }
@@ -61,7 +61,7 @@ func (d *Distributor) Update(id, kind, project string, spec 
[]byte) error {
        return err
 }
 
-func (d *Distributor) Delete(id, project string) error {
+func (d *Distributor) Delete(kind, id, project string) error {
        delete(d.lbPolicies, id)
        return nil
 }
@@ -107,7 +107,7 @@ func (d *Distributor) List(kind, project, app, env string) 
([]byte, error) {
 }
 
 func checkPolicy(g *gov.Policy, kind, app, env string) bool {
-       return g.Kind == kind && g.Selector.App == app && 
g.Selector.Environment == env
+       return g.Kind == kind && g.Selector != nil && g.Selector.App == app && 
g.Selector.Environment == env
 }
 
 func (d *Distributor) Get(kind, id, project string) ([]byte, error) {

Reply via email to