You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by li...@apache.org on 2021/09/10 13:38:32 UTC
[servicecomb-service-center] branch master updated: Fix: Add
Dependency API (#1151)
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 426e92a Fix: Add Dependency API (#1151)
426e92a is described below
commit 426e92a8e96ddcdbb2a6a043862ff47759a0613d
Author: little-cui <su...@qq.com>
AuthorDate: Fri Sep 10 21:38:26 2021 +0800
Fix: Add Dependency API (#1151)
---
datasource/dep.go | 3 +
datasource/dep_test.go | 341 ++++++++++++++++
datasource/dependency_util.go | 14 +-
datasource/etcd/dep.go | 73 +++-
datasource/etcd/event/dependency_event_handler.go | 16 +-
datasource/etcd/ms.go | 2 +-
datasource/etcd/util/dependency_util.go | 58 +--
datasource/etcd/util/dependency_util_test.go | 50 ---
datasource/mongo/dep.go | 64 ++-
integration/apis.go | 1 +
integration/microservices_test.go | 268 +++++++++++-
pkg/proto/service.go | 2 +
server/rest/controller/v4/dependency_controller.go | 55 +++
server/service/disco/dependency.go | 24 ++
server/service/disco/dependency_test.go | 451 +++++++++++++++++++--
server/service/validator/dependency_validator.go | 70 ++++
server/service/validator/validator.go | 4 +
17 files changed, 1365 insertions(+), 131 deletions(-)
diff --git a/datasource/dep.go b/datasource/dep.go
index d3cee31..a8e430d 100644
--- a/datasource/dep.go
+++ b/datasource/dep.go
@@ -23,9 +23,12 @@ import (
pb "github.com/go-chassis/cari/discovery"
)
+const AllVersions = "0.0.0+"
+
// DependencyManager contains the CRUD of microservice dependencies
type DependencyManager interface {
SearchProviderDependency(ctx context.Context, request *pb.GetDependenciesRequest) (*pb.GetProDependenciesResponse, error)
SearchConsumerDependency(ctx context.Context, request *pb.GetDependenciesRequest) (*pb.GetConDependenciesResponse, error)
+ AddOrUpdateDependencies(ctx context.Context, dependencyInfos []*pb.ConsumerDependency, override bool) (*pb.Response, error)
DependencyHandle(ctx context.Context) error
}
diff --git a/datasource/dep_test.go b/datasource/dep_test.go
index 435d881..da5daba 100644
--- a/datasource/dep_test.go
+++ b/datasource/dep_test.go
@@ -27,6 +27,292 @@ import (
"github.com/stretchr/testify/assert"
)
+func Test_Create(t *testing.T) {
+ var (
+ consumerId1 string
+ consumerId2 string
+ )
+ resp, err := datasource.GetMetadataManager().RegisterService(depGetContext(), &pb.CreateServiceRequest{
+ Service: &pb.MicroService{
+ AppId: "dep_create_dep_group",
+ ServiceName: "dep_create_dep_consumer",
+ Version: "1.0.0",
+ Level: "FRONT",
+ Status: pb.MS_UP,
+ },
+ })
+ assert.NotNil(t, resp)
+ assert.NoError(t, err)
+ assert.Equal(t, pb.ResponseSuccess, resp.Response.GetCode())
+ consumerId1 = resp.ServiceId
+ defer datasource.GetMetadataManager().UnregisterService(depGetContext(), &pb.DeleteServiceRequest{ServiceId: resp.ServiceId, Force: true})
+
+ resp, err = datasource.GetMetadataManager().RegisterService(depGetContext(), &pb.CreateServiceRequest{
+ Service: &pb.MicroService{
+ Environment: pb.ENV_PROD,
+ AppId: "dep_create_dep_group",
+ ServiceName: "dep_create_dep_consumer",
+ Version: "1.0.0",
+ Level: "FRONT",
+ Status: pb.MS_UP,
+ },
+ })
+ assert.NotNil(t, resp)
+ assert.NoError(t, err)
+ assert.Equal(t, pb.ResponseSuccess, resp.Response.GetCode())
+ consumerId2 = resp.ServiceId
+ defer datasource.GetMetadataManager().UnregisterService(depGetContext(), &pb.DeleteServiceRequest{ServiceId: resp.ServiceId, Force: true})
+
+ resp, err = datasource.GetMetadataManager().RegisterService(depGetContext(), &pb.CreateServiceRequest{
+ Service: &pb.MicroService{
+ AppId: "dep_create_dep_group",
+ ServiceName: "dep_create_dep_provider",
+ Version: "1.0.0",
+ Level: "FRONT",
+ Status: pb.MS_UP,
+ },
+ })
+ assert.NotNil(t, resp)
+ assert.NoError(t, err)
+ assert.Equal(t, pb.ResponseSuccess, resp.Response.GetCode())
+ defer datasource.GetMetadataManager().UnregisterService(depGetContext(), &pb.DeleteServiceRequest{ServiceId: resp.ServiceId, Force: true})
+
+ resp, err = datasource.GetMetadataManager().RegisterService(depGetContext(), &pb.CreateServiceRequest{
+ Service: &pb.MicroService{
+ AppId: "dep_create_dep_group",
+ ServiceName: "dep_create_dep_provider",
+ Version: "1.0.1",
+ Level: "FRONT",
+ Status: pb.MS_UP,
+ },
+ })
+ assert.NotNil(t, resp)
+ assert.NoError(t, err)
+ assert.Equal(t, pb.ResponseSuccess, resp.Response.GetCode())
+ defer datasource.GetMetadataManager().UnregisterService(depGetContext(), &pb.DeleteServiceRequest{ServiceId: resp.ServiceId, Force: true})
+
+ resp, err = datasource.GetMetadataManager().RegisterService(depGetContext(), &pb.CreateServiceRequest{
+ Service: &pb.MicroService{
+ AppId: "dep_create_dep_group",
+ ServiceName: "dep_create_dep_provider_other",
+ Version: "1.0.0",
+ Level: "FRONT",
+ Status: pb.MS_UP,
+ },
+ })
+ assert.NotNil(t, resp)
+ assert.NoError(t, err)
+ assert.Equal(t, pb.ResponseSuccess, resp.Response.GetCode())
+ defer datasource.GetMetadataManager().UnregisterService(depGetContext(), &pb.DeleteServiceRequest{ServiceId: resp.ServiceId, Force: true})
+
+ resp, err = datasource.GetMetadataManager().RegisterService(depGetContext(), &pb.CreateServiceRequest{
+ Service: &pb.MicroService{
+ Environment: pb.ENV_PROD,
+ AppId: "dep_create_dep_group",
+ ServiceName: "dep_create_dep_provider",
+ Version: "1.0.0",
+ Level: "FRONT",
+ Status: pb.MS_UP,
+ },
+ })
+ assert.NotNil(t, resp)
+ assert.NoError(t, err)
+ assert.Equal(t, pb.ResponseSuccess, resp.Response.GetCode())
+ defer datasource.GetMetadataManager().UnregisterService(depGetContext(), &pb.DeleteServiceRequest{ServiceId: resp.ServiceId, Force: true})
+
+ t.Run("add dep and search when request is invalid, should be failed", func(t *testing.T) {
+ consumer := &pb.MicroServiceKey{
+ AppId: "dep_create_dep_group",
+ ServiceName: "dep_create_dep_consumer",
+ Version: "1.0.0",
+ }
+ providers := []*pb.MicroServiceKey{
+ {
+ AppId: "dep_create_dep_group",
+ ServiceName: "dep_create_dep_provider",
+ },
+ }
+
+ // consumer does not exist
+ resp, err := datasource.GetDependencyManager().AddOrUpdateDependencies(depGetContext(), []*pb.ConsumerDependency{
+ {
+ Consumer: &pb.MicroServiceKey{
+ AppId: "noexistapp",
+ ServiceName: "noexistservice",
+ Version: "1.0.0",
+ },
+ Providers: providers,
+ },
+ }, false)
+ assert.NotNil(t, resp)
+ assert.NoError(t, err)
+ assert.Equal(t, pb.ErrServiceNotExists, resp.GetCode())
+
+ err = datasource.GetDependencyManager().DependencyHandle(getContext())
+ assert.NoError(t, err)
+
+ // provider in diff env
+ resp, err = datasource.GetDependencyManager().AddOrUpdateDependencies(depGetContext(), []*pb.ConsumerDependency{
+ {
+ Consumer: consumer,
+ Providers: []*pb.MicroServiceKey{
+ {
+ Environment: pb.ENV_PROD,
+ AppId: "dep_service_group_provider",
+ ServiceName: "dep_service_name_provider",
+ },
+ },
+ },
+ }, false)
+ assert.NotNil(t, resp)
+ assert.NoError(t, err)
+ assert.Equal(t, pb.ResponseSuccess, resp.GetCode())
+
+ //consumer in diff env
+ consumer.Environment = pb.ENV_PROD
+ resp, err = datasource.GetDependencyManager().AddOrUpdateDependencies(depGetContext(), []*pb.ConsumerDependency{
+ {
+ Consumer: consumer,
+ Providers: []*pb.MicroServiceKey{
+ {
+ AppId: "dep_service_group_provider",
+ ServiceName: "dep_service_name_provider",
+ },
+ },
+ },
+ }, false)
+ assert.NotNil(t, resp)
+ assert.NoError(t, err)
+ assert.Equal(t, pb.ResponseSuccess, resp.GetCode())
+
+ err = datasource.GetDependencyManager().DependencyHandle(getContext())
+ assert.NoError(t, err)
+
+ respCon, err := datasource.GetDependencyManager().SearchConsumerDependency(depGetContext(), &pb.GetDependenciesRequest{
+ ServiceId: consumerId1,
+ })
+ assert.NotNil(t, respCon)
+ assert.NoError(t, err)
+ assert.Equal(t, 0, len(respCon.Providers))
+
+ respCon, err = datasource.GetDependencyManager().SearchConsumerDependency(depGetContext(), &pb.GetDependenciesRequest{
+ ServiceId: consumerId2,
+ })
+ assert.NotNil(t, respCon)
+ assert.NoError(t, err)
+ assert.Equal(t, 0, len(respCon.Providers))
+ })
+
+ t.Run("add dep and search when request is valid, should be passed", func(t *testing.T) {
+ consumer := &pb.MicroServiceKey{
+ ServiceName: "dep_create_dep_consumer",
+ AppId: "dep_create_dep_group",
+ Version: "1.0.0",
+ }
+
+ resp, err := datasource.GetDependencyManager().AddOrUpdateDependencies(depGetContext(), []*pb.ConsumerDependency{
+ {
+ Consumer: consumer,
+ Providers: []*pb.MicroServiceKey{
+ {
+ AppId: "dep_create_dep_group",
+ ServiceName: "dep_create_dep_provider",
+ },
+ },
+ },
+ }, false)
+ assert.NotNil(t, resp)
+ assert.NoError(t, err)
+ assert.Equal(t, pb.ResponseSuccess, resp.GetCode())
+
+ err = datasource.GetDependencyManager().DependencyHandle(getContext())
+ assert.NoError(t, err)
+
+ respPro, err := datasource.GetDependencyManager().SearchConsumerDependency(depGetContext(), &pb.GetDependenciesRequest{
+ ServiceId: consumerId1,
+ })
+ assert.NotNil(t, respPro)
+ assert.NoError(t, err)
+ assert.Equal(t, 2, len(respPro.Providers))
+
+ // add multiple providers
+ resp, err = datasource.GetDependencyManager().AddOrUpdateDependencies(depGetContext(), []*pb.ConsumerDependency{
+ {
+ Consumer: consumer,
+ Providers: []*pb.MicroServiceKey{
+ {
+ AppId: "dep_create_dep_group",
+ ServiceName: "dep_create_dep_provider",
+ },
+ {
+ AppId: "dep_create_dep_group",
+ ServiceName: "dep_create_dep_provider_other",
+ },
+ },
+ },
+ }, false)
+ assert.NotNil(t, resp)
+ assert.NoError(t, err)
+ assert.Equal(t, pb.ResponseSuccess, resp.GetCode())
+
+ err = datasource.GetDependencyManager().DependencyHandle(getContext())
+ assert.NoError(t, err)
+
+ respPro, err = datasource.GetDependencyManager().SearchConsumerDependency(depGetContext(), &pb.GetDependenciesRequest{
+ ServiceId: consumerId1,
+ })
+ assert.NotNil(t, respPro)
+ assert.NoError(t, err)
+ assert.Equal(t, 3, len(respPro.Providers))
+
+ // override
+ resp, err = datasource.GetDependencyManager().AddOrUpdateDependencies(depGetContext(), []*pb.ConsumerDependency{
+ {
+ Consumer: consumer,
+ Providers: []*pb.MicroServiceKey{
+ {
+ AppId: "dep_create_dep_group",
+ ServiceName: "dep_create_dep_provider",
+ },
+ },
+ },
+ }, true)
+ assert.NotNil(t, resp)
+ assert.NoError(t, err)
+ assert.Equal(t, pb.ResponseSuccess, resp.GetCode())
+ err = datasource.GetDependencyManager().DependencyHandle(getContext())
+ assert.NoError(t, err)
+
+ respPro, err = datasource.GetDependencyManager().SearchConsumerDependency(depGetContext(), &pb.GetDependenciesRequest{
+ ServiceId: consumerId1,
+ })
+ assert.NotNil(t, respPro)
+ assert.NoError(t, err)
+ assert.Equal(t, 2, len(respPro.Providers))
+
+ // clean all
+ resp, err = datasource.GetDependencyManager().AddOrUpdateDependencies(depGetContext(), []*pb.ConsumerDependency{
+ {
+ Consumer: consumer,
+ Providers: nil,
+ },
+ }, true)
+ assert.NotNil(t, resp)
+ assert.NoError(t, err)
+ assert.Equal(t, pb.ResponseSuccess, resp.GetCode())
+
+ err = datasource.GetDependencyManager().DependencyHandle(getContext())
+ assert.NoError(t, err)
+
+ respPro, err = datasource.GetDependencyManager().SearchConsumerDependency(depGetContext(), &pb.GetDependenciesRequest{
+ ServiceId: consumerId1,
+ })
+ assert.NotNil(t, respPro)
+ assert.NoError(t, err)
+ assert.Equal(t, 0, len(respPro.Providers))
+ })
+}
+
func Test_Get(t *testing.T) {
var (
consumerId1 string
@@ -243,3 +529,58 @@ func Test_Get(t *testing.T) {
func depGetContext() context.Context {
return util.WithNoCache(util.SetDomainProject(context.Background(), "new_default", "new_default"))
}
+
+func TestParamsChecker(t *testing.T) {
+ p := datasource.ParamsChecker(nil, nil)
+ assert.Nil(t, p)
+
+ p = datasource.ParamsChecker(&pb.MicroServiceKey{
+ AppId: "a",
+ ServiceName: "b",
+ Version: "1.0.0",
+ }, nil)
+ assert.Nil(t, p)
+
+ producer := &pb.MicroServiceKey{ServiceName: "*"}
+ p = datasource.ParamsChecker(&pb.MicroServiceKey{
+ AppId: "a",
+ ServiceName: "b",
+ Version: "1.0.0",
+ }, []*pb.MicroServiceKey{
+ producer,
+ })
+ assert.Nil(t, p)
+ assert.Equal(t, "a", producer.AppId)
+ assert.Equal(t, "0.0.0+", producer.Version)
+
+ producer.ServiceName = "a"
+ producer.Version = "1"
+ p = datasource.ParamsChecker(&pb.MicroServiceKey{
+ AppId: "a",
+ ServiceName: "b",
+ Version: "1.0.0",
+ }, []*pb.MicroServiceKey{
+ producer,
+ })
+ assert.Nil(t, p)
+ assert.Equal(t, "0.0.0+", producer.Version)
+
+ p = datasource.ParamsChecker(&pb.MicroServiceKey{
+ AppId: "a",
+ ServiceName: "b",
+ Version: "1.0.0",
+ }, []*pb.MicroServiceKey{
+ {},
+ })
+ assert.NotNil(t, p)
+
+ p = datasource.ParamsChecker(&pb.MicroServiceKey{
+ AppId: "a",
+ ServiceName: "b",
+ Version: "1.0.0",
+ }, []*pb.MicroServiceKey{
+ {ServiceName: "a", Version: "1"},
+ {ServiceName: "a", Version: "1"},
+ })
+ assert.NotNil(t, p)
+}
diff --git a/datasource/dependency_util.go b/datasource/dependency_util.go
index 6733fbc..f57ce4f 100644
--- a/datasource/dependency_util.go
+++ b/datasource/dependency_util.go
@@ -43,25 +43,17 @@ type Dependency struct {
func ParamsChecker(consumerInfo *discovery.MicroServiceKey, providersInfo []*discovery.MicroServiceKey) *discovery.CreateDependenciesResponse {
flag := make(map[string]bool, len(providersInfo))
for _, providerInfo := range providersInfo {
- //存在带*的情况,后面的数据就不校验了
- if providerInfo.ServiceName == "*" {
- break
+ if len(providerInfo.ServiceName) == 0 {
+ return BadParamsResponse("Required provider serviceName")
}
if len(providerInfo.AppId) == 0 {
providerInfo.AppId = consumerInfo.AppId
}
-
- version := providerInfo.Version
- if len(version) == 0 {
- return BadParamsResponse("Required provider version")
- }
-
- providerInfo.Version = ""
+ providerInfo.Version = AllVersions
if _, ok := flag[toString(providerInfo)]; ok {
return BadParamsResponse("Invalid request body for provider info.Duplicate provider or (serviceName and appId is same).")
}
flag[toString(providerInfo)] = true
- providerInfo.Version = version
}
return nil
}
diff --git a/datasource/etcd/dep.go b/datasource/etcd/dep.go
index 884aedb..ba3c837 100644
--- a/datasource/etcd/dep.go
+++ b/datasource/etcd/dep.go
@@ -19,6 +19,7 @@ package etcd
import (
"context"
+ "encoding/json"
"errors"
"fmt"
@@ -104,17 +105,71 @@ func (dm *DepManager) DependencyHandle(ctx context.Context) error {
if err != nil {
return err
}
- for {
- key := path.GetServiceDependencyQueueRootKey("")
- resp, err := sd.DependencyQueue().Search(ctx,
- etcdadpt.WithStrKey(key), etcdadpt.WithPrefix(), etcdadpt.WithCountOnly())
+
+ key := path.GetServiceDependencyQueueRootKey("")
+ resp, err := sd.DependencyQueue().Search(ctx,
+ etcdadpt.WithStrKey(key), etcdadpt.WithPrefix(), etcdadpt.WithCountOnly())
+ if err != nil {
+ return err
+ }
+ // maintain dependency rules.
+ if resp.Count != 0 {
+ return fmt.Errorf("residual records[%d]", resp.Count)
+ }
+ return nil
+}
+
+func (dm *DepManager) AddOrUpdateDependencies(ctx context.Context, dependencyInfos []*pb.ConsumerDependency, override bool) (*pb.Response, error) {
+ opts := make([]etcdadpt.OpOptions, 0, len(dependencyInfos))
+ domainProject := util.ParseDomainProject(ctx)
+ for _, dependencyInfo := range dependencyInfos {
+ consumerFlag := util.StringJoin([]string{dependencyInfo.Consumer.Environment, dependencyInfo.Consumer.AppId, dependencyInfo.Consumer.ServiceName, dependencyInfo.Consumer.Version}, "/")
+ consumerInfo := pb.DependenciesToKeys([]*pb.MicroServiceKey{dependencyInfo.Consumer}, domainProject)[0]
+ providersInfo := pb.DependenciesToKeys(dependencyInfo.Providers, domainProject)
+
+ rsp := datasource.ParamsChecker(consumerInfo, providersInfo)
+ if rsp != nil {
+ log.Error(fmt.Sprintf("put request into dependency queue failed, override: %t, consumer is %s, %s",
+ override, consumerFlag, rsp.Response.GetMessage()), nil)
+ return rsp.Response, nil
+ }
+
+ consumerID, err := serviceUtil.GetServiceID(ctx, consumerInfo)
+ if err != nil {
+ log.Error(fmt.Sprintf("put request into dependency queue failed, override: %t, get consumer[%s] id failed",
+ override, consumerFlag), err)
+ return pb.CreateResponse(pb.ErrInternal, err.Error()), err
+ }
+ if len(consumerID) == 0 {
+ log.Error(fmt.Sprintf("put request into dependency queue failed, override: %t, consumer[%s] does not exist",
+ override, consumerFlag), nil)
+ return pb.CreateResponse(pb.ErrServiceNotExists, fmt.Sprintf("Consumer %s does not exist.", consumerFlag)), nil
+ }
+
+ dependencyInfo.Override = override
+ data, err := json.Marshal(dependencyInfo)
if err != nil {
- return err
+ log.Error(fmt.Sprintf("put request into dependency queue failed, override: %t, marshal consumer[%s] dependency failed",
+ override, consumerFlag), err)
+ return pb.CreateResponse(pb.ErrInternal, err.Error()), err
}
- // maintain dependency rules.
- if resp.Count == 0 {
- break
+
+ id := path.DepsQueueUUID
+ if !override {
+ id = util.GenerateUUID()
}
+ key := path.GenerateConsumerDependencyQueueKey(domainProject, consumerID, id)
+ opts = append(opts, etcdadpt.OpPut(etcdadpt.WithStrKey(key), etcdadpt.WithValue(data)))
}
- return nil
+
+ err := etcdadpt.Txn(ctx, opts)
+ if err != nil {
+ log.Error(fmt.Sprintf("put request into dependency queue failed, override: %t, %v",
+ override, dependencyInfos), err)
+ return pb.CreateResponse(pb.ErrInternal, err.Error()), err
+ }
+
+ log.Info(fmt.Sprintf("put request into dependency queue successfully, override: %t, %v, from remote %s",
+ override, dependencyInfos, util.GetIPFromContext(ctx)))
+ return pb.CreateResponse(pb.ResponseSuccess, "Create dependency successfully."), nil
}
diff --git a/datasource/etcd/event/dependency_event_handler.go b/datasource/etcd/event/dependency_event_handler.go
index 8a78baa..8a427d4 100644
--- a/datasource/etcd/event/dependency_event_handler.go
+++ b/datasource/etcd/event/dependency_event_handler.go
@@ -149,7 +149,10 @@ func (h *DependencyEventHandler) Handle() error {
key := path.GetServiceDependencyQueueRootKey("")
resp, err := sd.DependencyQueue().Search(context.Background(), etcdadpt.WithNoCache(),
- etcdadpt.WithStrKey(key), etcdadpt.WithPrefix())
+ etcdadpt.WithStrKey(key), etcdadpt.WithPrefix(),
+ etcdadpt.WithOrderByCreate(), etcdadpt.WithAscendOrder(),
+ // get one page
+ etcdadpt.WithLimit(etcdadpt.DefaultPageCount))
if err != nil {
return err
}
@@ -193,11 +196,18 @@ func (h *DependencyEventHandler) dependencyRuleHandle(res interface{}) error {
consumerInfo := pb.DependenciesToKeys([]*pb.MicroServiceKey{r.Consumer}, domainProject)[0]
providersInfo := pb.DependenciesToKeys(r.Providers, domainProject)
- var dep serviceUtil.Dependency
+ var (
+ dep serviceUtil.Dependency
+ err error
+ )
dep.DomainProject = domainProject
dep.Consumer = consumerInfo
dep.ProvidersRule = providersInfo
- err := serviceUtil.AddDependencyRule(ctx, &dep)
+ if r.Override {
+ err = serviceUtil.CreateDependencyRule(ctx, &dep)
+ } else {
+ err = serviceUtil.AddDependencyRule(ctx, &dep)
+ }
if err != nil {
log.Error(fmt.Sprintf("modify dependency rule failed, override: %t, consumer %s", r.Override, consumerFlag), err)
return fmt.Errorf("override: %t, consumer is %s, %s", r.Override, consumerFlag, err.Error())
diff --git a/datasource/etcd/ms.go b/datasource/etcd/ms.go
index ad1b78e..b2c5a4f 100644
--- a/datasource/etcd/ms.go
+++ b/datasource/etcd/ms.go
@@ -1020,7 +1020,7 @@ func (ds *MetadataManager) reshapeProviderKey(ctx context.Context, provider *pb.
}
provider = pb.MicroServiceToKey(provider.Tenant, providerService)
- provider.Version = "0.0.0+" // just compatible to old version
+ provider.Version = datasource.AllVersions // just compatible to old version
return provider, nil
}
diff --git a/datasource/etcd/util/dependency_util.go b/datasource/etcd/util/dependency_util.go
index 48caebc..b03debb 100644
--- a/datasource/etcd/util/dependency_util.go
+++ b/datasource/etcd/util/dependency_util.go
@@ -201,6 +201,34 @@ func parseAddOrUpdateRules(ctx context.Context, dep *Dependency) (createDependen
return
}
+func parseOverrideRules(ctx context.Context, dep *Dependency) (createDependencyRuleList, existDependencyRuleList, deleteDependencyRuleList []*pb.MicroServiceKey) {
+ conKey := path.GenerateConsumerDependencyRuleKey(dep.DomainProject, dep.Consumer)
+
+ oldProviderRules, err := TransferToMicroServiceDependency(ctx, conKey)
+ if err != nil {
+ log.Error(fmt.Sprintf("override dependency rule failed, get consumer[%s/%s/%s/%s]'s dependency rule failed",
+ dep.Consumer.Environment, dep.Consumer.AppId, dep.Consumer.ServiceName, dep.Consumer.Version), err)
+ return
+ }
+
+ deleteDependencyRuleList = make([]*pb.MicroServiceKey, 0, len(oldProviderRules.Dependency))
+ createDependencyRuleList = make([]*pb.MicroServiceKey, 0, len(dep.ProvidersRule))
+ existDependencyRuleList = make([]*pb.MicroServiceKey, 0, len(oldProviderRules.Dependency))
+ for _, oldProviderRule := range oldProviderRules.Dependency {
+ if ok, _ := ContainServiceDependency(dep.ProvidersRule, oldProviderRule); !ok {
+ deleteDependencyRuleList = append(deleteDependencyRuleList, oldProviderRule)
+ } else {
+ existDependencyRuleList = append(existDependencyRuleList, oldProviderRule)
+ }
+ }
+ for _, tmpProviderRule := range dep.ProvidersRule {
+ if ok, _ := ContainServiceDependency(existDependencyRuleList, tmpProviderRule); !ok {
+ createDependencyRuleList = append(createDependencyRuleList, tmpProviderRule)
+ }
+ }
+ return
+}
+
func syncDependencyRule(ctx context.Context, dep *Dependency, filter func(context.Context, *Dependency) (_, _, _ []*pb.MicroServiceKey)) error {
//更新consumer的providers的值,consumer的版本是确定的
consumerFlag := strings.Join([]string{dep.Consumer.Environment, dep.Consumer.AppId, dep.Consumer.ServiceName, dep.Consumer.Version}, "/")
@@ -227,6 +255,10 @@ func AddDependencyRule(ctx context.Context, dep *Dependency) error {
return syncDependencyRule(ctx, dep, parseAddOrUpdateRules)
}
+func CreateDependencyRule(ctx context.Context, dep *Dependency) error {
+ return syncDependencyRule(ctx, dep, parseOverrideRules)
+}
+
func IsNeedUpdate(services []*pb.MicroServiceKey, service *pb.MicroServiceKey) *pb.MicroServiceKey {
for _, tmp := range services {
if DiffServiceVersion(tmp, service) {
@@ -259,32 +291,6 @@ func BadParamsResponse(detailErr string) *pb.CreateDependenciesResponse {
}
}
-func ParamsChecker(consumerInfo *pb.MicroServiceKey, providersInfo []*pb.MicroServiceKey) *pb.CreateDependenciesResponse {
- flag := make(map[string]bool, len(providersInfo))
- for _, providerInfo := range providersInfo {
- //存在带*的情况,后面的数据就不校验了
- if providerInfo.ServiceName == "*" {
- break
- }
- if len(providerInfo.AppId) == 0 {
- providerInfo.AppId = consumerInfo.AppId
- }
-
- version := providerInfo.Version
- if len(version) == 0 {
- return BadParamsResponse("Required provider version")
- }
-
- providerInfo.Version = ""
- if _, ok := flag[toString(providerInfo)]; ok {
- return BadParamsResponse("Invalid request body for provider info.Duplicate provider or (serviceName and appId is same).")
- }
- flag[toString(providerInfo)] = true
- providerInfo.Version = version
- }
- return nil
-}
-
func DeleteDependencyForDeleteService(domainProject string, serviceID string, service *pb.MicroServiceKey) (etcdadpt.OpOptions, error) {
key := path.GenerateConsumerDependencyQueueKey(domainProject, serviceID, path.DepsQueueUUID)
conDep := new(pb.ConsumerDependency)
diff --git a/datasource/etcd/util/dependency_util_test.go b/datasource/etcd/util/dependency_util_test.go
index f22f061..5e89dce 100644
--- a/datasource/etcd/util/dependency_util_test.go
+++ b/datasource/etcd/util/dependency_util_test.go
@@ -112,56 +112,6 @@ func TestDependencyRuleExistUtil(t *testing.T) {
}
}
-func TestParamsChecker(t *testing.T) {
- p := ParamsChecker(nil, nil)
- if p != nil {
- t.Fatalf(`ParamsChecker invalid failed`)
- }
-
- p = ParamsChecker(&discovery.MicroServiceKey{
- AppId: "a",
- ServiceName: "b",
- Version: "1.0.0",
- }, nil)
- if p != nil {
- t.Fatalf(`ParamsChecker invalid failed`)
- }
-
- p = ParamsChecker(&discovery.MicroServiceKey{
- AppId: "a",
- ServiceName: "b",
- Version: "1.0.0",
- }, []*discovery.MicroServiceKey{
- {ServiceName: "*"},
- })
- if p != nil {
- t.Fatalf(`ParamsChecker * failed`)
- }
-
- p = ParamsChecker(&discovery.MicroServiceKey{
- AppId: "a",
- ServiceName: "b",
- Version: "1.0.0",
- }, []*discovery.MicroServiceKey{
- {},
- })
- if p == nil {
- t.Fatalf(`ParamsChecker invalid provider key failed`)
- }
-
- p = ParamsChecker(&discovery.MicroServiceKey{
- AppId: "a",
- ServiceName: "b",
- Version: "1.0.0",
- }, []*discovery.MicroServiceKey{
- {ServiceName: "a", Version: "1"},
- {ServiceName: "a", Version: "1"},
- })
- if p == nil {
- t.Fatalf(`ParamsChecker duplicate provider key failed`)
- }
-}
-
func TestServiceDependencyRuleExist(t *testing.T) {
_, err := DependencyRuleExist(context.Background(), &discovery.MicroServiceKey{}, &discovery.MicroServiceKey{})
if err != nil {
diff --git a/datasource/mongo/dep.go b/datasource/mongo/dep.go
index d83da13..03e2202 100644
--- a/datasource/mongo/dep.go
+++ b/datasource/mongo/dep.go
@@ -110,6 +110,64 @@ func (ds *DepManager) SearchConsumerDependency(ctx context.Context, request *dis
}, nil
}
+func (ds *DepManager) AddOrUpdateDependencies(ctx context.Context, dependencys []*discovery.ConsumerDependency, override bool) (*discovery.Response, error) {
+ domainProject := util.ParseDomainProject(ctx)
+ for _, dependency := range dependencys {
+ consumerFlag := util.StringJoin([]string{
+ dependency.Consumer.Environment,
+ dependency.Consumer.AppId,
+ dependency.Consumer.ServiceName,
+ dependency.Consumer.Version}, "/")
+ consumerInfo := discovery.DependenciesToKeys([]*discovery.MicroServiceKey{dependency.Consumer}, domainProject)[0]
+ providersInfo := discovery.DependenciesToKeys(dependency.Providers, domainProject)
+
+ rsp := datasource.ParamsChecker(consumerInfo, providersInfo)
+ if rsp != nil {
+ log.Error(fmt.Sprintf("put request into dependency queue failed, override: %t consumer is %s %s",
+ override, consumerFlag, rsp.Response.GetMessage()), nil)
+ return rsp.Response, nil
+ }
+
+ consumerID, err := GetServiceID(ctx, consumerInfo)
+ if err != nil && !errors.Is(err, datasource.ErrNoData) {
+ log.Error(fmt.Sprintf("put request into dependency queue failed, override: %t, get consumer %s id failed",
+ override, consumerFlag), err)
+ return discovery.CreateResponse(discovery.ErrInternal, err.Error()), err
+ }
+ if len(consumerID) == 0 {
+ log.Error(fmt.Sprintf("put request into dependency queue failed, override: %t consumer %s does not exist",
+ override, consumerFlag), err)
+ return discovery.CreateResponse(discovery.ErrServiceNotExists, fmt.Sprintf("Consumer %s does not exist.", consumerFlag)), nil
+ }
+
+ dependency.Override = override
+ if !override {
+ id := util.GenerateUUID()
+
+ domain := util.ParseDomain(ctx)
+ project := util.ParseProject(ctx)
+ data := &model.ConsumerDep{
+ Domain: domain,
+ Project: project,
+ ConsumerID: consumerID,
+ UUID: id,
+ ConsumerDep: dependency,
+ }
+ insertRes, err := client.GetMongoClient().Insert(ctx, model.CollectionDep, data)
+ if err != nil {
+ log.Error("failed to insert dep to mongodb", err)
+ return discovery.CreateResponse(discovery.ErrInternal, err.Error()), err
+ }
+ log.Info(fmt.Sprintf("insert dep to mongodb success %s", insertRes.InsertedID))
+ }
+ err = syncDependencyRule(ctx, domainProject, dependency)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return discovery.CreateResponse(discovery.ResponseSuccess, "Create dependency successfully."), nil
+}
+
func (ds *DepManager) DependencyHandle(ctx context.Context) (err error) {
return nil
}
@@ -130,7 +188,11 @@ func syncDependencyRule(ctx context.Context, domainProject string, r *discovery.
if err != nil {
return err
}
- datasource.ParseAddOrUpdateRules(ctx, &dep, oldProviderRules)
+ if r.Override {
+ datasource.ParseOverrideRules(ctx, &dep, oldProviderRules)
+ } else {
+ datasource.ParseAddOrUpdateRules(ctx, &dep, oldProviderRules)
+ }
return updateDeps(domainProject, &dep)
}
diff --git a/integration/apis.go b/integration/apis.go
index 6debf13..a1a4f2b 100644
--- a/integration/apis.go
+++ b/integration/apis.go
@@ -32,6 +32,7 @@ var UPDATESCHEMA = "/v4/default/registry/microservices/:serviceId/schemas/:schem
var GETSCHEMAS = "/v4/default/registry/microservices/:serviceId/schemas"
var UPDATESCHEMAS = "/v4/default/registry/microservices/:serviceId/schemas"
var DELETESCHEMA = "/v4/default/registry/microservices/:serviceId/schemas/:schemaId"
+var CREATEDEPENDENCIES = "/v4/default/registry/dependencies"
var GETCONPRODEPENDENCY = "/v4/default/registry/microservices/:consumerId/providers"
var GETPROCONDEPENDENCY = "/v4/default/registry/microservices/:providerId/consumers"
diff --git a/integration/microservices_test.go b/integration/microservices_test.go
index ee3027d..a78c493 100644
--- a/integration/microservices_test.go
+++ b/integration/microservices_test.go
@@ -17,9 +17,6 @@
package integrationtest_test
import (
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
-
"bytes"
"encoding/json"
"io/ioutil"
@@ -28,8 +25,12 @@ import (
"strconv"
"strings"
"testing"
+ "time"
. "github.com/apache/servicecomb-service-center/integration"
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+
"github.com/widuu/gojson"
)
@@ -260,6 +261,267 @@ var _ = Describe("MicroService Api Test", func() {
})
By("Test Dependency API for Provider and Consumer", func() {
+ It("test Valid dependency creation", func() {
+ //Register second microservice
+ getServiceName(serviceId)
+ schema := []string{"testSchema"}
+ properties := map[string]string{"attr1": "aa"}
+ consumerApp := strconv.Itoa(rand.Intn(15))
+ servicemap := map[string]interface{}{
+ "serviceName": consumerApp,
+ "appId": "consumerAppId",
+ "version": "2.0.0",
+ "description": "examples",
+ "level": "FRONT",
+ "schemas": schema,
+ "status": "UP",
+ "properties": properties,
+ }
+ bodyParams := map[string]interface{}{
+ "service": servicemap,
+ }
+ body, _ := json.Marshal(bodyParams)
+ bodyBuf := bytes.NewReader(body)
+ req, _ := http.NewRequest(POST, SCURL+REGISTERMICROSERVICE, bodyBuf)
+ req.Header.Set("X-Domain-Name", "default")
+ resp, err := scclient.Do(req)
+ Expect(err).To(BeNil())
+ defer resp.Body.Close()
+
+ // Validate the service creation
+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
+ respbody, _ := ioutil.ReadAll(resp.Body)
+ consumerServiceID := gojson.Json(string(respbody)).Get("serviceId").Tostring()
+
+ //Create Dependency
+ consumer := map[string]string{
+ "appId": "consumerAppId",
+ "serviceName": consumerApp,
+ "version": "2.0.0",
+ }
+ provider := map[string]string{
+ "appId": serviceAppId,
+ "serviceName": serviceName,
+ "version": serviceVersion,
+ }
+ providersArray := []interface{}{provider}
+ dependency := map[string]interface{}{
+ "consumer": consumer,
+ "providers": providersArray,
+ }
+ dependencyArray := []interface{}{dependency}
+ bodyParams = map[string]interface{}{
+ "dependencies": dependencyArray,
+ }
+ body, _ = json.Marshal(bodyParams)
+ bodyBuf = bytes.NewReader(body)
+ req, _ = http.NewRequest(UPDATE, SCURL+CREATEDEPENDENCIES, bodyBuf)
+ req.Header.Set("X-Domain-Name", "default")
+ resp, err = scclient.Do(req)
+ Expect(err).To(BeNil())
+ defer resp.Body.Close()
+
+ // Validate the dependency creation
+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
+
+ /*
+ //Now try to delete the provider //this will fail as consumer needs to be deleted first
+ url := strings.Replace(UNREGISTERMICROSERVICE, ":serviceId", serviceId, 1)
+ req, _ = http.NewRequest(DELETE, SCURL+url, nil)
+ req.Header.Set("X-Domain-Name", "default")
+ resp, _ = scclient.Do(req)
+ Expect(resp.StatusCode).To(Equal(http.StatusBadRequest))*/
+
+ //Now delete consumer and then provider
+
+ url := strings.Replace(UNREGISTERMICROSERVICE, ":serviceId", consumerServiceID, 1)
+ req, _ = http.NewRequest(DELETE, SCURL+url, nil)
+ req.Header.Set("X-Domain-Name", "default")
+ resp, _ = scclient.Do(req)
+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
+
+ url = strings.Replace(UNREGISTERMICROSERVICE, ":serviceId", serviceId, 1)
+ req, _ = http.NewRequest(DELETE, SCURL+url, nil)
+ req.Header.Set("X-Domain-Name", "default")
+ resp, _ = scclient.Do(req)
+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
+ serviceId = ""
+
+ })
+
+ It("Get Dependencies for providers and consumers", func() {
+ getServiceName(serviceId)
+ schema := []string{"testSchema"}
+ properties := map[string]string{"attr1": "aa"}
+ consumerAppName := strconv.Itoa(rand.Intn(15))
+ servicemap := map[string]interface{}{
+ "serviceName": consumerAppName,
+ "appId": "consumerAppId",
+ "version": "2.0.0",
+ "description": "examples",
+ "level": "FRONT",
+ "schemas": schema,
+ "status": "UP",
+ "properties": properties,
+ }
+ bodyParams := map[string]interface{}{
+ "service": servicemap,
+ }
+ body, _ := json.Marshal(bodyParams)
+ bodyBuf := bytes.NewReader(body)
+ req, _ := http.NewRequest(POST, SCURL+REGISTERMICROSERVICE, bodyBuf)
+ req.Header.Set("X-Domain-Name", "default")
+ resp, err := scclient.Do(req)
+ Expect(err).To(BeNil())
+ defer resp.Body.Close()
+
+ // Validate the service creation
+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
+ respbody, _ := ioutil.ReadAll(resp.Body)
+ consumerServiceID := gojson.Json(string(respbody)).Get("serviceId").Tostring()
+
+ //Create Dependency
+ consumer := map[string]string{
+ "appId": "consumerAppId",
+ "serviceName": consumerAppName,
+ "version": "2.0.0",
+ }
+ provider := map[string]string{
+ "appId": serviceAppId,
+ "serviceName": serviceName,
+ "version": serviceVersion,
+ }
+ providersArray := []interface{}{provider}
+ dependency := map[string]interface{}{
+ "consumer": consumer,
+ "providers": providersArray,
+ }
+ dependencyArray := []interface{}{dependency}
+ bodyParams = map[string]interface{}{
+ "dependencies": dependencyArray,
+ }
+ body, _ = json.Marshal(bodyParams)
+ bodyBuf = bytes.NewReader(body)
+ req, _ = http.NewRequest(UPDATE, SCURL+CREATEDEPENDENCIES, bodyBuf)
+ req.Header.Set("X-Domain-Name", "default")
+ resp, err = scclient.Do(req)
+ Expect(err).To(BeNil())
+ defer resp.Body.Close()
+
+ // Validate the dependency creation
+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
+
+ // add new dependency
+ dependency["providers"] = []interface{}{consumer}
+ body, _ = json.Marshal(bodyParams)
+ bodyBuf = bytes.NewReader(body)
+ req, _ = http.NewRequest(POST, SCURL+CREATEDEPENDENCIES, bodyBuf)
+ req.Header.Set("X-Domain-Name", "default")
+ resp, err = scclient.Do(req)
+ Expect(err).To(BeNil())
+ defer resp.Body.Close()
+
+ // Validate the dependency creation
+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
+
+ //Get Provider by ConsumerID
+ <-time.After(time.Second)
+ url := strings.Replace(GETCONPRODEPENDENCY, ":consumerId", consumerServiceID, 1)
+ req, _ = http.NewRequest(GET, SCURL+url, nil)
+ req.Header.Set("X-Domain-Name", "default")
+ resp, _ = scclient.Do(req)
+ respbody, _ = ioutil.ReadAll(resp.Body)
+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
+ servicesStruct := map[string][]map[string]interface{}{}
+
+ json.Unmarshal(respbody, &servicesStruct)
+ foundMicroService := false
+ for _, services := range servicesStruct["providers"] {
+ if services["serviceName"] == serviceName {
+ foundMicroService = true
+ break
+ }
+ }
+ Expect(foundMicroService).To(Equal(true))
+
+ //Get Consumer by ProviderID
+ url = strings.Replace(GETPROCONDEPENDENCY, ":providerId", serviceId, 1)
+ req, _ = http.NewRequest(GET, SCURL+url, nil)
+ req.Header.Set("X-Domain-Name", "default")
+ resp, _ = scclient.Do(req)
+ respbody, _ = ioutil.ReadAll(resp.Body)
+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
+ servicesStruct = map[string][]map[string]interface{}{}
+
+ json.Unmarshal(respbody, &servicesStruct)
+ foundMicroService = false
+ for _, services := range servicesStruct["consumers"] {
+ if services["serviceName"] == consumerAppName {
+ foundMicroService = true
+ break
+ }
+ }
+ Expect(foundMicroService).To(Equal(true))
+
+ //Get new dependency by ConsumerID
+ url = strings.Replace(GETCONPRODEPENDENCY, ":consumerId", consumerServiceID, 1)
+ req, _ = http.NewRequest(GET, SCURL+url, nil)
+ req.Header.Set("X-Domain-Name", "default")
+ resp, _ = scclient.Do(req)
+ respbody, _ = ioutil.ReadAll(resp.Body)
+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
+ servicesStruct = map[string][]map[string]interface{}{}
+
+ json.Unmarshal(respbody, &servicesStruct)
+ foundMicroService = false
+ for _, services := range servicesStruct["providers"] {
+ if services["serviceName"] == consumerAppName {
+ foundMicroService = true
+ break
+ }
+ }
+ Expect(foundMicroService).To(Equal(true))
+
+ // override the dependency
+ dependency["providers"] = []interface{}{}
+ body, _ = json.Marshal(bodyParams)
+ bodyBuf = bytes.NewReader(body)
+ req, _ = http.NewRequest(UPDATE, SCURL+CREATEDEPENDENCIES, bodyBuf)
+ req.Header.Set("X-Domain-Name", "default")
+ resp, err = scclient.Do(req)
+ Expect(err).To(BeNil())
+ defer resp.Body.Close()
+
+ // Validate the dependency creation
+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
+
+ //Get Provider by ConsumerID again
+ <-time.After(time.Second)
+ url = strings.Replace(GETCONPRODEPENDENCY, ":consumerId", consumerServiceID, 1)
+ req, _ = http.NewRequest(GET, SCURL+url, nil)
+ req.Header.Set("X-Domain-Name", "default")
+ resp, _ = scclient.Do(req)
+ respbody, _ = ioutil.ReadAll(resp.Body)
+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
+ servicesStruct = map[string][]map[string]interface{}{}
+ json.Unmarshal(respbody, &servicesStruct)
+ Expect(len(servicesStruct["providers"])).To(Equal(0))
+
+ //Delete Consumer and Provider
+ url = strings.Replace(UNREGISTERMICROSERVICE, ":serviceId", consumerServiceID, 1)
+ req, _ = http.NewRequest(DELETE, SCURL+url, nil)
+ req.Header.Set("X-Domain-Name", "default")
+ resp, _ = scclient.Do(req)
+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
+
+ url = strings.Replace(UNREGISTERMICROSERVICE, ":serviceId", serviceId, 1)
+ req, _ = http.NewRequest(DELETE, SCURL+url, nil)
+ req.Header.Set("X-Domain-Name", "default")
+ resp, _ = scclient.Do(req)
+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
+ serviceId = ""
+ })
+
It("Invalid scenario for GET Providers and Consumers", func() {
//Get Provider by ConsumerID
url := strings.Replace(GETCONPRODEPENDENCY, ":consumerId", "wrongID", 1)
diff --git a/pkg/proto/service.go b/pkg/proto/service.go
index 5767d98..1cf5faf 100644
--- a/pkg/proto/service.go
+++ b/pkg/proto/service.go
@@ -42,6 +42,8 @@ type ServiceCtrlServer interface {
DeleteSchema(context.Context, *discovery.DeleteSchemaRequest) (*discovery.DeleteSchemaResponse, error)
ModifySchema(context.Context, *discovery.ModifySchemaRequest) (*discovery.ModifySchemaResponse, error)
ModifySchemas(context.Context, *discovery.ModifySchemasRequest) (*discovery.ModifySchemasResponse, error)
+ AddDependenciesForMicroServices(context.Context, *discovery.AddDependenciesRequest) (*discovery.AddDependenciesResponse, error)
+ CreateDependenciesForMicroServices(context.Context, *discovery.CreateDependenciesRequest) (*discovery.CreateDependenciesResponse, error)
GetProviderDependencies(context.Context, *discovery.GetDependenciesRequest) (*discovery.GetProDependenciesResponse, error)
GetConsumerDependencies(context.Context, *discovery.GetDependenciesRequest) (*discovery.GetConDependenciesResponse, error)
DeleteServices(context.Context, *discovery.DelServicesRequest) (*discovery.DelServicesResponse, error)
diff --git a/server/rest/controller/v4/dependency_controller.go b/server/rest/controller/v4/dependency_controller.go
index d2607c4..a3791e8 100644
--- a/server/rest/controller/v4/dependency_controller.go
+++ b/server/rest/controller/v4/dependency_controller.go
@@ -18,9 +18,14 @@
package v4
import (
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
"net/http"
+ "github.com/apache/servicecomb-service-center/pkg/log"
"github.com/apache/servicecomb-service-center/pkg/rest"
+ "github.com/apache/servicecomb-service-center/pkg/util"
"github.com/apache/servicecomb-service-center/server/core"
pb "github.com/go-chassis/cari/discovery"
)
@@ -30,11 +35,61 @@ type DependencyService struct {
func (s *DependencyService) URLPatterns() []rest.Route {
return []rest.Route{
+ {Method: http.MethodPost, Path: "/v4/:project/registry/dependencies", Func: s.AddDependenciesForMicroServices},
+ {Method: http.MethodPut, Path: "/v4/:project/registry/dependencies", Func: s.CreateDependenciesForMicroServices},
{Method: http.MethodGet, Path: "/v4/:project/registry/microservices/:consumerId/providers", Func: s.GetConProDependencies},
{Method: http.MethodGet, Path: "/v4/:project/registry/microservices/:providerId/consumers", Func: s.GetProConDependencies},
}
}
+//Deprecated
+func (s *DependencyService) AddDependenciesForMicroServices(w http.ResponseWriter, r *http.Request) {
+ requestBody, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ log.Error("read body failed", err)
+ rest.WriteError(w, pb.ErrInvalidParams, err.Error())
+ return
+ }
+ request := &pb.AddDependenciesRequest{}
+ err = json.Unmarshal(requestBody, request)
+ if err != nil {
+ log.Error(fmt.Sprintf("invalid json: %s", util.BytesToStringWithNoCopy(requestBody)), err)
+ rest.WriteError(w, pb.ErrInvalidParams, err.Error())
+ return
+ }
+
+ resp, err := core.ServiceAPI.AddDependenciesForMicroServices(r.Context(), request)
+ if err != nil {
+ rest.WriteError(w, pb.ErrInternal, err.Error())
+ }
+ w.Header().Add("Deprecation", "version=\"v4\"")
+ rest.WriteResponse(w, r, resp.Response, nil)
+}
+
+//Deprecated
+func (s *DependencyService) CreateDependenciesForMicroServices(w http.ResponseWriter, r *http.Request) {
+ requestBody, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ log.Error("read body failed", err)
+ rest.WriteError(w, pb.ErrInvalidParams, err.Error())
+ return
+ }
+ request := &pb.CreateDependenciesRequest{}
+ err = json.Unmarshal(requestBody, request)
+ if err != nil {
+ log.Error(fmt.Sprintf("invalid json: %s", util.BytesToStringWithNoCopy(requestBody)), err)
+ rest.WriteError(w, pb.ErrInvalidParams, err.Error())
+ return
+ }
+
+ resp, err := core.ServiceAPI.CreateDependenciesForMicroServices(r.Context(), request)
+ if err != nil {
+ rest.WriteError(w, pb.ErrInternal, err.Error())
+ }
+ w.Header().Add("Deprecation", "version=\"v4\"")
+ rest.WriteResponse(w, r, resp.Response, nil)
+}
+
func (s *DependencyService) GetConProDependencies(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query()
request := &pb.GetDependenciesRequest{
diff --git a/server/service/disco/dependency.go b/server/service/disco/dependency.go
index ea083a6..4169829 100644
--- a/server/service/disco/dependency.go
+++ b/server/service/disco/dependency.go
@@ -26,6 +26,30 @@ import (
pb "github.com/go-chassis/cari/discovery"
)
+func (s *MicroServiceService) AddDependenciesForMicroServices(ctx context.Context,
+ in *pb.AddDependenciesRequest) (*pb.AddDependenciesResponse, error) {
+ if err := validator.Validate(in); err != nil {
+ return &pb.AddDependenciesResponse{
+ Response: datasource.BadParamsResponse(err.Error()).Response,
+ }, nil
+ }
+
+ resp, err := datasource.GetDependencyManager().AddOrUpdateDependencies(ctx, in.Dependencies, false)
+ return &pb.AddDependenciesResponse{Response: resp}, err
+}
+
+func (s *MicroServiceService) CreateDependenciesForMicroServices(ctx context.Context,
+ in *pb.CreateDependenciesRequest) (*pb.CreateDependenciesResponse, error) {
+ if err := validator.Validate(in); err != nil {
+ return &pb.CreateDependenciesResponse{
+ Response: datasource.BadParamsResponse(err.Error()).Response,
+ }, nil
+ }
+
+ resp, err := datasource.GetDependencyManager().AddOrUpdateDependencies(ctx, in.Dependencies, true)
+ return &pb.CreateDependenciesResponse{Response: resp}, err
+}
+
func (s *MicroServiceService) GetProviderDependencies(ctx context.Context,
in *pb.GetDependenciesRequest) (*pb.GetProDependenciesResponse, error) {
err := validator.Validate(in)
diff --git a/server/service/disco/dependency_test.go b/server/service/disco/dependency_test.go
index 4bcae90..ea9a41d 100644
--- a/server/service/disco/dependency_test.go
+++ b/server/service/disco/dependency_test.go
@@ -17,21 +17,436 @@
package disco_test
import (
+ "strconv"
+
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
- "github.com/apache/servicecomb-service-center/datasource/etcd/event"
- "github.com/apache/servicecomb-service-center/datasource/etcd/path"
- "github.com/apache/servicecomb-service-center/datasource/etcd/sd"
+ "github.com/apache/servicecomb-service-center/datasource"
"github.com/apache/servicecomb-service-center/server/service/disco"
pb "github.com/go-chassis/cari/discovery"
- "github.com/go-chassis/go-archaius"
- "github.com/little-cui/etcdadpt"
)
-var deh event.DependencyEventHandler
-
var _ = Describe("'Dependency' service", func() {
+ Describe("execute 'create' operation", func() {
+ var (
+ consumerId1 string
+ consumerId2 string
+ )
+
+ It("should be passed", func() {
+ respCreateService, err := serviceResource.Create(getContext(), &pb.CreateServiceRequest{
+ Service: &pb.MicroService{
+ AppId: "create_dep_group",
+ ServiceName: "create_dep_consumer",
+ Version: "1.0.0",
+ Level: "FRONT",
+ Status: pb.MS_UP,
+ },
+ })
+ Expect(err).To(BeNil())
+ Expect(respCreateService.Response.GetCode()).To(Equal(pb.ResponseSuccess))
+ consumerId1 = respCreateService.ServiceId
+
+ respCreateService, err = serviceResource.Create(getContext(), &pb.CreateServiceRequest{
+ Service: &pb.MicroService{
+ Environment: pb.ENV_PROD,
+ AppId: "create_dep_group",
+ ServiceName: "create_dep_consumer",
+ Version: "1.0.0",
+ Level: "FRONT",
+ Status: pb.MS_UP,
+ },
+ })
+ Expect(err).To(BeNil())
+ Expect(respCreateService.Response.GetCode()).To(Equal(pb.ResponseSuccess))
+ consumerId2 = respCreateService.ServiceId
+
+ respCreateService, err = serviceResource.Create(getContext(), &pb.CreateServiceRequest{
+ Service: &pb.MicroService{
+ AppId: "create_dep_group",
+ ServiceName: "create_dep_provider",
+ Version: "1.0.0",
+ Level: "FRONT",
+ Status: pb.MS_UP,
+ },
+ })
+ Expect(err).To(BeNil())
+ Expect(respCreateService.Response.GetCode()).To(Equal(pb.ResponseSuccess))
+
+ respCreateService, err = serviceResource.Create(getContext(), &pb.CreateServiceRequest{
+ Service: &pb.MicroService{
+ AppId: "create_dep_group",
+ ServiceName: "create_dep_provider",
+ Version: "1.0.1",
+ Level: "FRONT",
+ Status: pb.MS_UP,
+ },
+ })
+ Expect(err).To(BeNil())
+ Expect(respCreateService.Response.GetCode()).To(Equal(pb.ResponseSuccess))
+
+ respCreateService, err = serviceResource.Create(getContext(), &pb.CreateServiceRequest{
+ Service: &pb.MicroService{
+ Environment: pb.ENV_PROD,
+ AppId: "create_dep_group",
+ ServiceName: "create_dep_provider",
+ Version: "1.0.0",
+ Level: "FRONT",
+ Status: pb.MS_UP,
+ },
+ })
+ Expect(err).To(BeNil())
+ Expect(respCreateService.Response.GetCode()).To(Equal(pb.ResponseSuccess))
+
+ respCreateService, err = serviceResource.Create(getContext(), &pb.CreateServiceRequest{
+ Service: &pb.MicroService{
+ AppId: "create_dep_group",
+ ServiceName: "create_dep_provider_other",
+ Version: "1.0.0",
+ Level: "FRONT",
+ Status: pb.MS_UP,
+ },
+ })
+ Expect(err).To(BeNil())
+ Expect(respCreateService.Response.GetCode()).To(Equal(pb.ResponseSuccess))
+ })
+
+ Context("when request is invalid", func() {
+ It("should be failed", func() {
+ By("dependency is nil")
+ respCreateDependency, err := serviceResource.CreateDependenciesForMicroServices(getContext(), &pb.CreateDependenciesRequest{})
+ Expect(err).To(BeNil())
+ Expect(respCreateDependency.Response.GetCode()).ToNot(Equal(pb.ResponseSuccess))
+
+ consumer := &pb.MicroServiceKey{
+ AppId: "create_dep_group",
+ ServiceName: "create_dep_consumer",
+ Version: "1.0.0",
+ }
+ providers := []*pb.MicroServiceKey{
+ {
+ AppId: "create_dep_group",
+ ServiceName: "create_dep_provider",
+ },
+ }
+
+ By("consumer does not exist")
+ respCreateDependency, err = serviceResource.CreateDependenciesForMicroServices(getContext(), &pb.CreateDependenciesRequest{
+ Dependencies: []*pb.ConsumerDependency{
+ {
+ Consumer: &pb.MicroServiceKey{
+ AppId: "noexistapp",
+ ServiceName: "noexistservice",
+ Version: "1.0.0",
+ },
+ Providers: providers,
+ },
+ },
+ })
+ Expect(err).To(BeNil())
+ Expect(respCreateDependency.Response.GetCode()).ToNot(Equal(pb.ResponseSuccess))
+
+ By("provider version is invalid")
+ respCreateDependency, err = serviceResource.CreateDependenciesForMicroServices(getContext(), &pb.CreateDependenciesRequest{
+ Dependencies: []*pb.ConsumerDependency{
+ {
+ Consumer: consumer,
+ Providers: []*pb.MicroServiceKey{
+ {
+ AppId: "create_dep_group",
+ ServiceName: "",
+ },
+ },
+ },
+ },
+ })
+ Expect(err).To(BeNil())
+ Expect(respCreateDependency.Response.GetCode()).To(Equal(pb.ErrInvalidParams))
+
+ By("consumer version is invalid")
+ respCreateDependency, err = serviceResource.CreateDependenciesForMicroServices(getContext(), &pb.CreateDependenciesRequest{
+ Dependencies: []*pb.ConsumerDependency{
+ {
+ Consumer: &pb.MicroServiceKey{
+ AppId: "create_dep_group",
+ ServiceName: "create_dep_consumer",
+ Version: "1.0.0+",
+ },
+ Providers: providers,
+ },
+ },
+ })
+ Expect(err).To(BeNil())
+ Expect(respCreateDependency.Response.GetCode()).To(Equal(pb.ErrInvalidParams))
+ respCreateDependency, err = serviceResource.CreateDependenciesForMicroServices(getContext(), &pb.CreateDependenciesRequest{
+ Dependencies: []*pb.ConsumerDependency{
+ {
+ Consumer: &pb.MicroServiceKey{
+ AppId: "create_dep_group",
+ ServiceName: "create_dep_consumer",
+ Version: "1.0.0-1.0.1",
+ },
+ Providers: providers,
+ },
+ },
+ })
+ Expect(err).To(BeNil())
+ Expect(respCreateDependency.Response.GetCode()).To(Equal(pb.ErrInvalidParams))
+ respCreateDependency, err = serviceResource.CreateDependenciesForMicroServices(getContext(), &pb.CreateDependenciesRequest{
+ Dependencies: []*pb.ConsumerDependency{
+ {
+ Consumer: &pb.MicroServiceKey{
+ AppId: "create_dep_group",
+ ServiceName: "create_dep_consumer",
+ Version: "latest",
+ },
+ Providers: providers,
+ },
+ },
+ })
+ Expect(err).To(BeNil())
+ Expect(respCreateDependency.Response.GetCode()).To(Equal(pb.ErrInvalidParams))
+ respCreateDependency, err = serviceResource.CreateDependenciesForMicroServices(getContext(), &pb.CreateDependenciesRequest{
+ Dependencies: []*pb.ConsumerDependency{
+ {
+ Consumer: &pb.MicroServiceKey{
+ AppId: "create_dep_group",
+ ServiceName: "create_dep_consumer",
+ Version: "",
+ },
+ Providers: providers,
+ },
+ },
+ })
+ Expect(err).To(BeNil())
+ Expect(respCreateDependency.Response.GetCode()).To(Equal(pb.ErrInvalidParams))
+ respCreateDependency, err = serviceResource.CreateDependenciesForMicroServices(getContext(), &pb.CreateDependenciesRequest{
+ Dependencies: []*pb.ConsumerDependency{
+ {
+ Consumer: &pb.MicroServiceKey{
+ AppId: "create_dep_group",
+ ServiceName: "create_dep_consumer",
+ Version: "1.0.32768",
+ },
+ Providers: providers,
+ },
+ },
+ })
+ Expect(err).To(BeNil())
+ Expect(respCreateDependency.Response.GetCode()).To(Equal(pb.ErrInvalidParams))
+
+ By("consumer serviceName is invalid")
+ respCreateDependency, err = serviceResource.CreateDependenciesForMicroServices(getContext(), &pb.CreateDependenciesRequest{
+ Dependencies: []*pb.ConsumerDependency{
+ {
+ Consumer: &pb.MicroServiceKey{
+ AppId: "create_dep_group",
+ ServiceName: "*",
+ Version: "1.0.0",
+ },
+ Providers: providers,
+ },
+ },
+ })
+ Expect(err).To(BeNil())
+ Expect(respCreateDependency.Response.GetCode()).ToNot(Equal(pb.ResponseSuccess))
+
+ By("provider app is invalid")
+ respCreateDependency, err = serviceResource.CreateDependenciesForMicroServices(getContext(), &pb.CreateDependenciesRequest{
+ Dependencies: []*pb.ConsumerDependency{
+ {
+ Consumer: consumer,
+ Providers: []*pb.MicroServiceKey{
+ {
+ AppId: "*",
+ ServiceName: "service_name_provider",
+ Version: "2.0.0",
+ },
+ },
+ },
+ },
+ })
+ Expect(err).To(BeNil())
+ Expect(respCreateDependency.Response.GetCode()).ToNot(Equal(pb.ResponseSuccess))
+
+ By("provider serviceName is invalid")
+ respCreateDependency, err = serviceResource.CreateDependenciesForMicroServices(getContext(), &pb.CreateDependenciesRequest{
+ Dependencies: []*pb.ConsumerDependency{
+ {
+ Consumer: consumer,
+ Providers: []*pb.MicroServiceKey{
+ {
+ AppId: "service_group_provider",
+ ServiceName: "-",
+ Version: "2.0.0",
+ },
+ },
+ },
+ },
+ })
+ Expect(err).To(BeNil())
+ Expect(respCreateDependency.Response.GetCode()).ToNot(Equal(pb.ResponseSuccess))
+
+ By("provider in diff env")
+ respCreateDependency, err = serviceResource.CreateDependenciesForMicroServices(getContext(), &pb.CreateDependenciesRequest{
+ Dependencies: []*pb.ConsumerDependency{
+ {
+ Consumer: consumer,
+ Providers: []*pb.MicroServiceKey{
+ {
+ Environment: pb.ENV_PROD,
+ AppId: "service_group_provider",
+ ServiceName: "service_name_provider",
+ },
+ },
+ },
+ },
+ })
+ Expect(err).To(BeNil())
+ Expect(respCreateDependency.Response.GetCode()).To(Equal(pb.ResponseSuccess))
+
+ By("consumer in diff env")
+ consumer.Environment = pb.ENV_PROD
+ respCreateDependency, err = serviceResource.CreateDependenciesForMicroServices(getContext(), &pb.CreateDependenciesRequest{
+ Dependencies: []*pb.ConsumerDependency{
+ {
+ Consumer: consumer,
+ Providers: []*pb.MicroServiceKey{
+ {
+ AppId: "service_group_provider",
+ ServiceName: "service_name_provider",
+ },
+ },
+ },
+ },
+ })
+ Expect(err).To(BeNil())
+ Expect(respCreateDependency.Response.GetCode()).To(Equal(pb.ResponseSuccess))
+
+ DependencyHandle()
+
+ respCon, err := serviceResource.GetConsumerDependencies(getContext(), &pb.GetDependenciesRequest{
+ ServiceId: consumerId1,
+ })
+ Expect(err).To(BeNil())
+ Expect(respCon.Response.GetCode()).To(Equal(pb.ResponseSuccess))
+ Expect(len(respCon.Providers)).To(Equal(0))
+
+ respCon, err = serviceResource.GetConsumerDependencies(getContext(), &pb.GetDependenciesRequest{
+ ServiceId: consumerId2,
+ })
+ Expect(err).To(BeNil())
+ Expect(respCon.Response.GetCode()).To(Equal(pb.ResponseSuccess))
+ Expect(len(respCon.Providers)).To(Equal(0))
+
+ By("dependencies is invalid")
+ var deps []*pb.ConsumerDependency
+ for i := 0; i < 101; i++ {
+ deps = append(deps, &pb.ConsumerDependency{
+ Consumer: &pb.MicroServiceKey{
+ AppId: "create_dep_group",
+ ServiceName: "create_dep_consumer" + strconv.Itoa(i),
+ Version: "1.0.0",
+ },
+ Providers: []*pb.MicroServiceKey{
+ {
+ AppId: "service_group_provider",
+ ServiceName: "service_name_provider",
+ },
+ },
+ })
+ }
+ respCreateDependency, err = serviceResource.CreateDependenciesForMicroServices(getContext(), &pb.CreateDependenciesRequest{
+ Dependencies: deps,
+ })
+ Expect(err).To(BeNil())
+ Expect(respCreateDependency.Response.GetCode()).To(Equal(pb.ErrInvalidParams))
+ })
+ })
+
+ Context("when request is valid", func() {
+ It("should be passed", func() {
+ consumer := &pb.MicroServiceKey{
+ ServiceName: "create_dep_consumer",
+ AppId: "create_dep_group",
+ Version: "1.0.0",
+ }
+
+ respCreateDependency, err := serviceResource.CreateDependenciesForMicroServices(getContext(), &pb.CreateDependenciesRequest{
+ Dependencies: []*pb.ConsumerDependency{
+ {
+ Consumer: consumer,
+ Providers: []*pb.MicroServiceKey{
+ {
+ AppId: "create_dep_group",
+ ServiceName: "create_dep_provider",
+ },
+ },
+ },
+ },
+ })
+ Expect(err).To(BeNil())
+ Expect(respCreateDependency.Response.GetCode()).To(Equal(pb.ResponseSuccess))
+
+ DependencyHandle()
+
+ respPro, err := serviceResource.GetConsumerDependencies(getContext(), &pb.GetDependenciesRequest{
+ ServiceId: consumerId1,
+ })
+ Expect(err).To(BeNil())
+ Expect(respPro.Response.GetCode()).To(Equal(pb.ResponseSuccess))
+ Expect(len(respPro.Providers)).To(Equal(2))
+
+ respAddDependency, err := serviceResource.AddDependenciesForMicroServices(getContext(), &pb.AddDependenciesRequest{
+ Dependencies: []*pb.ConsumerDependency{
+ {
+ Consumer: consumer,
+ Providers: []*pb.MicroServiceKey{
+ {
+ AppId: "create_dep_group",
+ ServiceName: "create_dep_provider_other",
+ },
+ },
+ },
+ },
+ })
+ Expect(err).To(BeNil())
+ Expect(respAddDependency.Response.GetCode()).To(Equal(pb.ResponseSuccess))
+
+ DependencyHandle()
+
+ respPro, err = serviceResource.GetConsumerDependencies(getContext(), &pb.GetDependenciesRequest{
+ ServiceId: consumerId1,
+ })
+ Expect(err).To(BeNil())
+ Expect(respPro.Response.GetCode()).To(Equal(pb.ResponseSuccess))
+ Expect(len(respPro.Providers)).To(Equal(3))
+
+ By("clean all")
+ respCreateDependency, err = serviceResource.CreateDependenciesForMicroServices(getContext(), &pb.CreateDependenciesRequest{
+ Dependencies: []*pb.ConsumerDependency{
+ {
+ Consumer: consumer,
+ Providers: nil,
+ },
+ },
+ })
+ Expect(err).To(BeNil())
+ Expect(respCreateDependency.Response.GetCode()).To(Equal(pb.ResponseSuccess))
+
+ DependencyHandle()
+
+ respPro, err = serviceResource.GetConsumerDependencies(getContext(), &pb.GetDependenciesRequest{
+ ServiceId: consumerId1,
+ })
+ Expect(err).To(BeNil())
+ Expect(respPro.Response.GetCode()).To(Equal(pb.ResponseSuccess))
+ Expect(len(respPro.Providers)).To(Equal(0))
+ })
+ })
+ })
+
Describe("execute 'get' operation", func() {
var (
consumerId1 string
@@ -279,24 +694,6 @@ var _ = Describe("'Dependency' service", func() {
})
func DependencyHandle() {
- t := archaius.Get("TEST_MODE")
- if t == nil {
- t = "etcd"
- }
- if t == "etcd" {
- for {
- Expect(deh.Handle()).To(BeNil())
-
- key := path.GetServiceDependencyQueueRootKey("")
- resp, err := sd.DependencyQueue().Search(getContext(),
- etcdadpt.WithStrKey(key), etcdadpt.WithPrefix(), etcdadpt.WithCountOnly())
-
- Expect(err).To(BeNil())
-
- // maintain dependency rules.
- if resp.Count == 0 {
- break
- }
- }
- }
+ err := datasource.GetDependencyManager().DependencyHandle(getContext())
+ Expect(err).To(BeNil())
}
diff --git a/server/service/validator/dependency_validator.go b/server/service/validator/dependency_validator.go
new file mode 100644
index 0000000..7a349b3
--- /dev/null
+++ b/server/service/validator/dependency_validator.go
@@ -0,0 +1,70 @@
+/*
+ * 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 validator
+
+import (
+ "regexp"
+
+ "github.com/apache/servicecomb-service-center/pkg/validate"
+)
+
+var (
+ addDependenciesReqValidator validate.Validator
+ overwriteDependenciesReqValidator validate.Validator
+)
+
+var versionAllowEmptyRegex, _ = regexp.Compile(`^(^\d+(\.\d+){0,2}\+?$|^\d+(\.\d+){0,2}-\d+(\.\d+){0,2}$|^latest$)?$`)
+
+func defaultDependencyValidator() *validate.Validator {
+ appIDRule := *(MicroServiceKeyValidator().GetRule("AppId"))
+ appIDRule.Min = 0
+ versionRule := &validate.Rule{Max: 128, Regexp: &validate.VersionRegexp{Fuzzy: true, Regex: versionAllowEmptyRegex}}
+
+ var (
+ consumerMsValidator validate.Validator
+ providerMsValidator validate.Validator
+ )
+ consumerMsValidator.AddRules(MicroServiceKeyValidator().GetRules())
+
+ providerMsValidator.AddRules(MicroServiceKeyValidator().GetRules())
+ providerMsValidator.AddRule("AppId", &appIDRule)
+ providerMsValidator.AddRule("Version", versionRule)
+
+ var dependenciesValidator validate.Validator
+ dependenciesValidator.AddRule("Consumer", &validate.Rule{Min: 1})
+ dependenciesValidator.AddSub("Consumer", &consumerMsValidator)
+ dependenciesValidator.AddSub("Providers", &providerMsValidator)
+
+ return &dependenciesValidator
+}
+
+func AddDependenciesReqValidator() *validate.Validator {
+ return addDependenciesReqValidator.Init(func(v *validate.Validator) {
+ dep := defaultDependencyValidator()
+ dep.AddRule("Providers", &validate.Rule{Min: 1})
+ v.AddRule("Dependencies", &validate.Rule{Min: 1, Max: 100})
+ v.AddSub("Dependencies", dep)
+ })
+}
+
+func CreateDependenciesReqValidator() *validate.Validator {
+ return overwriteDependenciesReqValidator.Init(func(v *validate.Validator) {
+ v.AddRule("Dependencies", &validate.Rule{Min: 1, Max: 100})
+ v.AddSub("Dependencies", defaultDependencyValidator())
+ })
+}
diff --git a/server/service/validator/validator.go b/server/service/validator/validator.go
index 055fc24..2b1c0be 100644
--- a/server/service/validator/validator.go
+++ b/server/service/validator/validator.go
@@ -65,6 +65,10 @@ func Validate(v interface{}) error {
*pb.DeleteServiceRequest,
*pb.GetDependenciesRequest:
return GetServiceReqValidator().Validate(v)
+ case *pb.CreateDependenciesRequest:
+ return CreateDependenciesReqValidator().Validate(v)
+ case *pb.AddDependenciesRequest:
+ return AddDependenciesReqValidator().Validate(v)
case *pb.UpdateServicePropsRequest:
return UpdateServicePropsReqValidator().Validate(v)
case *pb.GetServiceTagsRequest: