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) {