robotLJW commented on a change in pull request #782:
URL: 
https://github.com/apache/servicecomb-service-center/pull/782#discussion_r540747894



##########
File path: datasource/mongo/ms.go
##########
@@ -2250,3 +2298,364 @@ func preProcessRegisterInstance(ctx context.Context, 
instance *pb.MicroServiceIn
        instance.Version = microservice.ServiceInfo.Version
        return nil
 }
+
+func findServices(ctx context.Context, key *pb.MicroServiceKey) ([]*Service, 
error) {
+       tenant := strings.Split(key.Tenant, "/")
+       rangeIdx := strings.Index(key.Version, "-")
+       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 filterLatestServices(ctx, filter)
+       case 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}}
+               return filterServices(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}}
+               return filterServices(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}
+               return filterServices(ctx, filter)
+       }
+}
+
+func findInstancesByServiceIDs(ctx context.Context, serviceIDs []string) 
([]*pb.MicroServiceInstance, error) {
+       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 {
+               return nil, err
+       }
+       if resp == nil {
+               return nil, nil
+       }
+
+       var instances []*pb.MicroServiceInstance
+       for resp.Next(ctx) {
+               var instance Instance
+               err := resp.Decode(&instance)
+               if err != nil {
+                       return nil, err
+               }
+               instances = append(instances, instance.InstanceInfo)
+       }
+       return instances, nil
+}
+
+func filterServiceIDs(ctx context.Context, consumerID string, tags []string, 
services []*Service) []string {
+       var filterService []*Service
+       var serviceIDs []string
+       filterService = tagsFilter(services, tags)
+       filterService = accessibleFilter(ctx, consumerID, filterService)
+       for _, service := range filterService {
+               serviceIDs = append(serviceIDs, service.ServiceInfo.ServiceId)
+       }
+       return serviceIDs
+}
+
+func tagsFilter(services []*Service, tags []string) []*Service {
+       var newServices []*Service
+loop:
+       for _, service := range services {
+               for _, tag := range tags {
+                       if _, ok := service.Tags[tag]; !ok {
+                               continue loop
+                       }
+               }
+               newServices = append(newServices, service)
+       }
+       return newServices
+}
+
+func accessibleFilter(ctx context.Context, consumerID string, services 
[]*Service) []*Service {
+       var newServices []*Service
+       for _, service := range services {
+               if err := accessible(ctx, consumerID, 
service.ServiceInfo.ServiceId); err != nil {
+                       findFlag := fmt.Sprintf("consumer '%s' find provider 
%s/%s/%s", consumerID,
+                               service.ServiceInfo.AppId, 
service.ServiceInfo.ServiceName, service.ServiceInfo.Version)
+                       log.Error(fmt.Sprintf("AccessibleFilter failed, %s", 
findFlag), err)
+                       continue
+               }
+               newServices = append(newServices, service)
+       }
+       return newServices
+}
+
+func filterServices(ctx context.Context, filter bson.M) ([]*Service, error) {
+       resp, err := client.GetMongoClient().Find(ctx, CollectionService, 
filter)
+       if err != nil {
+               return nil, err
+       }
+       var services []*Service
+       for resp.Next(ctx) {
+               var service Service
+               err := resp.Decode(&service)
+               if err != nil {
+                       log.Error("type conversion error", err)
+                       return nil, err
+               }
+               services = append(services, &service)
+       }
+       return services, nil
+}
+
+func filterLatestServices(ctx context.Context, filter bson.M) ([]*Service, 
error) {
+       resp, err := client.GetMongoClient().Find(ctx, CollectionService, 
filter, &options.FindOptions{
+               Sort: bson.M{StringBuilder([]string{ColumnServiceInfo, 
ColumnVersion}): -1}})
+       if err != nil {
+               return nil, err
+       }
+       var services []*Service
+       for resp.Next(ctx) {
+               var service Service
+               err := resp.Decode(&service)
+               if err != nil {
+                       log.Error("type conversion error", err)
+                       return nil, err
+               }
+               services = append(services, &service)
+               if services != nil {
+                       return services, nil
+               }
+       }
+       return services, nil
+}
+
+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,
+       }
+       result, err := client.GetMongoClient().FindOne(ctx, CollectionService, 
filter)
+       if err != nil {
+               return nil, err
+       }
+       if result.Err() != nil {
+               return nil, result.Err()
+       }
+       var service Service
+       err = result.Decode(&service)
+       if err != nil {
+               log.Error("type conversion error", err)
+               return nil, err
+       }
+       return service.Tags, nil
+}
+
+func getService(ctx context.Context, domain string, project string, serviceID 
string) (*Service, error) {
+       filter := bson.M{
+               ColumnDomain:  domain,
+               ColumnProject: project,
+               StringBuilder([]string{ColumnServiceInfo, ColumnServiceID}): 
serviceID,
+       }
+       result, err := client.GetMongoClient().FindOne(ctx, CollectionService, 
filter)
+       if err != nil {
+               return nil, err
+       }
+       if result.Err() != nil {
+               return nil, result.Err()
+       }
+       var svc Service
+       err = result.Decode(&svc)
+       if err != nil {
+               return nil, err
+       }
+       return &svc, nil
+}
+
+func accessible(ctx context.Context, consumerID string, providerID string) 
*pb.Error {
+       if len(consumerID) == 0 {
+               return nil
+       }
+
+       domainProject := util.ParseDomainProject(ctx)
+       targetDomainProject := util.ParseTargetDomainProject(ctx)
+       consumerTenant := strings.Split(domainProject, "/")
+       providerTenant := strings.Split(targetDomainProject, "/")
+
+       consumerService, err := getService(ctx, consumerTenant[0], 
consumerTenant[1], consumerID)
+       if err != nil {
+               return pb.NewErrorf(pb.ErrInternal, "An error occurred in query 
consumer(%s)", err.Error())
+       }
+       if consumerService == nil {
+               return pb.NewError(pb.ErrServiceNotExists, "consumer serviceID 
is invalid")
+       }
+
+       // 跨应用权限
+       providerService, err := getService(ctx, providerTenant[0], 
providerTenant[1], providerID)
+       if err != nil {
+               return pb.NewErrorf(pb.ErrInternal, "An error occurred in query 
provider(%s)", err.Error())
+       }
+       if providerService == nil {
+               return pb.NewError(pb.ErrServiceNotExists, "provider serviceID 
is invalid")
+       }
+       err = allowAcrossDimension(ctx, providerService, consumerService)
+       if err != nil {
+               return pb.NewError(pb.ErrPermissionDeny, err.Error())
+       }
+
+       // 黑白名单
+       rules, err := getRulesUtil(ctx, providerTenant[0], providerTenant[1], 
providerID)
+       if err != nil {
+               return pb.NewErrorf(pb.ErrInternal, "An error occurred in query 
provider rules(%s)", err.Error())
+       }
+
+       if len(rules) == 0 {
+               return nil
+       }
+
+       validateTags, err := getTags(ctx, consumerTenant[0], consumerTenant[1], 
consumerService.ServiceInfo.ServiceId)
+       if err != nil {
+               return pb.NewErrorf(pb.ErrInternal, "An error occurred in query 
consumer tags(%s)", err.Error())
+       }
+       return matchRules(rules, consumerService.ServiceInfo, validateTags)
+}
+
+func matchRules(rulesOfProvider []*Rule, consumer *pb.MicroService, 
tagsOfConsumer map[string]string) *pb.Error {
+       if consumer == nil {
+               return pb.NewError(pb.ErrInvalidParams, "consumer is nil")
+       }
+
+       if len(rulesOfProvider) <= 0 {
+               return nil
+       }
+       if rulesOfProvider[0].RuleInfo.RuleType == "WHITE" {
+               return patternWhiteList(rulesOfProvider, tagsOfConsumer, 
consumer)
+       }
+       return patternBlackList(rulesOfProvider, tagsOfConsumer, consumer)
+}
+
+func parsePattern(v reflect.Value, rule *pb.ServiceRule, tagsOfConsumer 
map[string]string, consumerID string) (string, *pb.Error) {
+       if strings.HasPrefix(rule.Attribute, "tag_") {
+               key := rule.Attribute[4:]
+               value := tagsOfConsumer[key]
+               if len(value) == 0 {
+                       log.Info(fmt.Sprintf("can not find service[%s] 
tag[%s]", consumerID, key))
+               }
+               return value, nil
+       }
+       key := v.FieldByName(rule.Attribute)
+       if !key.IsValid() {
+               log.Error(fmt.Sprintf("can not find service[%s] field[%s], 
ruleID is %s",
+                       consumerID, rule.Attribute, rule.RuleId), nil)
+               return "", pb.NewErrorf(pb.ErrInternal, "Can not find field 
'%s'", rule.Attribute)
+       }
+       return key.String(), nil
+
+}
+
+func patternWhiteList(rulesOfProvider []*Rule, tagsOfConsumer 
map[string]string, consumer *pb.MicroService) *pb.Error {
+       v := reflect.Indirect(reflect.ValueOf(consumer))
+       consumerID := consumer.ServiceId
+       for _, rule := range rulesOfProvider {
+               value, err := parsePattern(v, rule.RuleInfo, tagsOfConsumer, 
consumerID)
+               if err != nil {
+                       return err
+               }
+               if len(value) == 0 {
+                       continue
+               }
+
+               match, _ := regexp.MatchString(rule.RuleInfo.Pattern, value)
+               if match {
+                       log.Info(fmt.Sprintf("consumer[%s][%s/%s/%s/%s] match 
white list, rule.Pattern is %s, value is %s",
+                               consumerID, consumer.Environment, 
consumer.AppId, consumer.ServiceName, consumer.Version,
+                               rule.RuleInfo.Pattern, value))
+                       return nil
+               }
+       }
+       return pb.NewError(pb.ErrPermissionDeny, "Not found in white list")

Review comment:
       已经修改,感谢




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
[email protected]


Reply via email to