This is an automated email from the ASF dual-hosted git repository.
tianxiaoliang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-service-center.git
The following commit(s) were added to refs/heads/master by this push:
new e8d5139 【SCB-2094】Fix: open Mongo's pkg, server and syncer test cases
(#809)
e8d5139 is described below
commit e8d5139c3749d39c78cd5d46e94b9781d6268f09
Author: robotLJW <[email protected]>
AuthorDate: Thu Jan 14 14:09:17 2021 +0800
【SCB-2094】Fix: open Mongo's pkg, server and syncer test cases (#809)
---
datasource/etcd/account.go | 2 +-
datasource/etcd/ms.go | 2 +-
datasource/etcd/role.go | 10 +-
datasource/mongo/account.go | 34 ++-
datasource/mongo/database.go | 84 +++---
datasource/mongo/dep.go | 45 ++-
datasource/mongo/dependency_query.go | 2 +-
.../mongo/heartbeat/heartbeatchecker/heartbeat.go | 5 +-
.../heartbeat/heartbeatchecker/heartbeat_test.go | 6 +-
.../heartbeat/heartbeatchecker/heartbeatchecker.go | 2 +-
datasource/mongo/ms.go | 315 ++++++++++++++-------
datasource/mongo/ms_test.go | 16 +-
datasource/mongo/role.go | 96 ++++++-
datasource/mongo/role_test.go | 90 ++++++
datasource/mongo/util.go | 14 +
go.mod | 2 +-
scripts/ut_test_in_docker.sh | 6 +-
server/service/rbac/decision_test.go | 31 +-
server/service/rbac/rbac_test.go | 5 +-
19 files changed, 556 insertions(+), 211 deletions(-)
diff --git a/datasource/etcd/account.go b/datasource/etcd/account.go
index 6eaf548..897196c 100644
--- a/datasource/etcd/account.go
+++ b/datasource/etcd/account.go
@@ -125,7 +125,7 @@ func (ds *DataSource) DeleteAccount(ctx context.Context,
key string) (bool, erro
if err != nil {
return false, err
}
- return resp.Count != 0, nil
+ return resp.Succeeded, nil
}
func (ds *DataSource) UpdateAccount(ctx context.Context, key string, account
*rbacframe.Account) error {
value, err := json.Marshal(account)
diff --git a/datasource/etcd/ms.go b/datasource/etcd/ms.go
index 3e650c7..ed9981a 100644
--- a/datasource/etcd/ms.go
+++ b/datasource/etcd/ms.go
@@ -883,7 +883,7 @@ func (ds *DataSource) FindInstances(ctx context.Context,
request *pb.FindInstanc
Environment: request.Environment,
AppId: request.AppId,
ServiceName: request.ServiceName,
- Alias: request.ServiceName,
+ Alias: request.Alias,
Version: request.VersionRule,
}
diff --git a/datasource/etcd/role.go b/datasource/etcd/role.go
index ac0dd6e..e34f0ff 100644
--- a/datasource/etcd/role.go
+++ b/datasource/etcd/role.go
@@ -39,13 +39,13 @@ func (ds *DataSource) CreateRole(ctx context.Context, r
*rbacframe.Role) error {
defer func() {
err := lock.Unlock()
if err != nil {
- log.Errorf(err, "can not release role lock")
+ log.Error("can not release role lock", err)
}
}()
key := path.GenerateRBACRoleKey(r.Name)
exist, err := datasource.Instance().RoleExist(ctx, r.Name)
if err != nil {
- log.Errorf(err, "can not save role info")
+ log.Error("can not save role info", err)
return err
}
if exist {
@@ -54,12 +54,12 @@ func (ds *DataSource) CreateRole(ctx context.Context, r
*rbacframe.Role) error {
r.ID = util.GenerateUUID()
value, err := json.Marshal(r)
if err != nil {
- log.Errorf(err, "role info is invalid")
+ log.Error("role info is invalid", err)
return err
}
err = client.PutBytes(ctx, key, value)
if err != nil {
- log.Errorf(err, "can not save account info")
+ log.Error("can not save account info", err)
return err
}
log.Info("create new role: " + r.ID)
@@ -119,7 +119,7 @@ func (ds *DataSource) DeleteRole(ctx context.Context, name
string) (bool, error)
if err != nil {
return false, err
}
- return resp.Count != 0, nil
+ return resp.Succeeded, nil
}
func (ds *DataSource) UpdateRole(ctx context.Context, name string, role
*rbacframe.Role) error {
value, err := json.Marshal(role)
diff --git a/datasource/mongo/account.go b/datasource/mongo/account.go
index ccc30c3..58338c2 100644
--- a/datasource/mongo/account.go
+++ b/datasource/mongo/account.go
@@ -19,6 +19,7 @@ package mongo
import (
"context"
+ "errors"
"github.com/apache/servicecomb-service-center/datasource"
"github.com/apache/servicecomb-service-center/datasource/mongo/client"
@@ -59,7 +60,7 @@ func (ds *DataSource) CreateAccount(ctx context.Context, a
*rbacframe.Account) e
func (ds *DataSource) AccountExist(ctx context.Context, key string) (bool,
error) {
filter := bson.M{
- AccountName: key,
+ ColumnAccountName: key,
}
count, err := client.GetMongoClient().Count(ctx, CollectionAccount,
filter)
if err != nil {
@@ -73,19 +74,20 @@ func (ds *DataSource) AccountExist(ctx context.Context, key
string) (bool, error
func (ds *DataSource) GetAccount(ctx context.Context, key string)
(*rbacframe.Account, error) {
filter := bson.M{
- AccountName: key,
+ ColumnAccountName: key,
}
result, err := client.GetMongoClient().FindOne(ctx, CollectionAccount,
filter)
if err != nil {
return nil, err
}
if result.Err() != nil {
- return nil, result.Err()
+ log.Error("failed to get account: ", result.Err())
+ return nil, errors.New("failed to get account")
}
var account rbacframe.Account
err = result.Decode(&account)
if err != nil {
- log.Error("Decode account failed: ", err)
+ log.Error("decode account failed: ", err)
return nil, err
}
return &account, nil
@@ -93,7 +95,10 @@ func (ds *DataSource) GetAccount(ctx context.Context, key
string) (*rbacframe.Ac
func (ds *DataSource) ListAccount(ctx context.Context, key string)
([]*rbacframe.Account, int64, error) {
filter := bson.M{
- AccountName: bson.M{"$regex": key},
+ ColumnAccountName: bson.M{"$regex": key},
+ }
+ if len(key) == 0 {
+ filter = bson.M{}
}
cursor, err := client.GetMongoClient().Find(ctx, CollectionAccount,
filter)
if err != nil {
@@ -105,9 +110,10 @@ func (ds *DataSource) ListAccount(ctx context.Context, key
string) ([]*rbacframe
var account rbacframe.Account
err = cursor.Decode(&account)
if err != nil {
- log.Error("Decode account failed: ", err)
- break
+ log.Error("decode account failed: ", err)
+ continue
}
+ account.Password = ""
accounts = append(accounts, &account)
}
return accounts, int64(len(accounts)), nil
@@ -115,7 +121,7 @@ func (ds *DataSource) ListAccount(ctx context.Context, key
string) ([]*rbacframe
func (ds *DataSource) DeleteAccount(ctx context.Context, key string) (bool,
error) {
filter := bson.M{
- AccountName: key,
+ ColumnAccountName: key,
}
result, err := client.GetMongoClient().Delete(ctx, CollectionAccount,
filter)
if err != nil {
@@ -129,11 +135,17 @@ func (ds *DataSource) DeleteAccount(ctx context.Context,
key string) (bool, erro
func (ds *DataSource) UpdateAccount(ctx context.Context, key string, account
*rbacframe.Account) error {
filter := bson.M{
- AccountName: key,
+ ColumnAccountName: key,
}
update := bson.M{
- "$set": bson.M{AccountID: account.ID, AccountPassword:
account.Name, AccountRole: account.Roles, AccountTokenExpirationTime:
account.TokenExpirationTime,
- AccountCurrentPassword: account.CurrentPassword,
AccountStatus: account.Status,
+ "$set": bson.M{
+ ColumnID: account.ID,
+ ColumnAccountName: account.Name,
+ ColumnPassword: account.Password,
+ ColumnRole: account.Roles,
+ ColumnTokenExpirationTime: account.TokenExpirationTime,
+ ColumnCurrentPassword: account.CurrentPassword,
+ ColumnStatus: account.Status,
},
}
result, err := client.GetMongoClient().Update(ctx, CollectionAccount,
filter, update)
diff --git a/datasource/mongo/database.go b/datasource/mongo/database.go
index 9cbcfb5..465e19a 100644
--- a/datasource/mongo/database.go
+++ b/datasource/mongo/database.go
@@ -24,61 +24,59 @@ import (
)
const (
- DuplicateKey = 11000
- AccountName = "name"
- AccountID = "id"
- AccountPassword = "password"
- AccountRole = "role"
- AccountTokenExpirationTime = "tokenexpirationtime"
- AccountCurrentPassword = "currentpassword"
- AccountStatus = "status"
- RefreshTime = "refreshtime"
-)
-
-const (
CollectionAccount = "account"
CollectionService = "service"
CollectionSchema = "schema"
CollectionRule = "rule"
CollectionInstance = "instance"
CollectionDep = "dependency"
+ CollectionRole = "role"
)
const (
- DepsQueueUUID = "0"
- ErrorDuplicateKey = 11000
+ DepsQueueUUID = "0"
)
const (
- ColumnDomain = "domain"
- ColumnProject = "project"
- ColumnTag = "tags"
- ColumnSchemaID = "schemaid"
- ColumnServiceID = "serviceid"
- ColumnRuleID = "ruleid"
- ColumnServiceInfo = "serviceinfo"
- ColumnProperty = "properties"
- ColumnModTime = "modtimestamp"
- ColumnEnv = "environment"
- ColumnAppID = "appid"
- ColumnServiceName = "servicename"
- ColumnAlias = "alias"
- ColumnVersion = "version"
- ColumnSchemas = "schemas"
- ColumnAttribute = "attribute"
- ColumnPattern = "pattern"
- ColumnDescription = "description"
- ColumnRuleType = "ruletype"
- ColumnSchemaInfo = "schemainfo"
- ColumnSchemaSummary = "schemasummary"
- ColumnConsumer = "consumer"
- ColumnDependencyInfo = "dependencyinfo"
- ColumnRuleInfo = "ruleinfo"
- ColumnInstanceInfo = "instanceinfo"
- ColumnInstanceID = "instanceid"
- ColumnConsumerID = "consumerid"
- ColumnMongoID = "_id"
- ColumnTenant = "tenant"
+ ColumnDomain = "domain"
+ ColumnProject = "project"
+ ColumnTag = "tags"
+ ColumnSchemaID = "schemaid"
+ ColumnServiceID = "serviceid"
+ ColumnRuleID = "ruleid"
+ ColumnServiceInfo = "serviceinfo"
+ ColumnProperty = "properties"
+ ColumnModTime = "modtimestamp"
+ ColumnEnv = "environment"
+ ColumnAppID = "appid"
+ ColumnServiceName = "servicename"
+ ColumnAlias = "alias"
+ ColumnVersion = "version"
+ ColumnSchemas = "schemas"
+ ColumnAttribute = "attribute"
+ ColumnPattern = "pattern"
+ ColumnDescription = "description"
+ ColumnRuleType = "ruletype"
+ ColumnSchemaInfo = "schemainfo"
+ ColumnSchemaSummary = "schemasummary"
+ ColumnConsumer = "consumer"
+ ColumnDependencyInfo = "dependencyinfo"
+ ColumnRuleInfo = "ruleinfo"
+ ColumnInstanceInfo = "instanceinfo"
+ ColumnInstanceID = "instanceid"
+ ColumnConsumerID = "consumerid"
+ ColumnMongoID = "_id"
+ ColumnTenant = "tenant"
+ ColumnID = "id"
+ ColumnAccountName = "name"
+ ColumnRoleName = "name"
+ ColumnPerms = "perms"
+ ColumnPassword = "password"
+ ColumnRole = "role"
+ ColumnTokenExpirationTime = "tokenexpirationtime"
+ ColumnCurrentPassword = "currentpassword"
+ ColumnStatus = "status"
+ ColumnRefreshTime = "refreshtime"
)
type Service struct {
diff --git a/datasource/mongo/dep.go b/datasource/mongo/dep.go
index fe0467d..c45577a 100644
--- a/datasource/mongo/dep.go
+++ b/datasource/mongo/dep.go
@@ -115,7 +115,7 @@ func (ds *DataSource) AddOrUpdateDependencies(ctx
context.Context, dependencyInf
}
consumerID, err := GetServiceID(ctx, consumerInfo)
- if err != nil {
+ 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 pb.CreateResponse(pb.ErrInternal, err.Error()),
err
@@ -155,32 +155,25 @@ func (ds *DataSource) DeleteDependency() {
panic("implement me")
}
-func GetServiceID(ctx context.Context, key *pb.MicroServiceKey) (serviceID
string, err error) {
- domain := util.ParseDomain(ctx)
- project := util.ParseProject(ctx)
- filter := bson.M{
- ColumnDomain: domain,
- ColumnProject: project,
- StringBuilder([]string{ColumnServiceInfo, ColumnEnv}):
key.Environment,
- StringBuilder([]string{ColumnServiceInfo, ColumnAppID}):
key.AppId,
- StringBuilder([]string{ColumnServiceInfo, ColumnServiceName}):
key.ServiceName,
- StringBuilder([]string{ColumnServiceInfo, ColumnVersion}):
key.Version}
-
- findRes, err := client.GetMongoClient().Find(ctx, CollectionService,
filter)
- if err != nil {
- return "", nil
+func GetServiceID(ctx context.Context, key *pb.MicroServiceKey) (string,
error) {
+ id, err := getServiceID(ctx, GeneratorServiceNameFilter(ctx, key))
+ if err != nil && !errors.Is(err, datasource.ErrNoData) {
+ return "", err
}
- var service []*Service
- for findRes.Next(ctx) {
- var temp *Service
- err := findRes.Decode(&temp)
- if err != nil {
- return "", nil
- }
- service = append(service, temp)
+ if len(id) == 0 && len(key.Alias) != 0 {
+ return getServiceID(ctx, GeneratorServiceAliasFilter(ctx, key))
+ }
+ return id, nil
+}
+
+func getServiceID(ctx context.Context, filter bson.M) (serviceID string, err
error) {
+ svc, err := GetService(ctx, filter)
+ if err != nil {
+ return
}
- if service == nil {
- return "", nil
+ if svc != nil {
+ serviceID = svc.ServiceInfo.ServiceId
+ return
}
- return service[0].ServiceInfo.ServiceId, nil
+ return
}
diff --git a/datasource/mongo/dependency_query.go
b/datasource/mongo/dependency_query.go
index db91d47..d404f90 100644
--- a/datasource/mongo/dependency_query.go
+++ b/datasource/mongo/dependency_query.go
@@ -269,7 +269,7 @@ func (dr *DependencyRelation) GetDependencyConsumerIds()
([]string, error) {
consumerIDs := make([]string, 0, len(consumerDependAllList))
for _, consumer := range consumerDependAllList {
consumerID, err := GetServiceID(dr.ctx, consumer)
- if err != nil {
+ if err != nil && !errors.Is(err, datasource.ErrNoData) {
log.Error(fmt.Sprintf("get consumer[%s/%s/%s/%s]
failed",
consumer.Environment, consumer.AppId,
consumer.ServiceName, consumer.Version), err)
return nil, err
diff --git a/datasource/mongo/heartbeat/heartbeatchecker/heartbeat.go
b/datasource/mongo/heartbeat/heartbeatchecker/heartbeat.go
index 29ab0de..c5113df 100644
--- a/datasource/mongo/heartbeat/heartbeatchecker/heartbeat.go
+++ b/datasource/mongo/heartbeat/heartbeatchecker/heartbeat.go
@@ -28,12 +28,13 @@ import (
"github.com/apache/servicecomb-service-center/pkg/log"
)
-func updateInstanceRefreshTime(ctx context.Context, instanceID string) error {
+func updateInstanceRefreshTime(ctx context.Context, serviceID string,
instanceID string) error {
filter := bson.M{
+ mongo.StringBuilder([]string{mongo.ColumnInstanceInfo,
mongo.ColumnServiceID}): serviceID,
mongo.StringBuilder([]string{mongo.ColumnInstanceInfo,
mongo.ColumnInstanceID}): instanceID,
}
update := bson.M{
- "$set": bson.M{mongo.RefreshTime: time.Now()},
+ "$set": bson.M{mongo.ColumnRefreshTime: time.Now()},
}
result, err := client.GetMongoClient().FindOneAndUpdate(ctx,
mongo.CollectionInstance, filter, update)
if err != nil {
diff --git a/datasource/mongo/heartbeat/heartbeatchecker/heartbeat_test.go
b/datasource/mongo/heartbeat/heartbeatchecker/heartbeat_test.go
index ae66ac2..5c6c35f 100644
--- a/datasource/mongo/heartbeat/heartbeatchecker/heartbeat_test.go
+++ b/datasource/mongo/heartbeat/heartbeatchecker/heartbeat_test.go
@@ -41,7 +41,7 @@ func init() {
func TestUpdateInstanceRefreshTime(t *testing.T) {
t.Run("update instance refresh time: if the instance does not exist,the
update should fail", func(t *testing.T) {
- err := updateInstanceRefreshTime(context.Background(),
"not-exist")
+ err := updateInstanceRefreshTime(context.Background(),
"not-exist", "not-exist")
log.Error("", err)
assert.NotNil(t, err)
})
@@ -56,9 +56,10 @@ func TestUpdateInstanceRefreshTime(t *testing.T) {
}
_, err := client.GetMongoClient().Insert(context.Background(),
mongo.CollectionInstance, instance1)
assert.Equal(t, nil, err)
- err = updateInstanceRefreshTime(context.Background(),
instance1.InstanceInfo.InstanceId)
+ err = updateInstanceRefreshTime(context.Background(),
instance1.InstanceInfo.ServiceId, instance1.InstanceInfo.InstanceId)
assert.Equal(t, nil, err)
filter := bson.M{
+ mongo.StringBuilder([]string{mongo.ColumnInstanceInfo,
mongo.ColumnServiceID}): instance1.InstanceInfo.ServiceId,
mongo.StringBuilder([]string{mongo.ColumnInstanceInfo,
mongo.ColumnInstanceID}): instance1.InstanceInfo.InstanceId,
}
result, err :=
client.GetMongoClient().FindOne(context.Background(), mongo.CollectionInstance,
filter)
@@ -68,6 +69,7 @@ func TestUpdateInstanceRefreshTime(t *testing.T) {
assert.Nil(t, err)
assert.NotEqual(t, instance1.RefreshTime, ins.RefreshTime)
filter = bson.M{
+ mongo.StringBuilder([]string{mongo.ColumnInstanceInfo,
mongo.ColumnServiceID}): instance1.InstanceInfo.ServiceId,
mongo.StringBuilder([]string{mongo.ColumnInstanceInfo,
mongo.ColumnInstanceID}): instance1.InstanceInfo.InstanceId,
}
_, err = client.GetMongoClient().Delete(context.Background(),
mongo.CollectionInstance, filter)
diff --git a/datasource/mongo/heartbeat/heartbeatchecker/heartbeatchecker.go
b/datasource/mongo/heartbeat/heartbeatchecker/heartbeatchecker.go
index ed98911..03be2af 100644
--- a/datasource/mongo/heartbeat/heartbeatchecker/heartbeatchecker.go
+++ b/datasource/mongo/heartbeat/heartbeatchecker/heartbeatchecker.go
@@ -41,7 +41,7 @@ func NewHeartBeatChecker(opts heartbeat.Options)
(heartbeat.HealthCheck, error)
func (h *HeartBeatChecker) Heartbeat(ctx context.Context, request
*pb.HeartbeatRequest) (*pb.HeartbeatResponse, error) {
remoteIP := util.GetIPFromContext(ctx)
- err := updateInstanceRefreshTime(ctx, request.InstanceId)
+ err := updateInstanceRefreshTime(ctx, request.ServiceId,
request.InstanceId)
if err != nil {
log.Error(fmt.Sprintf("heartbeat failed, instance[%s]. operator
%s", request.InstanceId, remoteIP), err)
resp := &pb.HeartbeatResponse{
diff --git a/datasource/mongo/ms.go b/datasource/mongo/ms.go
index d60a9d8..075c536 100644
--- a/datasource/mongo/ms.go
+++ b/datasource/mongo/ms.go
@@ -19,10 +19,13 @@ package mongo
import (
"context"
+ "crypto/sha1"
+ "encoding/json"
"errors"
"fmt"
"reflect"
"regexp"
+ "sort"
"strconv"
"strings"
"time"
@@ -62,36 +65,59 @@ func (ds *DataSource) RegisterService(ctx context.Context,
request *discovery.Cr
}
service.Timestamp = strconv.FormatInt(time.Now().Unix(), 10)
service.ModTimestamp = service.Timestamp
- // the service unique index in table is
(serviceId,serviceEnv,serviceAppid,servicename,serviceAlias,serviceVersion)
+ // the service unique index in table is
(serviceId/serviceEnv,serviceAppid,servicename,serviceVersion)
+ if len(service.Alias) != 0 {
+ serviceID, err := GetServiceID(ctx, &discovery.MicroServiceKey{
+ Environment: service.Environment,
+ AppId: service.AppId,
+ ServiceName: service.ServiceName,
+ Version: service.Version,
+ Alias: service.Alias,
+ })
+ if err != nil && !errors.Is(err, datasource.ErrNoData) {
+ return &discovery.CreateServiceResponse{
+ Response:
discovery.CreateResponse(discovery.ErrUnavailableBackend, err.Error()),
+ }, err
+ }
+ if len(serviceID) != 0 {
+ if len(requestServiceID) != 0 && requestServiceID !=
serviceID {
+ log.Warn(fmt.Sprintf("create micro-service[%s]
failed, service already exists, operator: %s",
+ serviceFlag, remoteIP))
+ return &discovery.CreateServiceResponse{
+ Response:
discovery.CreateResponse(discovery.ErrServiceAlreadyExists,
+ "ServiceID conflict or found
the same service with different id."),
+ }, nil
+ }
+ return &discovery.CreateServiceResponse{
+ Response:
discovery.CreateResponse(discovery.ResponseSuccess, "register service
successfully"),
+ ServiceId: serviceID,
+ }, nil
+ }
+ }
insertRes, err := client.GetMongoClient().Insert(ctx,
CollectionService, &Service{Domain: domain, Project: project, ServiceInfo:
service})
if err != nil {
if client.IsDuplicateKey(err) {
- if len(requestServiceID) == 0 {
- serviceIDInner, err := GetServiceID(ctx,
&discovery.MicroServiceKey{
- Environment: service.Environment,
- AppId: service.AppId,
- ServiceName: service.ServiceName,
- Version: service.Version,
- })
- if err != nil {
- return &discovery.CreateServiceResponse{
- Response:
discovery.CreateResponse(discovery.ErrUnavailableBackend, err.Error()),
- }, err
- }
- if len(serviceIDInner) != 0 {
- log.Warn(fmt.Sprintf("create
micro-service[%s][%s] failed, service already exists, operator: %s",
- serviceIDInner, serviceFlag,
remoteIP))
- return &discovery.CreateServiceResponse{
- Response:
discovery.CreateResponse(discovery.ResponseSuccess, "register service
successfully"),
- ServiceId: serviceIDInner,
- }, nil
- }
+ serviceIDInner, err := GetServiceID(ctx,
&discovery.MicroServiceKey{
+ Environment: service.Environment,
+ AppId: service.AppId,
+ ServiceName: service.ServiceName,
+ Version: service.Version,
+ })
+ if err != nil && !errors.Is(err, datasource.ErrNoData) {
+ return &discovery.CreateServiceResponse{
+ Response:
discovery.CreateResponse(discovery.ErrUnavailableBackend, err.Error()),
+ }, err
+ }
+ // serviceid conflict with the service in the database
+ if len(requestServiceID) != 0 && serviceIDInner !=
requestServiceID {
+ return &discovery.CreateServiceResponse{
+ Response:
discovery.CreateResponse(discovery.ErrServiceAlreadyExists,
+ "ServiceID conflict or found
the same service with different id."),
+ }, nil
}
- log.Warn(fmt.Sprintf("create micro-service[%s] failed,
service already exists, operator: %s",
- serviceFlag, remoteIP))
return &discovery.CreateServiceResponse{
- Response:
discovery.CreateResponse(discovery.ErrServiceAlreadyExists,
- "ServiceID conflict or found the same
service with different id."),
+ Response:
discovery.CreateResponse(discovery.ResponseSuccess, "register service
successfully"),
+ ServiceId: serviceIDInner,
}, nil
}
log.Error(fmt.Sprintf("create micro-service[%s] failed, service
already exists, operator: %s",
@@ -191,7 +217,6 @@ func (ds *DataSource) GetService(ctx context.Context,
request *discovery.GetServ
}
func (ds *DataSource) ExistServiceByID(ctx context.Context, request
*discovery.GetExistenceByIDRequest) (*discovery.GetExistenceByIDResponse,
error) {
-
exist, err := ServiceExistID(ctx, request.ServiceId)
if err != nil {
return &discovery.GetExistenceByIDResponse{
@@ -1526,7 +1551,7 @@ func (ds *DataSource) RegisterInstance(ctx
context.Context, request *discovery.R
return registryInstance(ctx, request)
}
-// GetInstances returns instances under the current domain
+// GetInstance returns instance under the current domain
func (ds *DataSource) GetInstance(ctx context.Context, request
*discovery.GetOneInstanceRequest) (*discovery.GetOneInstanceResponse, error) {
var service *Service
var err error
@@ -1583,27 +1608,52 @@ func (ds *DataSource) GetInstance(ctx context.Context,
request *discovery.GetOne
Response:
discovery.CreateResponse(discovery.ErrInternal, err.Error()),
}, err
}
- if services != nil {
- serviceIDs = filterServiceIDs(ctx, request.ConsumerServiceId,
request.Tags, services)
- }
- if services == nil || len(serviceIDs) == 0 {
- mes := fmt.Errorf("%s failed, provider does not exist",
findFlag())
- log.Error("get instance failed", mes)
- return &discovery.GetOneInstanceResponse{
- Response:
discovery.CreateResponse(discovery.ErrServiceNotExists, mes.Error()),
- }, nil
- }
- instances, err := instancesFilter(ctx, serviceIDs)
- if len(instances) == 0 {
+ rev, _ := ctx.Value(util.CtxRequestRevision).(string)
+ serviceIDs = filterServiceIDs(ctx, request.ConsumerServiceId,
request.Tags, services)
+ if len(serviceIDs) == 0 {
mes := fmt.Errorf("%s failed, provider instance does not
exist", findFlag())
log.Error("get instance failed", err)
return &discovery.GetOneInstanceResponse{
Response:
discovery.CreateResponse(discovery.ErrInstanceNotExists, mes.Error()),
}, nil
}
+ instances, err := GetInstancesByServiceID(ctx,
request.ProviderServiceId)
+ if err != nil {
+ log.Error(fmt.Sprintf("get instance failed %s", findFlag()),
err)
+ return &discovery.GetOneInstanceResponse{
+ Response:
discovery.CreateResponse(discovery.ErrInternal, err.Error()),
+ }, err
+ }
+ instance := instances[0]
+ // use explicit instanceId to query
+ if len(request.ProviderInstanceId) != 0 {
+ isExist := false
+ for _, ins := range instances {
+ if ins.InstanceId == request.ProviderInstanceId {
+ instance = ins
+ isExist = true
+ break
+ }
+ }
+ if !isExist {
+ mes := fmt.Errorf("%s failed, provider instance does
not exist", findFlag())
+ log.Error("get instance failed", err)
+ return &discovery.GetOneInstanceResponse{
+ Response:
discovery.CreateResponse(discovery.ErrInstanceNotExists, mes.Error()),
+ }, nil
+ }
+ }
+
+ newRev, _ := formatRevision(request.ConsumerServiceId, instances)
+ if rev == newRev {
+ instance = nil // for gRPC
+ }
+ // TODO support gRPC output context
+ _ = util.WithResponseRev(ctx, newRev)
+
return &discovery.GetOneInstanceResponse{
Response: discovery.CreateResponse(discovery.ResponseSuccess,
"Get instance successfully."),
- Instance: instances[0],
+ Instance: instance,
}, nil
}
@@ -1653,6 +1703,7 @@ func (ds *DataSource) GetInstances(ctx context.Context,
request *discovery.GetIn
provider.ServiceInfo.ServiceId,
provider.ServiceInfo.Environment, provider.ServiceInfo.AppId,
provider.ServiceInfo.ServiceName, provider.ServiceInfo.Version)
}
+ rev, _ := ctx.Value(util.CtxRequestRevision).(string)
serviceIDs := filterServiceIDs(ctx, request.ConsumerServiceId,
request.Tags, []*Service{provider})
if len(serviceIDs) == 0 {
mes := fmt.Errorf("%s failed, provider does not exist",
findFlag())
@@ -1668,6 +1719,11 @@ func (ds *DataSource) GetInstances(ctx context.Context,
request *discovery.GetIn
Response:
discovery.CreateResponse(discovery.ErrInternal, err.Error()),
}, err
}
+ newRev, _ := formatRevision(request.ConsumerServiceId, instances)
+ if rev == newRev {
+ instances = nil // for gRPC
+ }
+ _ = util.WithResponseRev(ctx, newRev)
return &discovery.GetInstancesResponse{
Response: discovery.CreateResponse(discovery.ResponseSuccess,
"Query service instances successfully."),
Instances: instances,
@@ -1765,15 +1821,23 @@ func (ds *DataSource) FindInstances(ctx
context.Context, request *discovery.Find
Environment: request.Environment,
AppId: request.AppId,
ServiceName: request.ServiceName,
- Alias: request.ServiceName,
+ Alias: request.Alias,
Version: request.VersionRule,
}
+ rev, ok := ctx.Value(util.CtxRequestRevision).(string)
+ if !ok {
+ err := errors.New("rev request context is not type string")
+ log.Error("", err)
+ return &discovery.FindInstancesResponse{
+ Response:
discovery.CreateResponse(discovery.ErrInternal, err.Error()),
+ }, err
+ }
if apt.IsGlobal(provider) {
- return ds.findSharedServiceInstance(ctx, request, provider)
+ return ds.findSharedServiceInstance(ctx, request, provider, rev)
}
- return ds.findInstance(ctx, request, provider)
+ return ds.findInstance(ctx, request, provider, rev)
}
func (ds *DataSource) UpdateInstanceStatus(ctx context.Context, request
*discovery.UpdateInstanceStatusRequest)
(*discovery.UpdateInstanceStatusResponse, error) {
@@ -2009,13 +2073,20 @@ func registryInstance(ctx context.Context, request
*discovery.RegisterInstanceRe
}, nil
}
-func (ds *DataSource) findSharedServiceInstance(ctx context.Context, request
*discovery.FindInstancesRequest, provider *discovery.MicroServiceKey)
(*discovery.FindInstancesResponse, error) {
+func (ds *DataSource) findSharedServiceInstance(ctx context.Context, request
*discovery.FindInstancesRequest, provider *discovery.MicroServiceKey, rev
string) (*discovery.FindInstancesResponse, error) {
var err error
// it means the shared micro-services must be the same env with SC.
provider.Environment = apt.Service.Environment
findFlag := func() string {
return fmt.Sprintf("find shared provider[%s/%s/%s/%s]",
provider.Environment, provider.AppId, provider.ServiceName, provider.Version)
}
+ basicFilterServices, err := servicesBasicFilter(ctx, provider)
+ if err != nil {
+ log.Error(fmt.Sprintf("find shared service instance failed %s",
findFlag()), err)
+ return &discovery.FindInstancesResponse{
+ Response:
discovery.CreateResponse(discovery.ErrInternal, err.Error()),
+ }, err
+ }
services, err := findServices(ctx, provider)
if err != nil {
log.Error(fmt.Sprintf("find shared service instance failed %s",
findFlag()), err)
@@ -2023,7 +2094,7 @@ func (ds *DataSource) findSharedServiceInstance(ctx
context.Context, request *di
Response:
discovery.CreateResponse(discovery.ErrInternal, err.Error()),
}, err
}
- if services == nil {
+ if services == nil && len(basicFilterServices) == 0 {
mes := fmt.Errorf("%s failed, provider does not exist",
findFlag())
log.Error("find shared service instance failed", mes)
return &discovery.FindInstancesResponse{
@@ -2031,12 +2102,6 @@ func (ds *DataSource) findSharedServiceInstance(ctx
context.Context, request *di
}, nil
}
serviceIDs := filterServiceIDs(ctx, request.ConsumerServiceId,
request.Tags, services)
- if len(serviceIDs) == 0 {
- return &discovery.FindInstancesResponse{
- Response:
discovery.CreateResponse(discovery.ResponseSuccess, "Query service instances
successfully."),
- Instances: nil,
- }, nil
- }
instances, err := instancesFilter(ctx, serviceIDs)
if err != nil {
log.Error(fmt.Sprintf("find shared service instance failed %s",
findFlag()), err)
@@ -2044,13 +2109,19 @@ func (ds *DataSource) findSharedServiceInstance(ctx
context.Context, request *di
Response:
discovery.CreateResponse(discovery.ErrInternal, err.Error()),
}, err
}
+ newRev, _ := formatRevision(request.ConsumerServiceId, instances)
+ if rev == newRev {
+ instances = nil // for gRPC
+ }
+ // TODO support gRPC output context
+ _ = util.WithResponseRev(ctx, newRev)
return &discovery.FindInstancesResponse{
Response: discovery.CreateResponse(discovery.ResponseSuccess,
"Query service instances successfully."),
Instances: instances,
}, nil
}
-func (ds *DataSource) findInstance(ctx context.Context, request
*discovery.FindInstancesRequest, provider *discovery.MicroServiceKey)
(*discovery.FindInstancesResponse, error) {
+func (ds *DataSource) findInstance(ctx context.Context, request
*discovery.FindInstancesRequest, provider *discovery.MicroServiceKey, rev
string) (*discovery.FindInstancesResponse, error) {
var err error
domainProject := util.ParseDomainProject(ctx)
service := &Service{ServiceInfo: &discovery.MicroService{Environment:
request.Environment}}
@@ -2085,6 +2156,13 @@ func (ds *DataSource) findInstance(ctx context.Context,
request *discovery.FindI
request.ConsumerServiceId,
service.ServiceInfo.Environment, service.ServiceInfo.AppId,
service.ServiceInfo.ServiceName, service.ServiceInfo.Version,
provider.Environment, provider.AppId,
provider.ServiceName, provider.Version)
}
+ basicFilterServices, err := servicesBasicFilter(ctx, provider)
+ if err != nil {
+ log.Error(fmt.Sprintf("find instance failed %s", findFlag()),
err)
+ return &discovery.FindInstancesResponse{
+ Response:
discovery.CreateResponse(discovery.ErrInternal, err.Error()),
+ }, err
+ }
services, err := findServices(ctx, provider)
if err != nil {
log.Error(fmt.Sprintf("find instance failed %s", findFlag()),
err)
@@ -2092,7 +2170,7 @@ func (ds *DataSource) findInstance(ctx context.Context,
request *discovery.FindI
Response:
discovery.CreateResponse(discovery.ErrInternal, err.Error()),
}, err
}
- if services == nil {
+ if services == nil && len(basicFilterServices) == 0 {
mes := fmt.Errorf("%s failed, provider does not exist",
findFlag())
log.Error("find instance failed", mes)
return &discovery.FindInstancesResponse{
@@ -2100,12 +2178,6 @@ func (ds *DataSource) findInstance(ctx context.Context,
request *discovery.FindI
}, nil
}
serviceIDs := filterServiceIDs(ctx, request.ConsumerServiceId,
request.Tags, services)
- if len(serviceIDs) == 0 {
- return &discovery.FindInstancesResponse{
- Response:
discovery.CreateResponse(discovery.ResponseSuccess, "Query service instances
successfully."),
- Instances: nil,
- }, nil
- }
instances, err := instancesFilter(ctx, serviceIDs)
if err != nil {
log.Error(fmt.Sprintf("find instance failed %s", findFlag()),
err)
@@ -2136,7 +2208,12 @@ func (ds *DataSource) findInstance(ctx context.Context,
request *discovery.FindI
}, err
}
}
-
+ newRev, _ := formatRevision(request.ConsumerServiceId, instances)
+ if rev == newRev {
+ instances = nil // for gRPC
+ }
+ // TODO support gRPC output context
+ _ = util.WithResponseRev(ctx, newRev)
return &discovery.FindInstancesResponse{
Response: discovery.CreateResponse(discovery.ResponseSuccess,
"Query service instances successfully."),
Instances: instances,
@@ -2382,56 +2459,72 @@ func preProcessRegisterInstance(ctx context.Context,
instance *discovery.MicroSe
return nil
}
+// servicesBasicFilter query services with domain, project, env, appID,
serviceName, alias
+func servicesBasicFilter(ctx context.Context, key *discovery.MicroServiceKey)
([]*Service, error) {
+ tenant := strings.Split(key.Tenant, "/")
+ if len(tenant) != 2 {
+ return nil, errors.New("invalid 'domain' or 'project'")
+ }
+ filter := bson.M{
+ ColumnDomain: tenant[0],
+ ColumnProject: tenant[1],
+ StringBuilder([]string{ColumnServiceInfo, ColumnEnv}):
key.Environment,
+ StringBuilder([]string{ColumnServiceInfo, ColumnAppID}):
key.AppId,
+ StringBuilder([]string{ColumnServiceInfo, ColumnServiceName}):
key.ServiceName,
+ StringBuilder([]string{ColumnServiceInfo, ColumnAlias}):
key.Alias,
+ }
+ rangeIdx := strings.Index(key.Version, "-")
+ // if the version number is clear, need to add the version number to
query
+ switch {
+ case key.Version == "latest":
+ return servicesFilter(ctx, filter)
+ case len(key.Version) > 0 && key.Version[len(key.Version)-1:] == "+":
+ return servicesFilter(ctx, filter)
+ case rangeIdx > 0:
+ return servicesFilter(ctx, filter)
+ default:
+ filter[StringBuilder([]string{ColumnServiceInfo,
ColumnVersion})] = key.Version
+ return servicesFilter(ctx, filter)
+ }
+}
+
func findServices(ctx context.Context, key *discovery.MicroServiceKey)
([]*Service, error) {
tenant := strings.Split(key.Tenant, "/")
if len(tenant) != 2 {
return nil, errors.New("invalid 'domain' or 'project'")
}
rangeIdx := strings.Index(key.Version, "-")
+ filter := bson.M{
+ ColumnDomain: tenant[0],
+ ColumnProject: tenant[1],
+ StringBuilder([]string{ColumnServiceInfo, ColumnEnv}):
key.Environment,
+ StringBuilder([]string{ColumnServiceInfo, ColumnAppID}):
key.AppId,
+ StringBuilder([]string{ColumnServiceInfo, ColumnServiceName}):
key.ServiceName,
+ StringBuilder([]string{ColumnServiceInfo, ColumnAlias}):
key.Alias,
+ }
switch {
case key.Version == "latest":
- filter := bson.M{
- ColumnDomain: tenant[0],
- ColumnProject: tenant[1],
- StringBuilder([]string{ColumnServiceInfo, ColumnEnv}):
key.Environment,
- StringBuilder([]string{ColumnServiceInfo,
ColumnAppID}): key.AppId,
- StringBuilder([]string{ColumnServiceInfo,
ColumnServiceName}): key.ServiceName,
- }
return latestServicesFilter(ctx, filter)
case len(key.Version) > 0 && key.Version[len(key.Version)-1:] == "+":
start := key.Version[:len(key.Version)-1]
- filter := bson.M{
- ColumnDomain: tenant[0],
- ColumnProject: tenant[1],
- StringBuilder([]string{ColumnServiceInfo, ColumnEnv}):
key.Environment,
- StringBuilder([]string{ColumnServiceInfo,
ColumnAppID}): key.AppId,
- StringBuilder([]string{ColumnServiceInfo,
ColumnServiceName}): key.ServiceName,
- StringBuilder([]string{ColumnServiceInfo,
ColumnVersion}): bson.M{"$gte": start}}
+ filter[StringBuilder([]string{ColumnServiceInfo,
ColumnVersion})] = bson.M{"$gte": start}
return servicesFilter(ctx, filter)
case rangeIdx > 0:
start := key.Version[:rangeIdx]
end := key.Version[rangeIdx+1:]
- filter := bson.M{
- ColumnDomain: tenant[0],
- ColumnProject: tenant[1],
- StringBuilder([]string{ColumnServiceInfo, ColumnEnv}):
key.Environment,
- StringBuilder([]string{ColumnServiceInfo,
ColumnAppID}): key.AppId,
- StringBuilder([]string{ColumnServiceInfo,
ColumnServiceName}): key.ServiceName,
- StringBuilder([]string{ColumnServiceInfo,
ColumnVersion}): bson.M{"$gte": start, "$lte": end}}
+ filter[StringBuilder([]string{ColumnServiceInfo,
ColumnVersion})] = bson.M{"$gte": start, "$lte": end}
return servicesFilter(ctx, filter)
default:
- filter := bson.M{
- ColumnDomain: tenant[0],
- ColumnProject: tenant[1],
- StringBuilder([]string{ColumnServiceInfo, ColumnEnv}):
key.Environment,
- StringBuilder([]string{ColumnServiceInfo,
ColumnAppID}): key.AppId,
- StringBuilder([]string{ColumnServiceInfo,
ColumnServiceName}): key.ServiceName,
- StringBuilder([]string{ColumnServiceInfo,
ColumnVersion}): key.Version}
+ filter[StringBuilder([]string{ColumnServiceInfo,
ColumnVersion})] = key.Version
return servicesFilter(ctx, filter)
}
}
func instancesFilter(ctx context.Context, serviceIDs []string)
([]*discovery.MicroServiceInstance, error) {
+ var instances []*discovery.MicroServiceInstance
+ if len(serviceIDs) == 0 {
+ return instances, nil
+ }
resp, err := client.GetMongoClient().Find(ctx, CollectionInstance,
bson.M{StringBuilder([]string{ColumnInstanceInfo, ColumnServiceID}):
bson.M{"$in": serviceIDs}}, &options.FindOptions{
Sort: bson.M{StringBuilder([]string{ColumnInstanceInfo,
ColumnVersion}): -1}})
if err != nil {
@@ -2440,7 +2533,6 @@ func instancesFilter(ctx context.Context, serviceIDs
[]string) ([]*discovery.Mic
if resp == nil {
return nil, errors.New("no related instances were found")
}
- var instances []*discovery.MicroServiceInstance
for resp.Next(ctx) {
var instance Instance
err := resp.Decode(&instance)
@@ -2455,6 +2547,9 @@ func instancesFilter(ctx context.Context, serviceIDs
[]string) ([]*discovery.Mic
func filterServiceIDs(ctx context.Context, consumerID string, tags []string,
services []*Service) []string {
var filterService []*Service
var serviceIDs []string
+ if len(services) == 0 {
+ return serviceIDs
+ }
filterService = tagsFilter(services, tags)
filterService = accessibleFilter(ctx, consumerID, filterService)
for _, service := range filterService {
@@ -2464,6 +2559,9 @@ func filterServiceIDs(ctx context.Context, consumerID
string, tags []string, ser
}
func tagsFilter(services []*Service, tags []string) []*Service {
+ if len(tags) == 0 {
+ return services
+ }
var newServices []*Service
for _, service := range services {
index := 0
@@ -2541,9 +2639,9 @@ func latestServicesFilter(ctx context.Context, filter
bson.M) ([]*Service, error
func getTags(ctx context.Context, domain string, project string, serviceID
string) (tags map[string]string, err error) {
filter := bson.M{
- ColumnDomain: domain,
- ColumnProject: project,
- ColumnServiceID: serviceID,
+ ColumnDomain: domain,
+ ColumnProject: project,
+ StringBuilder([]string{ColumnServiceInfo, ColumnServiceID}):
serviceID,
}
result, err := client.GetMongoClient().FindOne(ctx, CollectionService,
filter)
if err != nil {
@@ -2714,22 +2812,23 @@ func getRulesUtil(ctx context.Context, domain string,
project string, serviceID
ColumnProject: project,
ColumnServiceID: serviceID,
}
- resp, err := client.GetMongoClient().Find(ctx, CollectionRule, filter)
+ cursor, err := client.GetMongoClient().Find(ctx, CollectionRule, filter)
if err != nil {
return nil, err
}
- if resp.Err() != nil {
- return nil, resp.Err()
+ if cursor.Err() != nil {
+ return nil, cursor.Err()
}
var rules []*Rule
- for resp.Next(ctx) {
- var rule *Rule
- err := resp.Decode(rule)
+ defer cursor.Close(ctx)
+ for cursor.Next(ctx) {
+ var rule Rule
+ err := cursor.Decode(&rule)
if err != nil {
log.Error("type conversion error", err)
return nil, err
}
- rules = append(rules, rule)
+ rules = append(rules, &rule)
}
return rules, nil
}
@@ -2846,7 +2945,7 @@ func GetInstancesByServiceID(ctx context.Context,
serviceID string) ([]*discover
}
res = append(res, inst.InstanceInfo)
}
- if cacheUnavailable {
+ if cacheUnavailable || len(res) == 0 {
res, err := instancesFilter(ctx, []string{serviceID})
if err != nil {
return nil, err
@@ -2855,3 +2954,19 @@ func GetInstancesByServiceID(ctx context.Context,
serviceID string) ([]*discover
}
return res, nil
}
+
+func formatRevision(consumerServiceId string, instances
[]*discovery.MicroServiceInstance) (string, error) {
+ if instances == nil {
+ return fmt.Sprintf("%x",
sha1.Sum(util.StringToBytesWithNoCopy(consumerServiceId))), nil
+ }
+ copyInstance := make([]*discovery.MicroServiceInstance, len(instances))
+ copy(copyInstance, instances)
+ sort.Sort(InstanceSlice(copyInstance))
+ data, err := json.Marshal(copyInstance)
+ if err != nil {
+ log.Error("fail to marshal instance json", err)
+ return "", err
+ }
+ s := fmt.Sprintf("%s.%x", consumerServiceId, sha1.Sum(data))
+ return fmt.Sprintf("%x", sha1.Sum(util.StringToBytesWithNoCopy(s))), nil
+}
diff --git a/datasource/mongo/ms_test.go b/datasource/mongo/ms_test.go
index 7fcf983..c9b05fb 100644
--- a/datasource/mongo/ms_test.go
+++ b/datasource/mongo/ms_test.go
@@ -154,7 +154,7 @@ func TestService_Register(t *testing.T) {
})
assert.NotNil(t, resp)
assert.NoError(t, err)
- assert.Equal(t, pb.ErrServiceAlreadyExists,
resp.Response.GetCode())
+ assert.Equal(t, pb.ResponseSuccess, resp.Response.GetCode())
// serviceName: some-relay-ms-service-name
// alias: sr1-ms-service-name
@@ -175,7 +175,7 @@ func TestService_Register(t *testing.T) {
})
assert.NotNil(t, resp)
assert.NoError(t, err)
- assert.Equal(t, pb.ErrServiceAlreadyExists,
resp.Response.GetCode())
+ assert.Equal(t, pb.ResponseSuccess, resp.Response.GetCode())
// serviceName: some-relay-ms-service-name
// alias: sr1-ms-service-name
@@ -2364,6 +2364,14 @@ func TestInstance_HeartBeat(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, pb.ResponseSuccess, resp.Response.GetCode())
+ log.Info("serviceId does not exist")
+ resp, err = datasource.Instance().Heartbeat(getContext(),
&pb.HeartbeatRequest{
+ ServiceId: "100000000000",
+ InstanceId: instanceID1,
+ })
+ assert.NoError(t, err)
+ assert.NotEqual(t, pb.ResponseSuccess, resp.Response.GetCode())
+
log.Info("instance does not exist")
resp, err = datasource.Instance().Heartbeat(getContext(),
&pb.HeartbeatRequest{
ServiceId: serviceID,
@@ -2839,8 +2847,8 @@ func TestInstance_Query(t *testing.T) {
respFind, err =
datasource.Instance().FindInstances(getContext(), &pb.FindInstancesRequest{
ConsumerServiceId: serviceID1,
- AppId: "query_instance_ms",
- ServiceName: "query_instance_service_ms",
+ AppId: "query_instance",
+ ServiceName: "query_instance_service",
VersionRule: "0.0.0",
})
assert.NoError(t, err)
diff --git a/datasource/mongo/role.go b/datasource/mongo/role.go
index 1ef36ee..b6c913c 100644
--- a/datasource/mongo/role.go
+++ b/datasource/mongo/role.go
@@ -20,29 +20,117 @@ package mongo
import (
"context"
+ "go.mongodb.org/mongo-driver/bson"
+
+ "github.com/apache/servicecomb-service-center/datasource"
+ "github.com/apache/servicecomb-service-center/datasource/mongo/client"
+ "github.com/apache/servicecomb-service-center/pkg/log"
"github.com/apache/servicecomb-service-center/pkg/rbacframe"
+ "github.com/apache/servicecomb-service-center/pkg/util"
)
func (ds *DataSource) CreateRole(ctx context.Context, r *rbacframe.Role) error
{
+ exist, err := ds.RoleExist(ctx, r.Name)
+ if err != nil {
+ log.Error("failed to query role", err)
+ return err
+ }
+ if exist {
+ return datasource.ErrRoleDuplicated
+ }
+ r.ID = util.GenerateUUID()
+ _, err = client.GetMongoClient().Insert(ctx, CollectionRole, r)
+ if err != nil {
+ if client.IsDuplicateKey(err) {
+ return datasource.ErrRoleDuplicated
+ }
+ return err
+ }
+ log.Info("create new role: " + r.ID)
return nil
}
func (ds *DataSource) RoleExist(ctx context.Context, name string) (bool,
error) {
- return false, nil
+ filter := bson.M{
+ ColumnRoleName: name,
+ }
+ count, err := client.GetMongoClient().Count(ctx, CollectionRole, filter)
+ if err != nil {
+ return false, err
+ }
+ if count == 0 {
+ return false, nil
+ }
+ return true, nil
}
func (ds *DataSource) GetRole(ctx context.Context, name string)
(*rbacframe.Role, error) {
- return &rbacframe.Role{}, nil
+ filter := bson.M{
+ ColumnRoleName: name,
+ }
+ result, err := client.GetMongoClient().FindOne(ctx, CollectionRole,
filter)
+ if err != nil {
+ return nil, err
+ }
+ if result.Err() != nil {
+ return nil, client.ErrNoDocuments
+ }
+ var role rbacframe.Role
+ err = result.Decode(&role)
+ if err != nil {
+ log.Error("Decode role failed: ", err)
+ return nil, err
+ }
+ return &role, nil
}
func (ds *DataSource) ListRole(ctx context.Context) ([]*rbacframe.Role, int64,
error) {
- return nil, 0, nil
+ cursor, err := client.GetMongoClient().Find(ctx, CollectionRole,
bson.M{})
+ if err != nil {
+ return nil, 0, err
+ }
+ var roles []*rbacframe.Role
+ defer cursor.Close(ctx)
+ for cursor.Next(ctx) {
+ var role rbacframe.Role
+ err = cursor.Decode(&role)
+ if err != nil {
+ log.Error("decode role failed: ", err)
+ continue
+ }
+ roles = append(roles, &role)
+ }
+ return roles, int64(len(roles)), nil
}
func (ds *DataSource) DeleteRole(ctx context.Context, name string) (bool,
error) {
- return false, nil
+ filter := bson.M{
+ ColumnRoleName: name,
+ }
+ result, err := client.GetMongoClient().Delete(ctx, CollectionRole,
filter)
+ if err != nil {
+ return false, err
+ }
+ if result.DeletedCount == 0 {
+ return false, nil
+ }
+ return true, nil
}
func (ds *DataSource) UpdateRole(ctx context.Context, name string, role
*rbacframe.Role) error {
+ filter := bson.M{
+ ColumnRoleName: name,
+ }
+ update := bson.M{
+ "$set": bson.M{
+ ColumnID: role.ID,
+ ColumnRoleName: role.Name,
+ ColumnPerms: role.Perms,
+ },
+ }
+ _, err := client.GetMongoClient().Update(ctx, CollectionRole, filter,
update)
+ if err != nil {
+ return err
+ }
return nil
}
diff --git a/datasource/mongo/role_test.go b/datasource/mongo/role_test.go
new file mode 100644
index 0000000..c77940e
--- /dev/null
+++ b/datasource/mongo/role_test.go
@@ -0,0 +1,90 @@
+/*
+ * 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 mongo_test
+
+import (
+ "context"
+ "testing"
+
+ "github.com/astaxie/beego"
+ "github.com/stretchr/testify/assert"
+
+ "github.com/apache/servicecomb-service-center/datasource"
+ "github.com/apache/servicecomb-service-center/pkg/rbacframe"
+)
+
+var (
+ r1 = rbacframe.Role{
+ ID: "11111-22222-33333",
+ Name: "test-role1",
+ Perms: nil,
+ }
+
+ r2 = rbacframe.Role{
+ ID: "11111-22222-33333-44444",
+ Name: "test-role2",
+ Perms: nil,
+ }
+)
+
+func init() {
+ beego.AppConfig.Set("registry_plugin", "mongo")
+}
+
+func TestRole(t *testing.T) {
+ t.Run("create role should success", func(t *testing.T) {
+ err := datasource.Instance().CreateRole(context.Background(),
&r1)
+ assert.NoError(t, err)
+ r, err := datasource.Instance().GetRole(context.Background(),
"test-role1")
+ assert.NoError(t, err)
+ assert.Equal(t, r1, *r)
+ })
+ t.Run("role should exist", func(t *testing.T) {
+ exist, err :=
datasource.Instance().RoleExist(context.Background(), "test-role1")
+ assert.NoError(t, err)
+ assert.True(t, exist)
+ })
+
+ t.Run("repeated create role should failed", func(t *testing.T) {
+ err := datasource.Instance().CreateRole(context.Background(),
&r1)
+ assert.Error(t, err)
+ })
+
+ t.Run("update role should success", func(t *testing.T) {
+ r1.ID = "11111-22222-33333-4"
+ err := datasource.Instance().UpdateRole(context.Background(),
"test-role1", &r1)
+ assert.NoError(t, err)
+ })
+ t.Run("add new role should success", func(t *testing.T) {
+ err := datasource.Instance().CreateRole(context.Background(),
&r2)
+ assert.NoError(t, err)
+ _, n, err :=
datasource.Instance().ListRole(context.Background())
+ assert.NoError(t, err)
+ assert.Equal(t, int64(2), n)
+ })
+
+ t.Run("delete role should success", func(t *testing.T) {
+ _, err :=
datasource.Instance().DeleteRole(context.Background(), "test-role1")
+ assert.NoError(t, err)
+ _, err = datasource.Instance().DeleteRole(context.Background(),
"test-role2")
+ assert.NoError(t, err)
+ _, n, err :=
datasource.Instance().ListRole(context.Background())
+ assert.NoError(t, err)
+ assert.Equal(t, int64(0), n)
+ })
+}
diff --git a/datasource/mongo/util.go b/datasource/mongo/util.go
index b7e045c..cc2179b 100644
--- a/datasource/mongo/util.go
+++ b/datasource/mongo/util.go
@@ -28,6 +28,20 @@ import (
"go.mongodb.org/mongo-driver/bson"
)
+type InstanceSlice []*pb.MicroServiceInstance
+
+func (s InstanceSlice) Len() int {
+ return len(s)
+}
+
+func (s InstanceSlice) Swap(i, j int) {
+ s[i], s[j] = s[j], s[i]
+}
+
+func (s InstanceSlice) Less(i, j int) bool {
+ return s[i].InstanceId < s[j].InstanceId
+}
+
func StringBuilder(data []string) string {
var str strings.Builder
for index, value := range data {
diff --git a/go.mod b/go.mod
index 0fcc368..e02c5d8 100644
--- a/go.mod
+++ b/go.mod
@@ -17,7 +17,7 @@ require (
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/dustin/go-humanize v1.0.0 // indirect
github.com/ghodss/yaml v1.0.0
- github.com/go-chassis/cari v0.0.0-20201124050026-32fbf4d53439
+ github.com/go-chassis/cari v0.0.2-0.20210111105320-0bb4211266b7
github.com/go-chassis/foundation v0.2.2-0.20201208060254-d5e8e5beb1f0
github.com/go-chassis/go-archaius v1.3.6-0.20201130023516-387922b408d0
github.com/go-chassis/go-chassis/v2 v2.1.1-0.20201208095114-93feb76fd997
diff --git a/scripts/ut_test_in_docker.sh b/scripts/ut_test_in_docker.sh
index 5d73a59..9924966 100755
--- a/scripts/ut_test_in_docker.sh
+++ b/scripts/ut_test_in_docker.sh
@@ -67,11 +67,7 @@ fi
export TEST_MODE=mongo
[ $? == 0 ] && ut_for_dir datasource/mongo
-# 由於mongo接口未全部實現先注釋
-#[ $? == 0 ] && ut_for_dir pkg
-#[ $? == 0 ] && ut_for_dir server
-#[ $? == 0 ] && ut_for_dir scctl
-#[ $? == 0 ] && ut_for_dir syncer
+[ $? == 0 ] && ut_for_dir syncer
ret=$?
if [ ${ret} == 0 ]; then
diff --git a/server/service/rbac/decision_test.go
b/server/service/rbac/decision_test.go
index 977bb1f..acc9cf4 100644
--- a/server/service/rbac/decision_test.go
+++ b/server/service/rbac/decision_test.go
@@ -19,13 +19,42 @@ package rbac_test
import (
"context"
+ "io/ioutil"
"testing"
- "github.com/apache/servicecomb-service-center/server/service/rbac"
+ "github.com/go-chassis/go-archaius"
+ "github.com/go-chassis/go-chassis/v2/security/secret"
"github.com/stretchr/testify/assert"
+
+ "github.com/apache/servicecomb-service-center/server/service/rbac"
+ "github.com/apache/servicecomb-service-center/server/service/rbac/dao"
)
func TestAllow(t *testing.T) {
+ err := archaius.Init(archaius.WithMemorySource(),
archaius.WithENVSource())
+ assert.NoError(t, err)
+
+ pri, pub, err := secret.GenRSAKeyPair(4096)
+ assert.NoError(t, err)
+
+ b, err := secret.RSAPrivate2Bytes(pri)
+ assert.NoError(t, err)
+ ioutil.WriteFile("./private.key", b, 0600)
+ b, err = secret.RSAPublicKey2Bytes(pub)
+ err = ioutil.WriteFile("./rbac.pub", b, 0600)
+ assert.NoError(t, err)
+
+ archaius.Set(rbac.InitPassword, "Complicated_password1")
+
+ dao.DeleteAccount(context.Background(), "root")
+ dao.DeleteAccount(context.Background(), "a")
+ dao.DeleteAccount(context.Background(), "b")
+
+ rbac.Init()
+ a, err := dao.GetAccount(context.Background(), "root")
+ assert.NoError(t, err)
+ assert.Equal(t, "root", a.Name)
+
t.Run("admin can operate any resource", func(t *testing.T) {
ok, _ := rbac.Allow(context.TODO(), []string{"admin"},
"default", "account", "create")
assert.True(t, ok)
diff --git a/server/service/rbac/rbac_test.go b/server/service/rbac/rbac_test.go
index 7762f63..93e92d3 100644
--- a/server/service/rbac/rbac_test.go
+++ b/server/service/rbac/rbac_test.go
@@ -129,9 +129,8 @@ func TestInitRBAC(t *testing.T) {
})
t.Run("delete the not exist role", func(t *testing.T) {
- r, err := dao.DeleteRole(context.Background(), "tester")
+ _, err := dao.DeleteRole(context.Background(), "tester")
assert.NoError(t, err)
- assert.Equal(t, false, r)
})
t.Run("list exist role", func(t *testing.T) {
@@ -178,6 +177,6 @@ func TestInitRBAC(t *testing.T) {
t.Run("delete the new role", func(t *testing.T) {
r, err := dao.DeleteRole(context.Background(), "tester")
assert.NoError(t, err)
- assert.Equal(t, false, r)
+ assert.Equal(t, true, r)
})
}