You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by as...@apache.org on 2019/06/27 11:53:11 UTC

[servicecomb-kie] branch master updated (6e9a59f -> 6745926)

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

asifdxtreme pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git.


    from 6e9a59f  SCB-1312 clear go lint (#12)
     new 999a224  support combination query
     new 2990828  add license header
     new bf3c4d6  fix bug: if find by labels, will lose key value record
     new 6745926  Merge pull request #13 from tianxiaoliang/master

The 29 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 go.mod                                             |  5 +-
 pkg/common/common.go                               |  3 +-
 server/config/config.go                            |  4 +-
 server/dao/kie_api.go                              | 24 ++++--
 server/dao/kv_test.go                              |  8 +-
 server/resource/v1/common.go                       | 34 +++++++--
 server/resource/v1/common_test.go                  | 64 ++++++++++++++++
 server/resource/v1/doc_struct.go                   | 14 ++--
 server/resource/v1/kv_resource.go                  | 89 +++++++++-------------
 .../v1/{history_resource.go => v1_suite_test.go}   | 14 +++-
 10 files changed, 172 insertions(+), 87 deletions(-)
 create mode 100644 server/resource/v1/common_test.go
 copy server/resource/v1/{history_resource.go => v1_suite_test.go} (82%)


[servicecomb-kie] 25/29: SCB-1312 clear go lint (#12)

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

asifdxtreme pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git

commit 6e9a59f0495e7938e330ad225891745f5ddef024
Author: Shawn <xi...@gmail.com>
AuthorDate: Tue Jun 18 20:51:39 2019 +0800

    SCB-1312 clear go lint (#12)
---
 .travis.yml                            |  12 +--
 build/build_server.sh                  |   9 +-
 client/client.go                       |   9 +-
 client/options.go                      |   3 +
 cmd/{kie/cmd.go => kieserver/main.go}  |  25 +++++-
 cmd/main.go                            |  48 -----------
 pkg/common/common.go                   |   7 +-
 pkg/model/kv.go                        |   7 ++
 pkg/model/mongodb_doc.go               |   9 +-
 scripts/start.sh                       |   2 +-
 scripts/travis/start_deps.sh           |   4 +-
 server/config/config.go                |   2 +
 server/config/struct.go                |   3 +
 server/dao/kie_api.go                  | 148 ++++++++++++++-------------------
 server/dao/kv.go                       |  47 ++++++++---
 server/dao/label.go                    |   2 +
 server/dao/label_history.go            |   2 +
 server/dao/options.go                  |   4 +-
 server/dao/tool.go                     |  40 ++++++++-
 server/handler/noop_auth_handler.go    |   2 +
 server/resource/v1/common.go           |  14 +++-
 server/resource/v1/doc_struct.go       |  29 +++++++
 server/resource/v1/history_resource.go |   1 +
 server/resource/v1/kv_resource.go      |  66 +++++----------
 24 files changed, 276 insertions(+), 219 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 6e4794f..a5361b4 100755
--- a/.travis.yml
+++ b/.travis.yml
@@ -51,14 +51,10 @@ jobs:
         - bash scripts/travis/goCycloChecker.sh
     - stage: Unit Test
       script:
+        - GO111MODULE=on go mod download
+        - GO111MODULE=on go mod vendor
         - bash scripts/travis/start_deps.sh
+        - cd $HOME/gopath/src/github.com/apache/servicecomb-kie
         - go get github.com/mattn/goveralls
         - go get golang.org/x/tools/cmd/cover
-        - GO111MODULE=on go mod download
-        - GO111MODULE=on go mod vendor
-        - bash scripts/travis/unit_test.sh && $HOME/gopath/bin/goveralls -coverprofile=coverage.txt -service=travis-ci
-
-    - stage: Build
-      script:
-        - cd build
-        - ./build_server.sh
+        - bash scripts/travis/unit_test.sh
diff --git a/build/build_server.sh b/build/build_server.sh
index 2ffe85b..099f64c 100755
--- a/build/build_server.sh
+++ b/build/build_server.sh
@@ -1,4 +1,5 @@
 #!/usr/bin/env bash
+set -x
 # 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.
@@ -46,8 +47,7 @@ echo "build from ${GIT_COMMIT}"
 
 
 echo "building..."
-go build -o ${release_dir}/kie github.com/apache/servicecomb-kie/cmd/kie
-
+go build -o ${release_dir}/kie github.com/apache/servicecomb-kie/cmd/kieserver
 
 writeConfig(){
 echo "write template config..."
@@ -95,5 +95,6 @@ tar zcf ${pkg_name} conf kie
 
 echo "building docker..."
 cp ${PROJECT_DIR}/scripts/start.sh ./
-
-sudo docker build -t servicecomb/kie:${version} -f ${PROJECT_DIR}/build/docker/server/Dockerfile .
\ No newline at end of file
+cp ${PROJECT_DIR}/build/docker/server/Dockerfile ./
+sudo docker version
+sudo docker build -t servicecomb/kie:${version} .
\ No newline at end of file
diff --git a/client/client.go b/client/client.go
index 3bcf161..f9df929 100644
--- a/client/client.go
+++ b/client/client.go
@@ -33,25 +33,32 @@ import (
 	"net/url"
 )
 
+//const
 const (
 	APIPathKV = "v1/kv"
 )
 
+//client errors
 var (
 	ErrKeyNotExist = errors.New("can not find value")
 )
 
+//Client is the servicecomb kie rest client.
+//it is concurrency safe
 type Client struct {
 	opts   Config
 	cipher security.Cipher
 	c      *httpclient.URLClient
 }
+
+//Config is the config of client
 type Config struct {
 	Endpoint      string
 	DefaultLabels map[string]string
 	VerifyPeer    bool //TODO make it works, now just keep it false
 }
 
+//New create a client
 func New(config Config) (*Client, error) {
 	u, err := url.Parse(config.Endpoint)
 	if err != nil {
@@ -73,7 +80,7 @@ func New(config Config) (*Client, error) {
 	}, nil
 }
 
-//GetValue get value of a key
+//Get get value of a key
 func (c *Client) Get(ctx context.Context, key string, opts ...GetOption) ([]*model.KVDoc, error) {
 	options := GetOptions{}
 	for _, o := range opts {
diff --git a/client/options.go b/client/options.go
index 21f820b..e56b76e 100644
--- a/client/options.go
+++ b/client/options.go
@@ -17,7 +17,10 @@
 
 package client
 
+//GetOption is the functional option of client func
 type GetOption func(*GetOptions)
+
+//GetOptions is the options of client func
 type GetOptions struct {
 	Labels    map[string]string
 	MatchMode string
diff --git a/cmd/kie/cmd.go b/cmd/kieserver/main.go
similarity index 71%
rename from cmd/kie/cmd.go
rename to cmd/kieserver/main.go
index 4ddad70..f77434f 100644
--- a/cmd/kie/cmd.go
+++ b/cmd/kieserver/main.go
@@ -15,11 +15,16 @@
  * limitations under the License.
  */
 
-package kie
+package main
 
 import (
 	"os"
 
+	"github.com/apache/servicecomb-kie/server/config"
+	_ "github.com/apache/servicecomb-kie/server/handler"
+	"github.com/apache/servicecomb-kie/server/resource/v1"
+	"github.com/go-chassis/go-chassis"
+	"github.com/go-mesh/openlogging"
 	"github.com/urfave/cli"
 )
 
@@ -61,3 +66,21 @@ func Init() error {
 	Configs = &ConfigFromCmd{}
 	return parseConfigFromCmd(os.Args)
 }
+func main() {
+	if err := Init(); err != nil {
+		openlogging.Fatal(err.Error())
+	}
+	chassis.RegisterSchema("rest", &v1.KVResource{})
+	if err := chassis.Init(); err != nil {
+		openlogging.Error(err.Error())
+		os.Exit(1)
+	}
+	if err := config.Init(Configs.ConfigFile); err != nil {
+		openlogging.Error(err.Error())
+		os.Exit(1)
+	}
+	if err := chassis.Run(); err != nil {
+		openlogging.Error("service exit: " + err.Error())
+		os.Exit(1)
+	}
+}
diff --git a/cmd/main.go b/cmd/main.go
deleted file mode 100644
index 4ce2316..0000000
--- a/cmd/main.go
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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 main
-
-import (
-	"github.com/apache/servicecomb-kie/cmd/kie"
-	_ "github.com/apache/servicecomb-kie/server/handler"
-
-	"github.com/apache/servicecomb-kie/server/config"
-	"github.com/apache/servicecomb-kie/server/resource/v1"
-	"github.com/go-chassis/go-chassis"
-	"github.com/go-mesh/openlogging"
-	"os"
-)
-
-func main() {
-	if err := kie.Init(); err != nil {
-		openlogging.Fatal(err.Error())
-	}
-	chassis.RegisterSchema("rest", &v1.KVResource{})
-	if err := chassis.Init(); err != nil {
-		openlogging.Error(err.Error())
-		os.Exit(1)
-	}
-	if err := config.Init(kie.Configs.ConfigFile); err != nil {
-		openlogging.Error(err.Error())
-		os.Exit(1)
-	}
-	if err := chassis.Run(); err != nil {
-		openlogging.Error("service exit: " + err.Error())
-		os.Exit(1)
-	}
-}
diff --git a/pkg/common/common.go b/pkg/common/common.go
index 345086a..e39dca6 100644
--- a/pkg/common/common.go
+++ b/pkg/common/common.go
@@ -17,12 +17,15 @@
 
 package common
 
+//match mode
 const (
 	MatchGreedy = "greedy"
 	MatchExact  = "exact"
 )
 
+//http headers
 const (
-	HeaderMatch = "X-Match"
-	HeaderDepth = "X-Depth"
+	HeaderMatch  = "X-Match"
+	HeaderDepth  = "X-Depth"
+	HeaderTenant = "X-Domain-Name"
 )
diff --git a/pkg/model/kv.go b/pkg/model/kv.go
index 73d33e3..2635f6e 100644
--- a/pkg/model/kv.go
+++ b/pkg/model/kv.go
@@ -17,7 +17,14 @@
 
 package model
 
+//KVResponse represents the key value list
 type KVResponse struct {
 	LabelDoc *LabelDocResponse `json:"label"`
 	Data     []*KVDoc          `json:"data"`
 }
+
+//LabelDocResponse is label struct
+type LabelDocResponse struct {
+	LabelID string            `json:"label_id,omitempty"`
+	Labels  map[string]string `json:"labels,omitempty"`
+}
diff --git a/pkg/model/mongodb_doc.go b/pkg/model/mongodb_doc.go
index 71a9483..ce32c5d 100644
--- a/pkg/model/mongodb_doc.go
+++ b/pkg/model/mongodb_doc.go
@@ -19,16 +19,15 @@ package model
 
 import "go.mongodb.org/mongo-driver/bson/primitive"
 
-type LabelDocResponse struct {
-	LabelID string            `json:"label_id,omitempty"`
-	Labels  map[string]string `json:"labels,omitempty"`
-}
+//LabelDoc is database struct to store labels
 type LabelDoc struct {
 	ID       primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"`
 	Labels   map[string]string  `json:"labels,omitempty"`
 	Revision int                `json:"revision,omitempty"`
 	Domain   string             `json:"domain,omitempty"` //tenant info
 }
+
+//KVDoc is database struct to store kv
 type KVDoc struct {
 	ID        primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"`
 	LabelID   string             `json:"label_id,omitempty" bson:"label_id,omitempty"`
@@ -41,6 +40,8 @@ type KVDoc struct {
 	Domain   string            `json:"domain,omitempty"` //redundant
 	Revision int               `json:"revision,omitempty" bson:"-"`
 }
+
+//LabelRevisionDoc is database struct to store label history stats
 type LabelRevisionDoc struct {
 	ID       primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"`
 	LabelID  string             `json:"label_id,omitempty"  bson:"label_id,omitempty"`
diff --git a/scripts/start.sh b/scripts/start.sh
index 682634c..9abf470 100755
--- a/scripts/start.sh
+++ b/scripts/start.sh
@@ -45,7 +45,7 @@ logger_level: ${LOG_LEVEL}
 
 logger_file: log/chassis.log
 
-log_format_text: true
+log_format_text: false
 
 rollingPolicy: size
 
diff --git a/scripts/travis/start_deps.sh b/scripts/travis/start_deps.sh
index b4587ef..d2236f6 100755
--- a/scripts/travis/start_deps.sh
+++ b/scripts/travis/start_deps.sh
@@ -15,4 +15,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-docker-compose up -f $GOPATH/src/github.com/apache/servicecomb-kie/deployments/docker/docker-compose.yaml
\ No newline at end of file
+cd build
+bash build_server.sh
+sudo docker-compose -f $GOPATH/src/github.com/apache/servicecomb-kie/deployments/docker/docker-compose.yaml up -d
\ No newline at end of file
diff --git a/server/config/config.go b/server/config/config.go
index 7e03731..76571de 100644
--- a/server/config/config.go
+++ b/server/config/config.go
@@ -26,6 +26,7 @@ import (
 
 var configurations *Config
 
+//Init initiate config files
 func Init(file string) error {
 	if err := archaius.AddFile(file, archaius.WithFileHandler(filesource.UseFileNameAsKeyContentAsValue)); err != nil {
 		return err
@@ -39,6 +40,7 @@ func Init(file string) error {
 	return nil
 }
 
+//GetDB return db configs
 func GetDB() DB {
 	return configurations.DB
 }
diff --git a/server/config/struct.go b/server/config/struct.go
index cbfb644..0e2cd55 100644
--- a/server/config/struct.go
+++ b/server/config/struct.go
@@ -17,9 +17,12 @@
 
 package config
 
+//Config is yaml file struct
 type Config struct {
 	DB DB `yaml:"db"`
 }
+
+//DB is yaml file struct to set mongodb config
 type DB struct {
 	URI      string   `yaml:"uri"`
 	PoolSize int      `yaml:"poolSize"`
diff --git a/server/dao/kie_api.go b/server/dao/kie_api.go
index 323d8e7..a5cca3d 100644
--- a/server/dao/kie_api.go
+++ b/server/dao/kie_api.go
@@ -15,6 +15,7 @@
  * limitations under the License.
  */
 
+//Package dao is the data access layer
 package dao
 
 import (
@@ -32,6 +33,7 @@ import (
 
 var client *mongo.Client
 
+//const for dao
 const (
 	DB                      = "kie"
 	CollectionLabel         = "label"
@@ -41,11 +43,17 @@ const (
 	DefaultValueType        = "text"
 )
 
+//MongodbService operate data in mongodb
 type MongodbService struct {
 	c       *mongo.Client
 	timeout time.Duration
 }
 
+//CreateOrUpdate will create or update a key value record
+//it first check label exists or not, and create labels if labels is first posted.
+//if label exists, then get its latest revision, and update current revision,
+//save the current label and its all key values to history collection
+//then check key exists or not, then create or update it
 func (s *MongodbService) CreateOrUpdate(ctx context.Context, domain string, kv *model.KVDoc) (*model.KVDoc, error) {
 	if domain == "" {
 		return nil, ErrMissingDomain
@@ -176,9 +184,8 @@ func (s *MongodbService) FindKVByLabelID(ctx context.Context, domain, labelID, k
 	filter := bson.M{"label_id": labelID, "domain": domain}
 	if key != "" {
 		return s.findOneKey(ctx, filter, key)
-	} else {
-		return s.findKeys(ctx, filter, true)
 	}
+	return s.findKeys(ctx, filter, true)
 
 }
 
@@ -193,107 +200,74 @@ func (s *MongodbService) FindKV(ctx context.Context, domain string, options ...F
 	if domain == "" {
 		return nil, ErrMissingDomain
 	}
-	collection := s.c.Database(DB).Collection(CollectionKV)
-	ctx, _ = context.WithTimeout(ctx, DefaultTimeout)
-	filter := bson.M{"domain": domain}
-	if opts.Key != "" {
-		filter["key"] = opts.Key
-	}
-	for k, v := range opts.Labels {
-		filter["labels."+k] = v
-	}
 
-	cur, err := collection.Find(ctx, filter)
+	cur, err := s.findKV(ctx, domain, opts)
 	if err != nil {
-		if err.Error() == context.DeadlineExceeded.Error() {
-			return nil, ErrAction("find", filter, fmt.Errorf("can not reach mongodb in %s", s.timeout))
-		}
 		return nil, err
 	}
 	defer cur.Close(ctx)
-	if cur.Err() != nil {
-		return nil, err
-	}
+
 	kvResp := make([]*model.KVResponse, 0)
 	if opts.ExactLabels {
-		openlogging.Debug(fmt.Sprintf("find one [%s] with lables [%s] in [%s]", opts.Key, opts.Labels, domain))
-		curKV := &model.KVDoc{} //reuse this pointer to reduce GC, only clear label
-
-		//check label length to get the exact match
-		for cur.Next(ctx) { //although complexity is O(n), but there won't be so much labels for one key
-			curKV.Labels = nil
-			err := cur.Decode(curKV)
-			if err != nil {
-				openlogging.Error("decode error: " + err.Error())
-				return nil, err
-			}
-			if len(curKV.Labels) == len(opts.Labels) {
-				openlogging.Debug("hit exact labels")
-				labelGroup := &model.KVResponse{
-					LabelDoc: &model.LabelDocResponse{
-						Labels:  opts.Labels,
-						LabelID: curKV.LabelID,
-					},
-					Data: make([]*model.KVDoc, 0),
-				}
-				clearKV(curKV)
-				labelGroup.Data = append(labelGroup.Data, curKV)
-				kvResp = append(kvResp, labelGroup)
-				return kvResp, nil
-			}
+		openlogging.Debug("find one key", openlogging.WithTags(
+			map[string]interface{}{
+				"key":    opts.Key,
+				"label":  opts.Labels,
+				"domain": domain,
+			},
+		))
+		return cursorToOneKV(ctx, cur, opts.Labels)
+	}
+	if opts.Depth == 0 {
+		opts.Depth = 1
+	}
+	for cur.Next(ctx) {
+		curKV := &model.KVDoc{}
 
+		if err := cur.Decode(curKV); err != nil {
+			openlogging.Error("decode to KVs error: " + err.Error())
+			return nil, err
 		}
-		return nil, ErrKeyNotExists
-	} else {
-		if opts.Depth == 0 {
-			opts.Depth = 1
+		if (len(curKV.Labels) - len(opts.Labels)) > opts.Depth {
+			//because it is query by labels, so result can not be minus
+			//so many labels,then continue
+			openlogging.Debug("so deep, skip this key")
+			continue
 		}
-		for cur.Next(ctx) {
-			curKV := &model.KVDoc{}
-
-			if err := cur.Decode(curKV); err != nil {
-				openlogging.Error("decode to KVs error: " + err.Error())
-				return nil, err
-			}
-			if (len(curKV.Labels) - len(opts.Labels)) > opts.Depth {
-				//because it is query by labels, so result can not be minus
-				//so many labels,then continue
-				openlogging.Debug("so deep, skip this key")
-				continue
-			}
-			openlogging.Info(fmt.Sprintf("%v", curKV))
-			var groupExist bool
-			var labelGroup *model.KVResponse
-			for _, labelGroup = range kvResp {
-				if reflect.DeepEqual(labelGroup.LabelDoc.Labels, curKV.Labels) {
-					groupExist = true
-					clearKV(curKV)
-					labelGroup.Data = append(labelGroup.Data, curKV)
-					break
-				}
-
-			}
-			if !groupExist {
-				labelGroup = &model.KVResponse{
-					LabelDoc: &model.LabelDocResponse{
-						Labels:  curKV.Labels,
-						LabelID: curKV.LabelID,
-					},
-					Data: []*model.KVDoc{curKV},
-				}
+		openlogging.Info(fmt.Sprintf("%v", curKV))
+		var groupExist bool
+		var labelGroup *model.KVResponse
+		for _, labelGroup = range kvResp {
+			if reflect.DeepEqual(labelGroup.LabelDoc.Labels, curKV.Labels) {
+				groupExist = true
 				clearKV(curKV)
-				openlogging.Debug("add new label group")
-				kvResp = append(kvResp, labelGroup)
+				labelGroup.Data = append(labelGroup.Data, curKV)
+				break
 			}
 
 		}
-		if len(kvResp) == 0 {
-			return nil, ErrKeyNotExists
+		if !groupExist {
+			labelGroup = &model.KVResponse{
+				LabelDoc: &model.LabelDocResponse{
+					Labels:  curKV.Labels,
+					LabelID: curKV.LabelID,
+				},
+				Data: []*model.KVDoc{curKV},
+			}
+			clearKV(curKV)
+			openlogging.Debug("add new label group")
+			kvResp = append(kvResp, labelGroup)
 		}
-		return kvResp, nil
+
+	}
+	if len(kvResp) == 0 {
+		return nil, ErrKeyNotExists
 	}
+	return kvResp, nil
 
 }
+
+//DeleteByID delete a key value by collection ID
 func (s *MongodbService) DeleteByID(id string) error {
 	collection := s.c.Database(DB).Collection(CollectionKV)
 	hex, err := primitive.ObjectIDFromHex(id)
@@ -312,6 +286,8 @@ func (s *MongodbService) DeleteByID(id string) error {
 	return nil
 }
 
+//Delete remove a list of key values for a tenant
+//domain=tenant
 func (s *MongodbService) Delete(ids []string, domain string) error {
 	if len(ids) == 0 {
 		openlogging.Warn("delete error,ids is blank")
@@ -351,6 +327,8 @@ func (s *MongodbService) Delete(ids []string, domain string) error {
 	}
 	return nil
 }
+
+//NewMongoService create a new mongo db service
 func NewMongoService(opts Options) (*MongodbService, error) {
 	if opts.Timeout == 0 {
 		opts.Timeout = DefaultTimeout
diff --git a/server/dao/kv.go b/server/dao/kv.go
index c48774b..41aba48 100644
--- a/server/dao/kv.go
+++ b/server/dao/kv.go
@@ -15,13 +15,14 @@
  * limitations under the License.
  */
 
-//package dao is a persis layer of kie
+//Package dao is a persis layer of kie
 package dao
 
 import (
 	"context"
 	"crypto/tls"
 	"errors"
+	"fmt"
 	"github.com/apache/servicecomb-kie/pkg/model"
 	"github.com/apache/servicecomb-kie/server/config"
 	"github.com/go-mesh/openlogging"
@@ -31,6 +32,7 @@ import (
 	"time"
 )
 
+//db errors
 var (
 	ErrMissingDomain    = errors.New("domain info missing, illegal access")
 	ErrKeyNotExists     = errors.New("key with labels does not exits")
@@ -40,6 +42,7 @@ var (
 	ErrRevisionNotExist = errors.New("label revision not exist")
 )
 
+//Options mongodb options
 type Options struct {
 	URI      string
 	PoolSize int
@@ -48,6 +51,8 @@ type Options struct {
 	Timeout  time.Duration
 }
 
+//NewKVService create a kv service
+//TODO, multiple config server
 func NewKVService() (*MongodbService, error) {
 	opts := Options{
 		URI:      config.GetDB().URI,
@@ -55,7 +60,7 @@ func NewKVService() (*MongodbService, error) {
 		SSL:      config.GetDB().SSL,
 	}
 	if opts.SSL {
-
+		//TODO tls config
 	}
 	return NewMongoService(opts)
 }
@@ -90,16 +95,36 @@ func (s *MongodbService) KVExist(ctx context.Context, domain, key string, option
 			return primitive.NilObjectID, err
 		}
 		return kvs[0].ID, nil
-	} else {
-		kvs, err := s.FindKV(ctx, domain, WithExactLabels(), WithLabels(opts.Labels), WithKey(key))
-		if err != nil {
-			return primitive.NilObjectID, err
-		}
-		if len(kvs) != 1 {
-			return primitive.NilObjectID, ErrTooMany
-		}
+	}
+	kvs, err := s.FindKV(ctx, domain, WithExactLabels(), WithLabels(opts.Labels), WithKey(key))
+	if err != nil {
+		return primitive.NilObjectID, err
+	}
+	if len(kvs) != 1 {
+		return primitive.NilObjectID, ErrTooMany
+	}
 
-		return kvs[0].Data[0].ID, nil
+	return kvs[0].Data[0].ID, nil
+
+}
+
+func (s *MongodbService) findKV(ctx context.Context, domain string, opts FindOptions) (*mongo.Cursor, error) {
+	collection := s.c.Database(DB).Collection(CollectionKV)
+	ctx, _ = context.WithTimeout(ctx, DefaultTimeout)
+	filter := bson.M{"domain": domain}
+	if opts.Key != "" {
+		filter["key"] = opts.Key
+	}
+	for k, v := range opts.Labels {
+		filter["labels."+k] = v
 	}
 
+	cur, err := collection.Find(ctx, filter)
+	if err != nil {
+		if err.Error() == context.DeadlineExceeded.Error() {
+			return nil, ErrAction("find", filter, fmt.Errorf("can not reach mongodb in %s", s.timeout))
+		}
+		return nil, err
+	}
+	return cur, err
 }
diff --git a/server/dao/label.go b/server/dao/label.go
index 3fddd2f..742c3dc 100644
--- a/server/dao/label.go
+++ b/server/dao/label.go
@@ -58,6 +58,8 @@ func (s *MongodbService) findOneLabels(ctx context.Context, filter bson.M) (*mod
 	}
 	return l, nil
 }
+
+//LabelsExist check label exists or not and return label ID
 func (s *MongodbService) LabelsExist(ctx context.Context, domain string, labels map[string]string) (primitive.ObjectID, error) {
 	l, err := s.FindLabels(ctx, domain, labels)
 	if err != nil {
diff --git a/server/dao/label_history.go b/server/dao/label_history.go
index fb8164f..a3809d6 100644
--- a/server/dao/label_history.go
+++ b/server/dao/label_history.go
@@ -56,6 +56,8 @@ func (s *MongodbService) getLatestLabel(ctx context.Context, labelID string) (*m
 	}
 	return h, nil
 }
+
+//AddHistory get latest labels revision and plus 1  and save current label stats to history, then update current revision to db
 func (s *MongodbService) AddHistory(ctx context.Context, labelID string, labels map[string]string, domain string) (int, error) {
 	r, err := s.getLatestLabel(ctx, labelID)
 	if err != nil {
diff --git a/server/dao/options.go b/server/dao/options.go
index 7e33798..fbbe031 100644
--- a/server/dao/options.go
+++ b/server/dao/options.go
@@ -17,6 +17,7 @@
 
 package dao
 
+//FindOptions is option to find key value
 type FindOptions struct {
 	ExactLabels bool
 	Depth       int
@@ -26,6 +27,7 @@ type FindOptions struct {
 	ClearLabel  bool
 }
 
+//FindOption is functional option to find key value
 type FindOption func(*FindOptions)
 
 //WithExactLabels tell model service to return only one kv matches the labels
@@ -49,7 +51,7 @@ func WithLabels(labels map[string]string) FindOption {
 	}
 }
 
-//WithLabels find kv by labelID
+//WithLabelID find kv by labelID
 func WithLabelID(label string) FindOption {
 	return func(o *FindOptions) {
 		o.LabelID = label
diff --git a/server/dao/tool.go b/server/dao/tool.go
index b3d5ea4..08ff602 100644
--- a/server/dao/tool.go
+++ b/server/dao/tool.go
@@ -17,7 +17,12 @@
 
 package dao
 
-import "github.com/apache/servicecomb-kie/pkg/model"
+import (
+	"context"
+	"github.com/apache/servicecomb-kie/pkg/model"
+	"github.com/go-mesh/openlogging"
+	"go.mongodb.org/mongo-driver/mongo"
+)
 
 //clearKV clean attr which don't need to return to client side
 func clearKV(kv *model.KVDoc) {
@@ -25,3 +30,36 @@ func clearKV(kv *model.KVDoc) {
 	kv.Labels = nil
 	kv.LabelID = ""
 }
+
+func cursorToOneKV(ctx context.Context, cur *mongo.Cursor, labels map[string]string) ([]*model.KVResponse, error) {
+	kvResp := make([]*model.KVResponse, 0)
+	curKV := &model.KVDoc{} //reuse this pointer to reduce GC, only clear label
+	//check label length to get the exact match
+	for cur.Next(ctx) { //although complexity is O(n), but there won't be so much labels for one key
+		if cur.Err() != nil {
+			return nil, cur.Err()
+		}
+		curKV.Labels = nil
+		err := cur.Decode(curKV)
+		if err != nil {
+			openlogging.Error("decode error: " + err.Error())
+			return nil, err
+		}
+		if len(curKV.Labels) == len(labels) {
+			openlogging.Debug("hit exact labels")
+			labelGroup := &model.KVResponse{
+				LabelDoc: &model.LabelDocResponse{
+					Labels:  labels,
+					LabelID: curKV.LabelID,
+				},
+				Data: make([]*model.KVDoc, 0),
+			}
+			clearKV(curKV)
+			labelGroup.Data = append(labelGroup.Data, curKV)
+			kvResp = append(kvResp, labelGroup)
+			return kvResp, nil
+		}
+
+	}
+	return nil, ErrKeyNotExists
+}
diff --git a/server/handler/noop_auth_handler.go b/server/handler/noop_auth_handler.go
index b2c4a20..b4a3833 100644
--- a/server/handler/noop_auth_handler.go
+++ b/server/handler/noop_auth_handler.go
@@ -26,6 +26,7 @@ import (
 //developer can extend authenticate and authorization by set new handler in chassis.yaml
 type NoopAuthHandler struct{}
 
+//Handle set local attribute to http request
 func (bk *NoopAuthHandler) Handle(chain *handler.Chain, inv *invocation.Invocation, cb invocation.ResponseCallBack) {
 	inv.SetMetadata("domain", "default")
 	chain.Next(inv, cb)
@@ -35,6 +36,7 @@ func newDomainResolver() handler.Handler {
 	return &NoopAuthHandler{}
 }
 
+//Name is handler name
 func (bk *NoopAuthHandler) Name() string {
 	return "auth-handler"
 }
diff --git a/server/resource/v1/common.go b/server/resource/v1/common.go
index eca9fef..48baa22 100644
--- a/server/resource/v1/common.go
+++ b/server/resource/v1/common.go
@@ -27,11 +27,8 @@ import (
 	"strconv"
 )
 
+//const of server
 const (
-	HeaderTenant = "X-Domain-Name"
-
-	FindExact               = "exact"
-	FindMany                = "greedy"
 	MsgDomainMustNotBeEmpty = "domain must not be empty"
 	MsgIllegalFindPolicy    = "value of header " + common.HeaderMatch + " can be greedy or exact"
 	MsgIllegalLabels        = "label's value can not be empty, " +
@@ -40,9 +37,12 @@ const (
 	ErrIDMustNotEmpty = "must supply id if you want to remove key"
 )
 
+//ReadDomain get domain info from attribute
 func ReadDomain(context *restful.Context) interface{} {
 	return context.ReadRestfulRequest().Attribute("domain")
 }
+
+//ReadFindDepth get find depth
 func ReadFindDepth(context *restful.Context) (int, error) {
 	d := context.ReadRestfulRequest().HeaderParameter(common.HeaderDepth)
 	if d == "" {
@@ -54,6 +54,8 @@ func ReadFindDepth(context *restful.Context) (int, error) {
 	}
 	return depth, nil
 }
+
+//ReadMatchPolicy get match policy
 func ReadMatchPolicy(context *restful.Context) string {
 	policy := context.ReadRestfulRequest().HeaderParameter(common.HeaderMatch)
 	if policy == "" {
@@ -62,16 +64,20 @@ func ReadMatchPolicy(context *restful.Context) string {
 	}
 	return policy
 }
+
+//WriteErrResponse write error message to client
 func WriteErrResponse(context *restful.Context, status int, msg string) {
 	context.WriteHeader(status)
 	b, _ := json.MarshalIndent(&ErrorMsg{Msg: msg}, "", " ")
 	context.Write(b)
 }
 
+//ErrLog record error
 func ErrLog(action string, kv *model.KVDoc, err error) {
 	openlogging.Error(fmt.Sprintf("[%s] [%v] err:%s", action, kv, err.Error()))
 }
 
+//InfoLog record info
 func InfoLog(action string, kv *model.KVDoc) {
 	openlogging.Info(
 		fmt.Sprintf("[%s] [%s:%s] in [%s] success", action, kv.Key, kv.Value, kv.Domain))
diff --git a/server/resource/v1/doc_struct.go b/server/resource/v1/doc_struct.go
index a0402ae..37f7432 100644
--- a/server/resource/v1/doc_struct.go
+++ b/server/resource/v1/doc_struct.go
@@ -17,12 +17,41 @@
 
 package v1
 
+import (
+	"github.com/apache/servicecomb-kie/pkg/common"
+	goRestful "github.com/emicklei/go-restful"
+	"github.com/go-chassis/go-chassis/server/restful"
+)
+
+//swagger doc elements
+var (
+	DocHeaderDepth = &restful.Parameters{
+		DataType:  "string",
+		Name:      common.HeaderDepth,
+		ParamType: goRestful.HeaderParameterKind,
+		Desc:      "integer, default is 1, if you set match policy, you can set,depth to decide label number",
+	}
+	DocPathKey = &restful.Parameters{
+		DataType:  "string",
+		Name:      "key",
+		ParamType: goRestful.PathParameterKind,
+	}
+	DocHeaderMath = &restful.Parameters{
+		DataType:  "string",
+		Name:      common.HeaderMatch,
+		ParamType: goRestful.HeaderParameterKind,
+		Desc:      "greedy or exact",
+	}
+)
+
+//KVBody is open api doc
 type KVBody struct {
 	Labels    map[string]string `json:"labels"`
 	ValueType string            `json:"valueType"`
 	Value     string            `json:"value"`
 }
 
+//ErrorMsg is open api doc
 type ErrorMsg struct {
 	Msg string `json:"msg"`
 }
diff --git a/server/resource/v1/history_resource.go b/server/resource/v1/history_resource.go
index 3952a19..0bca053 100644
--- a/server/resource/v1/history_resource.go
+++ b/server/resource/v1/history_resource.go
@@ -17,5 +17,6 @@
 
 package v1
 
+//HistoryResource TODO
 type HistoryResource struct {
 }
diff --git a/server/resource/v1/kv_resource.go b/server/resource/v1/kv_resource.go
index 7832f23..a1f94b6 100644
--- a/server/resource/v1/kv_resource.go
+++ b/server/resource/v1/kv_resource.go
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-//v1 package hold http rest v1 API
+//Package v1 hold http rest v1 API
 package v1
 
 import (
@@ -31,9 +31,11 @@ import (
 	"strings"
 )
 
+//KVResource has API about kv operations
 type KVResource struct {
 }
 
+//Put create or update kv
 func (r *KVResource) Put(context *restful.Context) {
 	var err error
 	key := context.ReadPathParameter("key")
@@ -64,6 +66,8 @@ func (r *KVResource) Put(context *restful.Context) {
 	context.WriteHeaderAndJSON(http.StatusOK, kv, goRestful.MIME_JSON)
 
 }
+
+//FindWithKey search key by label and key
 func (r *KVResource) FindWithKey(context *restful.Context) {
 	var err error
 	key := context.ReadPathParameter("key")
@@ -121,6 +125,8 @@ func (r *KVResource) FindWithKey(context *restful.Context) {
 	}
 
 }
+
+//FindByLabels search key only by label
 func (r *KVResource) FindByLabels(context *restful.Context) {
 	var err error
 	values := context.ReadRequest().URL.Query()
@@ -169,6 +175,8 @@ func (r *KVResource) FindByLabels(context *restful.Context) {
 	}
 
 }
+
+//Delete deletes key by ids
 func (r *KVResource) Delete(context *restful.Context) {
 	domain := ReadDomain(context)
 	if domain == nil {
@@ -203,16 +211,7 @@ func (r *KVResource) URLPatterns() []restful.Route {
 			ResourceFuncName: "Put",
 			FuncDesc:         "create or update key value",
 			Parameters: []*restful.Parameters{
-				{
-					DataType:  "string",
-					Name:      "key",
-					ParamType: goRestful.PathParameterKind,
-				}, {
-					DataType:  "string",
-					Name:      HeaderTenant,
-					ParamType: goRestful.HeaderParameterKind,
-					Desc:      "set kv to other tenant",
-				}, {
+				DocPathKey, {
 					DataType:  "string",
 					Name:      "X-Realm",
 					ParamType: goRestful.HeaderParameterKind,
@@ -234,20 +233,7 @@ func (r *KVResource) URLPatterns() []restful.Route {
 			ResourceFuncName: "FindWithKey",
 			FuncDesc:         "get key values by key and labels",
 			Parameters: []*restful.Parameters{
-				{
-					DataType:  "string",
-					Name:      "key",
-					ParamType: goRestful.PathParameterKind,
-				}, {
-					DataType:  "string",
-					Name:      HeaderTenant,
-					ParamType: goRestful.HeaderParameterKind,
-				}, {
-					DataType:  "string",
-					Name:      common.HeaderMatch,
-					ParamType: goRestful.HeaderParameterKind,
-					Desc:      "greedy or exact",
-				},
+				DocPathKey, DocHeaderMath, DocHeaderDepth,
 			},
 			Returns: []*restful.Returns{
 				{
@@ -265,16 +251,7 @@ func (r *KVResource) URLPatterns() []restful.Route {
 			ResourceFuncName: "FindByLabels",
 			FuncDesc:         "find key values only by labels",
 			Parameters: []*restful.Parameters{
-				{
-					DataType:  "string",
-					Name:      HeaderTenant,
-					ParamType: goRestful.HeaderParameterKind,
-				}, {
-					DataType:  "string",
-					Name:      common.HeaderMatch,
-					ParamType: goRestful.HeaderParameterKind,
-					Desc:      "greedy or exact",
-				},
+				DocHeaderMath, DocHeaderDepth,
 			},
 			Returns: []*restful.Returns{
 				{
@@ -290,18 +267,13 @@ func (r *KVResource) URLPatterns() []restful.Route {
 			Path:             "/v1/kv/{ids}",
 			ResourceFuncName: "Delete",
 			FuncDesc:         "delete key by id,separated by ','",
-			Parameters: []*restful.Parameters{
-				{
-					DataType:  "string",
-					Name:      HeaderTenant,
-					ParamType: goRestful.HeaderParameterKind,
-				}, {
-					DataType:  "string",
-					Name:      "ids",
-					ParamType: goRestful.PathParameterKind,
-					Desc: "The id strings to be removed are separated by ',',If the actual number of deletions " +
-						"and the number of parameters are not equal, no error will be returned and only warn log will be printed.",
-				},
+			Parameters: []*restful.Parameters{{
+				DataType:  "string",
+				Name:      "ids",
+				ParamType: goRestful.PathParameterKind,
+				Desc: "The id strings to be removed are separated by ',',If the actual number of deletions " +
+					"and the number of parameters are not equal, no error will be returned and only warn log will be printed.",
+			},
 			},
 			Returns: []*restful.Returns{
 				{


[servicecomb-kie] 01/29: Init the project documents

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

asifdxtreme pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git

commit e66eaec7b280a60ba4d94f88a660da201b7d6e91
Author: Willem Jiang <ji...@huawei.com>
AuthorDate: Mon Apr 29 14:23:28 2019 +0800

    Init the project documents
---
 .gitignore |  24 ++++++++
 LICENSE    | 201 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 NOTICE     |   5 ++
 README.md  |  19 ++++++
 4 files changed, 249 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..901a1e4
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,24 @@
+bin/
+output
+**/*.coverprofile
+**/coverage.out
+**/coverage.txt
+**/*.log
+
+*.iml
+.idea/
+**/*junit.xml
+**/*.exe
+**/*.tgz
+
+vendor/**
+!vendor/manifest
+
+# for local UT
+**/conf/
+!etc/conf/
+etc/data/
+etc/ssl/
+tmp/
+glide.lock
+go.sum
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..8dada3e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   Licensed 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.
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..effa6a2
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,5 @@
+Apache ServiceComb Kie
+Copyright 2019-2019 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..91353db
--- /dev/null
+++ b/README.md
@@ -0,0 +1,19 @@
+# Apache-ServiceComb-Kie
+
+Introduction of the project
+
+## Features
+
+## Quick Start
+
+## Contact
+
+Bugs: [issues](https://issues.apache.org/jira/browse/SCB)
+
+## Contributing
+
+See [Contribution guide](/CONTRIBUTING.md) for details on submitting patches and the contribution workflow.
+
+## Reporting Issues
+
+See reporting bugs for details about reporting any issues.


[servicecomb-kie] 29/29: Merge pull request #13 from tianxiaoliang/master

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

asifdxtreme pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git

commit 674592695778b42a5704bc1cfe4a5533e3bc8370
Merge: 6e9a59f bf3c4d6
Author: Mohammad Asif Siddiqui <mo...@huawei.com>
AuthorDate: Thu Jun 27 17:23:06 2019 +0530

    Merge pull request #13 from tianxiaoliang/master
    
    SCB-1320 support combination query

 go.mod                                             |  5 +-
 pkg/common/common.go                               |  3 +-
 server/config/config.go                            |  4 +-
 server/dao/kie_api.go                              | 24 ++++--
 server/dao/kv_test.go                              |  8 +-
 server/resource/v1/common.go                       | 34 +++++++--
 server/resource/v1/common_test.go                  | 64 ++++++++++++++++
 server/resource/v1/doc_struct.go                   | 14 ++--
 server/resource/v1/kv_resource.go                  | 89 +++++++++-------------
 .../resource/v1/v1_suite_test.go                   | 21 +++--
 10 files changed, 171 insertions(+), 95 deletions(-)


[servicecomb-kie] 05/29: fix based on comments

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

asifdxtreme pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git

commit 65b7c24d6ae13148b2dc463460d2aaa8bdedff32
Author: tian <xi...@gmail.com>
AuthorDate: Tue May 7 20:16:45 2019 +0800

    fix based on comments
---
 deployments/docker/docker-compose.yaml | 16 ++++++++++++++++
 pkg/model/kv.go                        |  8 --------
 2 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/deployments/docker/docker-compose.yaml b/deployments/docker/docker-compose.yaml
index 2c87590..700fa28 100644
--- a/deployments/docker/docker-compose.yaml
+++ b/deployments/docker/docker-compose.yaml
@@ -1,3 +1,19 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
 version: '3.1'
 services:
   mongo:
diff --git a/pkg/model/kv.go b/pkg/model/kv.go
index 1c31fc0..042cd20 100644
--- a/pkg/model/kv.go
+++ b/pkg/model/kv.go
@@ -23,14 +23,6 @@ import (
 
 type Labels map[string]string
 
-//func (m Labels) ToString() string {
-//	sb := strings.Builder{}
-//	for k, v := range m {
-//		sb.WriteString(k + "=" + v + ",")
-//	}
-//	return sb.String()
-//}
-
 type KV struct {
 	ID        primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"`
 	Key       string             `json:"key"`


[servicecomb-kie] 11/29: Merge pull request #5 from tianxiaoliang/master

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

asifdxtreme pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git

commit cd39e571fd49d7f25ae83b3509263efa2f0585e3
Merge: ebcea39 e2b4384
Author: Mohammad Asif Siddiqui <mo...@huawei.com>
AuthorDate: Fri May 24 15:00:43 2019 +0530

    Merge pull request #5 from tianxiaoliang/master
    
    add go client, return 404 if key not exist

 build/build_server.sh                              |   6 +-
 client/client.go                                   | 106 +++++++++++++++++++++
 .../client_suite_test.go                           |   6 +-
 client/client_test.go                              |  65 +++++++++++++
 .../dao/model_suite_test.go => client/options.go   |  37 +++----
 go.mod                                             |   1 +
 .../model_suite_test.go => pkg/common/common.go    |  31 ++----
 .../dao/{model_suite_test.go => dao_suite_test.go} |   2 +-
 server/resource/v1/common.go                       |  12 +--
 server/resource/v1/kv_resource.go                  |  29 ++++--
 10 files changed, 228 insertions(+), 67 deletions(-)


[servicecomb-kie] 06/29: Merge pull request #2 from tianxiaoliang/master

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

asifdxtreme pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git

commit 151158fd1e9ce7c3fe8650b587f0f8520afcddcd
Merge: a1c0700 65b7c24
Author: little-cui <su...@qq.com>
AuthorDate: Thu May 9 16:12:43 2019 +0800

    Merge pull request #2 from tianxiaoliang/master
    
    add kv data access api

 deployments/docker/docker-compose.yaml |  35 ++++
 go.mod                                 |  16 ++
 pkg/model/kv.go                        |  41 +++++
 pkg/model/kv_test.go                   |  45 +++++
 server/config/config.go                |  44 +++++
 server/config/config_test.go           |  51 ++++++
 server/config/struct.go                |  29 ++++
 server/kv/errors.go                    |  35 ++++
 server/kv/kv.go                        |  62 +++++++
 server/kv/kv_test.go                   | 192 +++++++++++++++++++++
 server/kv/model_suite_test.go          |  44 +++++
 server/kv/mongodb.go                   | 304 +++++++++++++++++++++++++++++++++
 server/kv/options.go                   |  49 ++++++
 13 files changed, 947 insertions(+)


[servicecomb-kie] 13/29: use const

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

asifdxtreme pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git

commit 272ca4a9d8db8a2eec924a25be3eae693dc4405a
Author: wangqijun <wa...@sohu.com>
AuthorDate: Sat May 25 16:07:08 2019 +0800

    use const
---
 server/resource/v1/common.go      |  1 +
 server/resource/v1/kv_resource.go | 20 ++++++++++----------
 2 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/server/resource/v1/common.go b/server/resource/v1/common.go
index e246602..c9fb5bb 100644
--- a/server/resource/v1/common.go
+++ b/server/resource/v1/common.go
@@ -27,6 +27,7 @@ import (
 )
 
 const (
+	TenantHeaderParam       = "X-Domain-Name"
 	FindExact               = "exact"
 	FindMany                = "greedy"
 	MsgDomainMustNotBeEmpty = "domain must not be empty"
diff --git a/server/resource/v1/kv_resource.go b/server/resource/v1/kv_resource.go
index 4839279..0ecd74c 100644
--- a/server/resource/v1/kv_resource.go
+++ b/server/resource/v1/kv_resource.go
@@ -200,7 +200,7 @@ func (r *KVResource) URLPatterns() []restful.Route {
 					ParamType: goRestful.PathParameterKind,
 				}, {
 					DataType:  "string",
-					Name:      "X-Domain-Name",
+					Name:      TenantHeaderParam,
 					ParamType: goRestful.HeaderParameterKind,
 					Desc:      "set kv to other tenant",
 				}, {
@@ -216,8 +216,8 @@ func (r *KVResource) URLPatterns() []restful.Route {
 					Message: "true",
 				},
 			},
-			Consumes: []string{"application/json"},
-			Produces: []string{"application/json"},
+			Consumes: []string{goRestful.MIME_JSON},
+			Produces: []string{goRestful.MIME_JSON},
 			Read:     &KVBody{},
 		}, {
 			Method:           http.MethodGet,
@@ -231,7 +231,7 @@ func (r *KVResource) URLPatterns() []restful.Route {
 					ParamType: goRestful.PathParameterKind,
 				}, {
 					DataType:  "string",
-					Name:      "X-Domain-Name",
+					Name:      TenantHeaderParam,
 					ParamType: goRestful.HeaderParameterKind,
 				}, {
 					DataType:  "string",
@@ -247,8 +247,8 @@ func (r *KVResource) URLPatterns() []restful.Route {
 					Model:   []*KVBody{},
 				},
 			},
-			Consumes: []string{"application/json"},
-			Produces: []string{"application/json"},
+			Consumes: []string{goRestful.MIME_JSON},
+			Produces: []string{goRestful.MIME_JSON},
 			Read:     &KVBody{},
 		}, {
 			Method:           http.MethodGet,
@@ -258,7 +258,7 @@ func (r *KVResource) URLPatterns() []restful.Route {
 			Parameters: []*restful.Parameters{
 				{
 					DataType:  "string",
-					Name:      "X-Domain-Name",
+					Name:      TenantHeaderParam,
 					ParamType: goRestful.HeaderParameterKind,
 				}, {
 					DataType:  "string",
@@ -274,8 +274,8 @@ func (r *KVResource) URLPatterns() []restful.Route {
 					Model:   []*KVBody{},
 				},
 			},
-			Consumes: []string{"application/json"},
-			Produces: []string{"application/json"},
+			Consumes: []string{goRestful.MIME_JSON},
+			Produces: []string{goRestful.MIME_JSON},
 		}, {
 			Method:           http.MethodDelete,
 			Path:             "/v1/kv/{ids}",
@@ -284,7 +284,7 @@ func (r *KVResource) URLPatterns() []restful.Route {
 			Parameters: []*restful.Parameters{
 				{
 					DataType:  "string",
-					Name:      "X-Domain-Name",
+					Name:      TenantHeaderParam,
 					ParamType: goRestful.HeaderParameterKind,
 				}, {
 					DataType:  "string",


[servicecomb-kie] 27/29: add license header

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

asifdxtreme pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git

commit 2990828f8e39eb7e97810a5f6771181f0a945e08
Author: tian <xi...@gmail.com>
AuthorDate: Thu Jun 20 09:39:54 2019 +0800

    add license header
---
 server/resource/v1/common_test.go | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/server/resource/v1/common_test.go b/server/resource/v1/common_test.go
index 6f3b139..d662799 100644
--- a/server/resource/v1/common_test.go
+++ b/server/resource/v1/common_test.go
@@ -1,3 +1,20 @@
+/*
+ * 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 v1_test
 
 import (


[servicecomb-kie] 16/29: SCB-1311 Merge pull request #7 from tianxiaoliang/master

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

asifdxtreme pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git

commit 818dd480d8eabc17816f55278880bf5630eb881e
Merge: 272ca4a 9597250
Author: Willem Jiang <ji...@huawei.com>
AuthorDate: Thu Jun 6 17:44:51 2019 +0800

    SCB-1311 Merge pull request #7 from tianxiaoliang/master
    
    SCB-1311 redesign database to make service faster and more ease of use

 client/client.go                                   |   6 +-
 client/client_suite_test.go                        |   2 +
 client/client_test.go                              |   2 +-
 client/options.go                                  |   6 +-
 go.mod                                             |   4 +-
 pkg/common/common.go                               |   1 +
 pkg/model/kv.go                                    |  24 +-
 pkg/model/kv_test.go                               |   4 +-
 pkg/model/mongodb_doc.go                           |  47 +++
 proxy.sh                                           |  16 +
 scripts/start.sh                                   |  18 +-
 server/dao/errors.go                               |   7 +-
 server/dao/kie_api.go                              | 381 +++++++++++++++++++++
 server/dao/kv.go                                   |  73 +++-
 server/dao/kv_test.go                              |  79 +++--
 server/dao/label.go                                |  69 ++++
 server/dao/label_history.go                        | 111 ++++++
 server/dao/mongodb.go                              | 340 ------------------
 server/dao/mongodb_operator.go                     |  95 +++++
 server/dao/options.go                              |  30 +-
 server/resource/v1/common.go                       |  20 +-
 .../resource/v1/history_resource.go                |  12 +-
 server/resource/v1/kv_resource.go                  |  41 ++-
 23 files changed, 929 insertions(+), 459 deletions(-)


[servicecomb-kie] 28/29: fix bug: if find by labels, will lose key value record

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

asifdxtreme pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git

commit bf3c4d6121be294afd97b706b356481e6ea5c1a8
Author: tian <xi...@gmail.com>
AuthorDate: Thu Jun 27 15:54:06 2019 +0800

    fix bug: if find by labels, will lose key value record
---
 go.mod                              |  2 +-
 server/config/config.go             |  4 ++--
 server/dao/kie_api.go               | 19 +++++++++++++++++--
 server/resource/v1/common.go        |  3 +++
 server/resource/v1/common_test.go   | 16 ++++++++++++++++
 server/resource/v1/kv_resource.go   | 14 +++++++-------
 server/resource/v1/v1_suite_test.go | 17 +++++++++++++++++
 7 files changed, 63 insertions(+), 12 deletions(-)

diff --git a/go.mod b/go.mod
index 6646204..2540c72 100644
--- a/go.mod
+++ b/go.mod
@@ -3,7 +3,7 @@ module github.com/apache/servicecomb-kie
 require (
 	github.com/emicklei/go-restful v2.8.0+incompatible
 	github.com/go-chassis/foundation v0.0.0-20190516083152-b8b2476b6db7
-	github.com/go-chassis/go-archaius v0.16.0
+	github.com/go-chassis/go-archaius v0.18.0
 	github.com/go-chassis/go-chassis v1.4.3
 	github.com/go-chassis/paas-lager v1.0.2-0.20190328010332-cf506050ddb2
 	github.com/go-mesh/openlogging v1.0.1-0.20181205082104-3d418c478b2d
diff --git a/server/config/config.go b/server/config/config.go
index 76571de..36b66c2 100644
--- a/server/config/config.go
+++ b/server/config/config.go
@@ -19,7 +19,7 @@ package config
 
 import (
 	"github.com/go-chassis/go-archaius"
-	"github.com/go-chassis/go-archaius/sources/file-source"
+	"github.com/go-chassis/go-archaius/sources/utils"
 	"gopkg.in/yaml.v2"
 	"path/filepath"
 )
@@ -28,7 +28,7 @@ var configurations *Config
 
 //Init initiate config files
 func Init(file string) error {
-	if err := archaius.AddFile(file, archaius.WithFileHandler(filesource.UseFileNameAsKeyContentAsValue)); err != nil {
+	if err := archaius.AddFile(file, archaius.WithFileHandler(utils.UseFileNameAsKeyContentAsValue)); err != nil {
 		return err
 	}
 	_, filename := filepath.Split(file)
diff --git a/server/dao/kie_api.go b/server/dao/kie_api.go
index 0e0020d..5e641aa 100644
--- a/server/dao/kie_api.go
+++ b/server/dao/kie_api.go
@@ -58,6 +58,11 @@ func (s *MongodbService) CreateOrUpdate(ctx context.Context, domain string, kv *
 	if domain == "" {
 		return nil, ErrMissingDomain
 	}
+	if len(kv.Labels) == 0 {
+		kv.Labels = map[string]string{
+			"default": "default",
+		}
+	}
 	ctx, _ = context.WithTimeout(ctx, DefaultTimeout)
 	//check labels exits or not
 	labelID, err := s.LabelsExist(ctx, domain, kv.Labels)
@@ -66,6 +71,10 @@ func (s *MongodbService) CreateOrUpdate(ctx context.Context, domain string, kv *
 		if err == ErrLabelNotExists {
 			l, err = s.createLabel(ctx, domain, kv.Labels)
 			if err != nil {
+				openlogging.Error("create label failed", openlogging.WithTags(openlogging.Tags{
+					"k":      kv.Key,
+					"domain": kv.Domain,
+				}))
 				return nil, err
 			}
 			labelID = l.ID
@@ -96,6 +105,7 @@ func (s *MongodbService) CreateOrUpdate(ctx context.Context, domain string, kv *
 		return nil, err
 	}
 	kv.Revision = revision
+	kv.Domain = ""
 	return kv, nil
 
 }
@@ -208,7 +218,7 @@ func (s *MongodbService) FindKV(ctx context.Context, domain string, options ...F
 	defer cur.Close(ctx)
 
 	kvResp := make([]*model.KVResponse, 0)
-	if opts.Depth == 0 {
+	if opts.Depth == 0 && opts.Key != "" {
 		openlogging.Debug("find one key", openlogging.WithTags(
 			map[string]interface{}{
 				"key":    opts.Key,
@@ -218,6 +228,11 @@ func (s *MongodbService) FindKV(ctx context.Context, domain string, options ...F
 		))
 		return cursorToOneKV(ctx, cur, opts.Labels)
 	}
+	openlogging.Debug("find more", openlogging.WithTags(openlogging.Tags{
+		"depth":  opts.Depth,
+		"k":      opts.Key,
+		"labels": opts.Labels,
+	}))
 	for cur.Next(ctx) {
 		curKV := &model.KVDoc{}
 
@@ -231,7 +246,7 @@ func (s *MongodbService) FindKV(ctx context.Context, domain string, options ...F
 			openlogging.Debug("so deep, skip this key")
 			continue
 		}
-		openlogging.Info(fmt.Sprintf("%v", curKV))
+		openlogging.Debug(fmt.Sprintf("%v", curKV))
 		var groupExist bool
 		var labelGroup *model.KVResponse
 		for _, labelGroup = range kvResp {
diff --git a/server/resource/v1/common.go b/server/resource/v1/common.go
index dcf9901..9b01260 100644
--- a/server/resource/v1/common.go
+++ b/server/resource/v1/common.go
@@ -77,6 +77,9 @@ func ReadLabelCombinations(req *goRestful.Request) ([]map[string]string, error)
 		}
 		labelCombinations = append(labelCombinations, labels)
 	}
+	if len(labelCombinations) == 0 {
+		return []map[string]string{{"default": "default"}}, nil
+	}
 	return labelCombinations, nil
 }
 
diff --git a/server/resource/v1/common_test.go b/server/resource/v1/common_test.go
index d662799..792383c 100644
--- a/server/resource/v1/common_test.go
+++ b/server/resource/v1/common_test.go
@@ -44,5 +44,21 @@ var _ = Describe("Common", func() {
 			})
 
 		})
+		Context("find default", func() {
+			r, err := http.NewRequest("GET",
+				"/kv",
+				nil)
+			It("should not return err ", func() {
+				Expect(err).Should(BeNil())
+			})
+			c, err := ReadLabelCombinations(restful.NewRequest(r))
+			It("should not return err ", func() {
+				Expect(err).Should(BeNil())
+			})
+			It("should has 1 combinations", func() {
+				Expect(len(c)).Should(Equal(1))
+			})
+
+		})
 	})
 })
diff --git a/server/resource/v1/kv_resource.go b/server/resource/v1/kv_resource.go
index c072dc6..832dae7 100644
--- a/server/resource/v1/kv_resource.go
+++ b/server/resource/v1/kv_resource.go
@@ -99,11 +99,11 @@ func (r *KVResource) GetByKey(context *restful.Context) {
 		return
 	}
 	kvs, err := s.FindKV(context.Ctx, domain.(string), dao.WithKey(key), dao.WithLabels(labels), dao.WithDepth(d))
-	if err == dao.ErrKeyNotExists {
-		WriteErrResponse(context, http.StatusNotFound, err.Error())
-		return
-	}
 	if err != nil {
+		if err == dao.ErrKeyNotExists {
+			WriteErrResponse(context, http.StatusNotFound, err.Error())
+			return
+		}
 		WriteErrResponse(context, http.StatusInternalServerError, err.Error())
 		return
 	}
@@ -146,7 +146,7 @@ func (r *KVResource) SearchByLabels(context *restful.Context) {
 
 	}
 	if len(kvs) == 0 {
-		WriteErrResponse(context, http.StatusNotFound, err.Error())
+		WriteErrResponse(context, http.StatusNotFound, "no kv found")
 		return
 	}
 
@@ -214,7 +214,7 @@ func (r *KVResource) URLPatterns() []restful.Route {
 			ResourceFuncName: "GetByKey",
 			FuncDesc:         "get key values by key and labels",
 			Parameters: []*restful.Parameters{
-				DocPathKey, DocHeaderMath, DocHeaderDepth,
+				DocPathKey, DocHeaderDepth,
 			},
 			Returns: []*restful.Returns{
 				{
@@ -232,7 +232,7 @@ func (r *KVResource) URLPatterns() []restful.Route {
 			ResourceFuncName: "SearchByLabels",
 			FuncDesc:         "search key values by labels combination",
 			Parameters: []*restful.Parameters{
-				DocHeaderMath, DocQueryCombination,
+				DocQueryCombination,
 			},
 			Returns: []*restful.Returns{
 				{
diff --git a/server/resource/v1/v1_suite_test.go b/server/resource/v1/v1_suite_test.go
index 23b7482..99a2884 100644
--- a/server/resource/v1/v1_suite_test.go
+++ b/server/resource/v1/v1_suite_test.go
@@ -1,3 +1,20 @@
+/*
+ * 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 v1_test
 
 import (


[servicecomb-kie] 04/29: add kv data access api

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

asifdxtreme pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git

commit 6afc216839e28680776a539407cfb30cf83ecd5d
Author: tian <xi...@gmail.com>
AuthorDate: Tue May 7 19:25:30 2019 +0800

    add kv data access api
---
 deployments/docker/docker-compose.yaml |  19 +++
 go.mod                                 |  16 ++
 pkg/model/kv.go                        |  49 ++++++
 pkg/model/kv_test.go                   |  45 +++++
 server/config/config.go                |  44 +++++
 server/config/config_test.go           |  51 ++++++
 server/config/struct.go                |  29 ++++
 server/kv/errors.go                    |  35 ++++
 server/kv/kv.go                        |  62 +++++++
 server/kv/kv_test.go                   | 192 +++++++++++++++++++++
 server/kv/model_suite_test.go          |  44 +++++
 server/kv/mongodb.go                   | 304 +++++++++++++++++++++++++++++++++
 server/kv/options.go                   |  49 ++++++
 13 files changed, 939 insertions(+)

diff --git a/deployments/docker/docker-compose.yaml b/deployments/docker/docker-compose.yaml
new file mode 100644
index 0000000..2c87590
--- /dev/null
+++ b/deployments/docker/docker-compose.yaml
@@ -0,0 +1,19 @@
+version: '3.1'
+services:
+  mongo:
+    image: mongo
+    restart: always
+    ports:
+      - 27017:27017
+    environment:
+      MONGO_INITDB_ROOT_USERNAME: kie
+      MONGO_INITDB_ROOT_PASSWORD: 123
+
+  mongo-express:
+    image: mongo-express
+    restart: always
+    ports:
+      - 8081:8081
+    environment:
+      ME_CONFIG_MONGODB_ADMINUSERNAME: kie
+      ME_CONFIG_MONGODB_ADMINPASSWORD: 123
\ No newline at end of file
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..da3d3eb
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,16 @@
+module github.com/apache/servicecomb-kie
+
+require (
+	github.com/go-chassis/go-archaius v0.14.0
+	github.com/go-chassis/go-chassis v1.4.0 // indirect
+	github.com/go-chassis/paas-lager v1.0.2-0.20190328010332-cf506050ddb2
+	github.com/go-mesh/openlogging v1.0.1-0.20181205082104-3d418c478b2d
+	github.com/onsi/ginkgo v1.8.0
+	github.com/onsi/gomega v1.5.0
+	github.com/stretchr/testify v1.2.2
+	github.com/urfave/cli v1.20.0 // indirect
+	github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c // indirect
+	github.com/xdg/stringprep v1.0.0 // indirect
+	go.mongodb.org/mongo-driver v1.0.0
+	gopkg.in/yaml.v2 v2.2.1
+)
diff --git a/pkg/model/kv.go b/pkg/model/kv.go
new file mode 100644
index 0000000..1c31fc0
--- /dev/null
+++ b/pkg/model/kv.go
@@ -0,0 +1,49 @@
+/*
+ * 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 model
+
+import (
+	"go.mongodb.org/mongo-driver/bson/primitive"
+)
+
+type Labels map[string]string
+
+//func (m Labels) ToString() string {
+//	sb := strings.Builder{}
+//	for k, v := range m {
+//		sb.WriteString(k + "=" + v + ",")
+//	}
+//	return sb.String()
+//}
+
+type KV struct {
+	ID        primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"`
+	Key       string             `json:"key"`
+	Value     string             `json:"value"`
+	ValueType string             `json:"valueType"`        //ini,json,text,yaml,properties
+	Domain    string             `json:"domain"`           //tenant info
+	Labels    map[string]string  `json:"labels,omitempty"` //key has labels
+	Checker   string             `json:"check,omitempty"`  //python script
+	Revision  int                `json:"revision"`
+}
+type KVHistory struct {
+	KID      string `json:"id,omitempty" bson:"kvID"`
+	Value    string `json:"value"`
+	Checker  string `json:"check,omitempty"` //python script
+	Revision int    `json:"revision"`
+}
diff --git a/pkg/model/kv_test.go b/pkg/model/kv_test.go
new file mode 100644
index 0000000..cbb05c0
--- /dev/null
+++ b/pkg/model/kv_test.go
@@ -0,0 +1,45 @@
+/*
+ * 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 model_test
+
+import (
+	"encoding/json"
+	"github.com/apache/servicecomb-kie/pkg/model"
+	"github.com/stretchr/testify/assert"
+	"testing"
+)
+
+func TestKV_UnmarshalJSON(t *testing.T) {
+	kv := &model.KV{
+		Value: "test",
+		Labels: map[string]string{
+			"test": "env",
+		},
+	}
+	b, _ := json.Marshal(kv)
+	t.Log(string(b))
+
+	var kv2 model.KV
+	err := json.Unmarshal([]byte(` 
+        {"value": "1","labels":{"test":"env"}}
+    `), &kv2)
+	assert.NoError(t, err)
+	assert.Equal(t, "env", kv2.Labels["test"])
+	assert.Equal(t, "1", kv2.Value)
+
+}
diff --git a/server/config/config.go b/server/config/config.go
new file mode 100644
index 0000000..7e03731
--- /dev/null
+++ b/server/config/config.go
@@ -0,0 +1,44 @@
+/*
+ * 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 config
+
+import (
+	"github.com/go-chassis/go-archaius"
+	"github.com/go-chassis/go-archaius/sources/file-source"
+	"gopkg.in/yaml.v2"
+	"path/filepath"
+)
+
+var configurations *Config
+
+func Init(file string) error {
+	if err := archaius.AddFile(file, archaius.WithFileHandler(filesource.UseFileNameAsKeyContentAsValue)); err != nil {
+		return err
+	}
+	_, filename := filepath.Split(file)
+	content := archaius.GetString(filename, "")
+	configurations = &Config{}
+	if err := yaml.Unmarshal([]byte(content), configurations); err != nil {
+		return err
+	}
+	return nil
+}
+
+func GetDB() DB {
+	return configurations.DB
+}
diff --git a/server/config/config_test.go b/server/config/config_test.go
new file mode 100644
index 0000000..75ca3ae
--- /dev/null
+++ b/server/config/config_test.go
@@ -0,0 +1,51 @@
+/*
+ * 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 config_test
+
+import (
+	"github.com/apache/servicecomb-kie/server/config"
+	"github.com/go-chassis/go-archaius"
+	"github.com/stretchr/testify/assert"
+	"io"
+	"os"
+	"testing"
+)
+
+func TestInit(t *testing.T) {
+	err := archaius.Init()
+	assert.NoError(t, err)
+	b := []byte(`
+db:
+  uri: mongodb://admin:123@127.0.0.1:27017/kie
+  type: mongodb
+  poolSize: 10
+  ssl: false
+  sslCA:
+  sslCert:
+
+`)
+	defer os.Remove("test.yaml")
+	f1, err := os.Create("test.yaml")
+	assert.NoError(t, err)
+	_, err = io.WriteString(f1, string(b))
+	assert.NoError(t, err)
+	err = config.Init("test.yaml")
+	assert.NoError(t, err)
+	assert.Equal(t, 10, config.GetDB().PoolSize)
+	assert.Equal(t, "mongodb://admin:123@127.0.0.1:27017/kie", config.GetDB().URI)
+}
diff --git a/server/config/struct.go b/server/config/struct.go
new file mode 100644
index 0000000..cbfb644
--- /dev/null
+++ b/server/config/struct.go
@@ -0,0 +1,29 @@
+/*
+ * 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 config
+
+type Config struct {
+	DB DB `yaml:"db"`
+}
+type DB struct {
+	URI      string   `yaml:"uri"`
+	PoolSize int      `yaml:"poolSize"`
+	SSL      bool     `yaml:"ssl"`
+	CABundle []string `yaml:"sslCA"`
+	Cert     string   `yaml:"sslCert"`
+}
diff --git a/server/kv/errors.go b/server/kv/errors.go
new file mode 100644
index 0000000..958a015
--- /dev/null
+++ b/server/kv/errors.go
@@ -0,0 +1,35 @@
+/*
+ * 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 kv
+
+import (
+	"errors"
+	"fmt"
+
+	"github.com/apache/servicecomb-kie/pkg/model"
+	"github.com/go-mesh/openlogging"
+)
+
+//ErrAction will wrap raw error to biz error and return
+//it record audit log for mongodb operation failure like find, insert, update, deletion
+func ErrAction(action, key string, labels model.Labels, domain string, err error) error {
+	msg := fmt.Sprintf("can not [%s] [%s] in [%s] with [%s],err: %s", action, key, domain, labels, err.Error())
+	openlogging.Error(msg)
+	return errors.New(msg)
+
+}
diff --git a/server/kv/kv.go b/server/kv/kv.go
new file mode 100644
index 0000000..9513e60
--- /dev/null
+++ b/server/kv/kv.go
@@ -0,0 +1,62 @@
+/*
+ * 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 kv
+
+import (
+	"crypto/tls"
+	"errors"
+	"time"
+	"github.com/apache/servicecomb-kie/server/config"
+	"github.com/apache/servicecomb-kie/pkg/model"
+)
+
+var ErrMissingDomain = errors.New("domain info missing, illegal access")
+var ErrNotExists = errors.New("key with labels does not exits")
+var ErrTooMany = errors.New("key with labels should be only one")
+var ErrKeyMustNotEmpty = errors.New("must supply key if you want to get exact one result")
+
+type Service interface {
+	CreateOrUpdate(kv *model.KV) (*model.KV, error)
+	//do not use primitive.ObjectID as return to decouple with mongodb, we can afford perf lost
+	Exist(key, domain string, labels model.Labels) (string, error)
+	DeleteByID(id string) error
+	Delete(key, domain string, labels model.Labels) error
+	Find(domain string, options ...CallOption) ([]*model.KV, error)
+	AddHistory(kv *model.KV) error
+	//RollBack(kv *KV, version string) error
+}
+
+type Options struct {
+	URI      string
+	PoolSize int
+	SSL      bool
+	TLS      *tls.Config
+	Timeout  time.Duration
+}
+
+func NewKVService() (Service, error) {
+	opts := Options{
+		URI:      config.GetDB().URI,
+		PoolSize: config.GetDB().PoolSize,
+		SSL:      config.GetDB().SSL,
+	}
+	if opts.SSL {
+
+	}
+	return NewMongoService(opts)
+}
diff --git a/server/kv/kv_test.go b/server/kv/kv_test.go
new file mode 100644
index 0000000..4bdd043
--- /dev/null
+++ b/server/kv/kv_test.go
@@ -0,0 +1,192 @@
+/*
+ * 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 kv_test
+
+import (
+	. "github.com/apache/servicecomb-kie/pkg/model"
+	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/gomega"
+	"github.com/apache/servicecomb-kie/pkg/model"
+	"github.com/apache/servicecomb-kie/server/kv"
+)
+
+var _ = Describe("Kv mongodb service", func() {
+	var s kv.Service
+	var err error
+	Describe("connecting db", func() {
+		s, err = kv.NewMongoService(kv.Options{
+			URI: "mongodb://kie:123@127.0.0.1:27017",
+		})
+		It("should not return err", func() {
+			Expect(err).Should(BeNil())
+		})
+	})
+
+	Describe("put kv timeout", func() {
+		Context("with labels app and service", func() {
+			kv, err := s.CreateOrUpdate(&model.KV{
+				Key:    "timeout",
+				Value:  "2s",
+				Domain: "default",
+				Labels: map[string]string{
+					"app":     "mall",
+					"service": "cart",
+				},
+			})
+			It("should not return err", func() {
+				Expect(err).Should(BeNil())
+			})
+			It("should has revision", func() {
+				Expect(kv.Revision).ShouldNot(BeZero())
+			})
+			It("should has ID", func() {
+				Expect(kv.ID.Hex()).ShouldNot(BeEmpty())
+			})
+
+		})
+		Context("with labels app, service and version", func() {
+			kv, err := s.CreateOrUpdate(&KV{
+				Key:    "timeout",
+				Value:  "2s",
+				Domain: "default",
+				Labels: map[string]string{
+					"app":     "mall",
+					"service": "cart",
+					"version": "1.0.0",
+				},
+			})
+			oid, err := s.Exist("timeout", "default", map[string]string{
+				"app":     "mall",
+				"service": "cart",
+				"version": "1.0.0",
+			})
+			It("should not return err", func() {
+				Expect(err).Should(BeNil())
+			})
+			It("should has revision", func() {
+				Expect(kv.Revision).ShouldNot(BeZero())
+			})
+			It("should has ID", func() {
+				Expect(kv.ID.Hex()).ShouldNot(BeEmpty())
+			})
+			It("should exist", func() {
+				Expect(oid).ShouldNot(BeEmpty())
+			})
+		})
+		Context("with labels app,and update value", func() {
+			beforeKV, err := s.CreateOrUpdate(&KV{
+				Key:    "timeout",
+				Value:  "1s",
+				Domain: "default",
+				Labels: map[string]string{
+					"app": "mall",
+				},
+			})
+			It("should not return err", func() {
+				Expect(err).Should(BeNil())
+			})
+			kvs1, err := s.Find("default", kv.WithKey("timeout"), kv.WithLabels(map[string]string{
+				"app": "mall",
+			}), kv.WithExactLabels())
+			It("should be 1s", func() {
+				Expect(kvs1[0].Value).Should(Equal(beforeKV.Value))
+			})
+			afterKV, err := s.CreateOrUpdate(&KV{
+				Key:    "timeout",
+				Value:  "3s",
+				Domain: "default",
+				Labels: map[string]string{
+					"app": "mall",
+				},
+			})
+			It("should has same id", func() {
+				Expect(afterKV.ID.Hex()).Should(Equal(beforeKV.ID.Hex()))
+			})
+			oid, err := s.Exist("timeout", "default", map[string]string{
+				"app": "mall",
+			})
+			It("should exists", func() {
+				Expect(oid).Should(Equal(beforeKV.ID.Hex()))
+			})
+			kvs, err := s.Find("default", kv.WithKey("timeout"), kv.WithLabels(map[string]string{
+				"app": "mall",
+			}), kv.WithExactLabels())
+			It("should be 3s", func() {
+				Expect(kvs[0].Value).Should(Equal(afterKV.Value))
+			})
+		})
+	})
+
+	Describe("greedy find by kv and labels", func() {
+		Context("with labels app ", func() {
+			kvs, err := s.Find("default", kv.WithKey("timeout"), kv.WithLabels(map[string]string{
+				"app": "mall",
+			}))
+			It("should not return err", func() {
+				Expect(err).Should(BeNil())
+			})
+			It("should has 3 records", func() {
+				Expect(len(kvs)).Should(Equal(3))
+			})
+
+		})
+	})
+	Describe("exact find by kv and labels", func() {
+		Context("with labels app ", func() {
+			kvs, err := s.Find("default", kv.WithKey("timeout"), kv.WithLabels(map[string]string{
+				"app": "mall",
+			}), kv.WithExactLabels())
+			It("should not return err", func() {
+				Expect(err).Should(BeNil())
+			})
+			It("should has 1 records", func() {
+				Expect(len(kvs)).Should(Equal(1))
+			})
+
+		})
+	})
+	Describe("exact find by labels", func() {
+		Context("with labels app ", func() {
+			kvs, err := s.Find("default", kv.WithLabels(map[string]string{
+				"app": "mall",
+			}), kv.WithExactLabels())
+			It("should not return err", func() {
+				Expect(err).Should(BeNil())
+			})
+			It("should has 1 records", func() {
+				Expect(len(kvs)).Should(Equal(1))
+			})
+
+		})
+	})
+	Describe("greedy find by labels", func() {
+		Context("with labels app ans service ", func() {
+			kvs, err := s.Find("default", kv.WithLabels(map[string]string{
+				"app":     "mall",
+				"service": "cart",
+			}))
+			It("should not return err", func() {
+				Expect(err).Should(BeNil())
+			})
+			It("should has 2 records", func() {
+				Expect(len(kvs)).Should(Equal(2))
+			})
+
+		})
+	})
+})
diff --git a/server/kv/model_suite_test.go b/server/kv/model_suite_test.go
new file mode 100644
index 0000000..965802e
--- /dev/null
+++ b/server/kv/model_suite_test.go
@@ -0,0 +1,44 @@
+/*
+ * 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 kv_test
+
+import (
+	"testing"
+
+	"github.com/go-chassis/paas-lager"
+	"github.com/go-mesh/openlogging"
+	. "github.com/onsi/ginkgo"
+	"github.com/onsi/ginkgo/reporters"
+	. "github.com/onsi/gomega"
+)
+
+func TestModel(t *testing.T) {
+	RegisterFailHandler(Fail)
+	junitReporter := reporters.NewJUnitReporter("junit.xml")
+	RunSpecsWithDefaultAndCustomReporters(t, "Model Suite", []Reporter{junitReporter})
+}
+
+var _ = BeforeSuite(func() {
+	log.Init(log.Config{
+		Writers:     []string{"stdout"},
+		LoggerLevel: "DEBUG",
+	})
+
+	logger := log.NewLogger("ut")
+	openlogging.SetLogger(logger)
+})
diff --git a/server/kv/mongodb.go b/server/kv/mongodb.go
new file mode 100644
index 0000000..37664ae
--- /dev/null
+++ b/server/kv/mongodb.go
@@ -0,0 +1,304 @@
+/*
+ * 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 kv
+
+import (
+	"context"
+	"fmt"
+	"github.com/apache/servicecomb-kie/pkg/model"
+	"github.com/go-mesh/openlogging"
+	"go.mongodb.org/mongo-driver/bson"
+	"go.mongodb.org/mongo-driver/bson/primitive"
+	"go.mongodb.org/mongo-driver/mongo"
+	"go.mongodb.org/mongo-driver/mongo/options"
+	"time"
+)
+
+var client *mongo.Client
+
+const (
+	DB                 = "kie"
+	CollectionKV       = "kv"
+	CollectionRevision = "revision"
+	DefaultTimeout     = 5 * time.Second
+	DefaultValueType   = "text"
+)
+
+type MongodbService struct {
+	c       *mongo.Client
+	timeout time.Duration
+}
+
+func (s *MongodbService) CreateOrUpdate(kv *model.KV) (*model.KV, error) {
+	if kv.Domain == "" {
+		return nil, ErrMissingDomain
+	}
+	ctx, _ := context.WithTimeout(context.Background(), DefaultTimeout)
+	collection := s.c.Database(DB).Collection(CollectionKV)
+	oid, err := s.Exist(kv.Key, kv.Domain, kv.Labels)
+	if err != nil {
+		if err != ErrNotExists {
+			return nil, err
+		}
+	}
+	if oid != "" {
+		hex, err := primitive.ObjectIDFromHex(oid)
+		if err != nil {
+			openlogging.Error(fmt.Sprintf("convert %s ,err:%s", oid, err))
+			return nil, err
+		}
+		kv.ID = hex
+		if err := s.update(ctx, collection, kv); err != nil {
+			return nil, err
+		}
+		return kv, nil
+	}
+	if kv.ValueType == "" {
+		kv.ValueType = DefaultValueType
+	}
+	//set 1 to revision for insertion
+	kv.Revision = 1
+	res, err := collection.InsertOne(ctx, kv)
+	if err != nil {
+		return nil, err
+	}
+	objectID, _ := res.InsertedID.(primitive.ObjectID)
+	kv.ID = objectID
+	if err := s.AddHistory(kv); err != nil {
+		openlogging.Warn(
+			fmt.Sprintf("can not update version for [%s] [%s] in [%s]",
+				kv.Key, kv.Labels, kv.Domain))
+	}
+	openlogging.Debug(fmt.Sprintf("create %s with labels %s value [%s]", kv.Key, kv.Labels, kv.Value))
+	return kv, nil
+}
+
+//update get latest revision from history
+//and increase revision
+//and update and them add new history
+func (s *MongodbService) update(ctx context.Context, collection *mongo.Collection, kv *model.KV) error {
+	h, err := s.getLatest(kv.ID)
+	if err != nil {
+		openlogging.Error(fmt.Sprintf("get latest [%s][%s] in [%s],err: %s",
+			kv.Key, kv.Labels, kv.Domain, err.Error()))
+		return err
+	}
+	if h != nil {
+		kv.Revision = h.Revision + 1
+	}
+	ur, err := collection.UpdateOne(ctx, bson.M{"_id": kv.ID}, bson.D{
+		{"$set", bson.D{
+			{"value", kv.Value},
+			{"revision", kv.Revision},
+			{"checker", kv.Checker},
+		}},
+	})
+	if err != nil {
+		return err
+	}
+	openlogging.Debug(
+		fmt.Sprintf("update %s with labels %s value [%s] %d ",
+			kv.Key, kv.Labels, kv.Value, ur.ModifiedCount))
+	if err := s.AddHistory(kv); err != nil {
+		openlogging.Warn(
+			fmt.Sprintf("can not update version for [%s] [%s] in [%s]",
+				kv.Key, kv.Labels, kv.Domain))
+	}
+	openlogging.Debug(
+		fmt.Sprintf("add history %s with labels %s value [%s] %d ",
+			kv.Key, kv.Labels, kv.Value, ur.ModifiedCount))
+	return nil
+
+}
+func (s *MongodbService) Exist(key, domain string, labels model.Labels) (string, error) {
+	kvs, err := s.Find(domain, WithExactLabels(), WithLabels(labels), WithKey(key))
+	if err != nil {
+		return "", err
+	}
+	if len(kvs) != 1 {
+		return "", ErrTooMany
+	}
+
+	return kvs[0].ID.Hex(), nil
+
+}
+
+//Find get kvs by key, labels
+//because labels has a a lot of combination,
+//you can use WithExactLabels to return only one kv which's labels exactly match the criteria
+func (s *MongodbService) Find(domain string, options ...CallOption) ([]*model.KV, error) {
+	opts := CallOptions{}
+	for _, o := range options {
+		o(&opts)
+	}
+	if domain == "" {
+		return nil, ErrMissingDomain
+	}
+	collection := s.c.Database(DB).Collection(CollectionKV)
+	ctx, _ := context.WithTimeout(context.Background(), DefaultTimeout)
+	filter := bson.M{"domain": domain}
+	if opts.Key != "" {
+		filter["key"] = opts.Key
+	}
+	for k, v := range opts.Labels {
+		filter["labels."+k] = v
+	}
+
+	cur, err := collection.Find(ctx, filter)
+	if err != nil {
+		if err.Error() == context.DeadlineExceeded.Error() {
+			return nil, ErrAction("find", opts.Key, opts.Labels, domain, fmt.Errorf("can not reach mongodb in %s", s.timeout))
+		}
+		return nil, err
+	}
+	defer cur.Close(ctx)
+	if cur.Err() != nil {
+		return nil, err
+	}
+	if opts.ExactLabels {
+		openlogging.Debug(fmt.Sprintf("find one [%s] with lables [%s] in [%s]", opts.Key, opts.Labels, domain))
+		curKV := &model.KV{} //reuse this pointer to reduce GC, only clear label
+		//check label length to get the exact match
+		for cur.Next(ctx) { //although complexity is O(n), but there won't be so much labels for one key
+			curKV.Labels = nil
+			err := cur.Decode(curKV)
+			if err != nil {
+				openlogging.Error("decode error: " + err.Error())
+				return nil, err
+			}
+			if len(curKV.Labels) == len(opts.Labels) {
+				openlogging.Debug("hit")
+				return []*model.KV{curKV}, nil
+			}
+
+		}
+		return nil, ErrNotExists
+	} else {
+		kvs := make([]*model.KV, 0)
+		for cur.Next(ctx) {
+			curKV := &model.KV{}
+			if err := cur.Decode(curKV); err != nil {
+				openlogging.Error("decode to KVs error: " + err.Error())
+				return nil, err
+			}
+			kvs = append(kvs, curKV)
+
+		}
+		if len(kvs) == 0 {
+			return nil, ErrNotExists
+		}
+		return kvs, nil
+	}
+
+}
+func (s *MongodbService) DeleteByID(id string) error {
+	collection := s.c.Database(DB).Collection(CollectionKV)
+	hex, err := primitive.ObjectIDFromHex(id)
+	if err != nil {
+		openlogging.Error(fmt.Sprintf("convert %s ,err:%s", id, err))
+		return err
+	}
+	ctx, _ := context.WithTimeout(context.Background(), DefaultTimeout)
+	dr, err := collection.DeleteOne(ctx, bson.M{"_id": hex})
+	if err != nil {
+		openlogging.Error(fmt.Sprintf("delete [%s] failed: %s", hex, err))
+	}
+	if dr.DeletedCount != 1 {
+		openlogging.Warn(fmt.Sprintf("delete [%s], but it is not exist", hex))
+	}
+	return nil
+}
+
+func (s *MongodbService) Delete(key, domain string, labels model.Labels) error {
+	return nil
+}
+func (s *MongodbService) AddHistory(kv *model.KV) error {
+	collection := s.c.Database(DB).Collection(CollectionRevision)
+	ctx, _ := context.WithTimeout(context.Background(), DefaultTimeout)
+	h := &model.KVHistory{
+		KID:      kv.ID.Hex(),
+		Value:    kv.Value,
+		Revision: kv.Revision,
+		Checker:  kv.Checker,
+	}
+	_, err := collection.InsertOne(ctx, h)
+	if err != nil {
+		openlogging.Error(err.Error())
+		return err
+	}
+	return nil
+}
+func (s *MongodbService) getLatest(id primitive.ObjectID) (*model.KVHistory, error) {
+	collection := s.c.Database(DB).Collection(CollectionRevision)
+	ctx, _ := context.WithTimeout(context.Background(), DefaultTimeout)
+
+	filter := bson.M{"kvID": id.Hex()}
+
+	cur, err := collection.Find(ctx, filter,
+		options.Find().SetSort(map[string]interface{}{
+			"revision": -1,
+		}), options.Find().SetLimit(1))
+	if err != nil {
+		return nil, err
+	}
+	h := &model.KVHistory{}
+	var exist bool
+	for cur.Next(ctx) {
+		if err := cur.Decode(h); err != nil {
+			openlogging.Error("decode to KVs error: " + err.Error())
+			return nil, err
+		}
+		exist = true
+		break
+	}
+	if !exist {
+		return nil, nil
+	}
+	return h, nil
+}
+func NewMongoService(opts Options) (Service, error) {
+	if opts.Timeout == 0 {
+		opts.Timeout = DefaultTimeout
+	}
+	c, err := getClient(opts)
+	if err != nil {
+		return nil, err
+	}
+	m := &MongodbService{
+		c:       c,
+		timeout: opts.Timeout,
+	}
+	return m, nil
+}
+func getClient(opts Options) (*mongo.Client, error) {
+	if client == nil {
+		var err error
+		client, err = mongo.NewClient(options.Client().ApplyURI(opts.URI))
+		if err != nil {
+			return nil, err
+		}
+		openlogging.Info("connecting to " + opts.URI)
+		ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
+		err = client.Connect(ctx)
+		if err != nil {
+			return nil, err
+		}
+		openlogging.Info("connected to " + opts.URI)
+	}
+	return client, nil
+}
diff --git a/server/kv/options.go b/server/kv/options.go
new file mode 100644
index 0000000..aabe1ec
--- /dev/null
+++ b/server/kv/options.go
@@ -0,0 +1,49 @@
+/*
+ * 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 kv
+
+import "github.com/apache/servicecomb-kie/pkg/model"
+
+type CallOptions struct {
+	ExactLabels bool
+	Key         string
+	Labels      model.Labels
+}
+
+type CallOption func(*CallOptions)
+
+//WithExactLabels tell model service to return only one kv matches the labels
+func WithExactLabels() CallOption {
+	return func(o *CallOptions) {
+		o.ExactLabels = true
+	}
+}
+
+//WithKey find by key
+func WithKey(key string) CallOption {
+	return func(o *CallOptions) {
+		o.Key = key
+	}
+}
+
+//WithLabels find kv by labels
+func WithLabels(labels model.Labels) CallOption {
+	return func(o *CallOptions) {
+		o.Labels = labels
+	}
+}


[servicecomb-kie] 14/29: redesign database to make service faster and more ease of use

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

asifdxtreme pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git

commit f6f5b0af01bf460bebba782f2b6739fb66e12782
Author: tian <xi...@gmail.com>
AuthorDate: Fri May 31 11:57:33 2019 +0800

    redesign database to make service faster and more ease of use
---
 client/client.go                                   |   6 +-
 client/client_suite_test.go                        |   2 +
 client/client_test.go                              |   2 +-
 client/options.go                                  |   6 +-
 go.mod                                             |   4 +-
 pkg/model/kv.go                                    |  22 +-
 pkg/model/kv_test.go                               |   4 +-
 pkg/model/mongodb_doc.go                           |  47 ++++
 proxy.sh                                           |   3 +
 server/dao/errors.go                               |   7 +-
 server/dao/{mongodb.go => kie_api.go}              | 254 ++++++++++-----------
 server/dao/kv.go                                   |  73 ++++--
 server/dao/kv_test.go                              |  59 ++---
 server/dao/label.go                                |  69 ++++++
 server/dao/label_history.go                        | 111 +++++++++
 server/dao/mongodb_operator.go                     |  95 ++++++++
 server/dao/options.go                              |  22 +-
 server/resource/v1/common.go                       |   4 +-
 .../resource/v1/history_resource.go                |  20 +-
 server/resource/v1/kv_resource.go                  |  23 +-
 20 files changed, 589 insertions(+), 244 deletions(-)

diff --git a/client/client.go b/client/client.go
index cb78d7c..3bcf161 100644
--- a/client/client.go
+++ b/client/client.go
@@ -74,7 +74,7 @@ func New(config Config) (*Client, error) {
 }
 
 //GetValue get value of a key
-func (c *Client) Get(ctx context.Context, key string, opts ...GetOption) ([]*model.KV, error) {
+func (c *Client) Get(ctx context.Context, key string, opts ...GetOption) ([]*model.KVDoc, error) {
 	options := GetOptions{}
 	for _, o := range opts {
 		o(&options)
@@ -84,7 +84,7 @@ func (c *Client) Get(ctx context.Context, key string, opts ...GetOption) ([]*mod
 	if options.MatchMode != "" {
 		h.Set(common.HeaderMatch, options.MatchMode)
 	}
-	resp, err := c.c.HTTPDo("GET", url, h, nil)
+	resp, err := c.c.HTTPDoWithContext(ctx, "GET", url, h, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -96,7 +96,7 @@ func (c *Client) Get(ctx context.Context, key string, opts ...GetOption) ([]*mod
 		return nil, fmt.Errorf("get %s failed,http status [%s], body [%s]", key, resp.Status, b)
 	}
 
-	kvs := make([]*model.KV, 0)
+	kvs := make([]*model.KVDoc, 0)
 	err = json.Unmarshal(b, kvs)
 	if err != nil {
 		openlogging.Error("unmarshal kv failed:" + err.Error())
diff --git a/client/client_suite_test.go b/client/client_suite_test.go
index 27a4f23..f699279 100644
--- a/client/client_suite_test.go
+++ b/client/client_suite_test.go
@@ -25,6 +25,7 @@ import (
 	. "github.com/onsi/ginkgo"
 	"github.com/onsi/ginkgo/reporters"
 	. "github.com/onsi/gomega"
+	"os"
 )
 
 func TestClient(t *testing.T) {
@@ -41,4 +42,5 @@ var _ = BeforeSuite(func() {
 
 	logger := log.NewLogger("ut")
 	openlogging.SetLogger(logger)
+	os.Setenv("HTTP_DEBUG","1")
 })
diff --git a/client/client_test.go b/client/client_test.go
index 3e02b02..937b6c1 100644
--- a/client/client_test.go
+++ b/client/client_test.go
@@ -53,7 +53,7 @@ var _ = Describe("Client", func() {
 
 		})
 		Context("by key and labels", func() {
-			_, err := c1.Get(context.TODO(), "app.properties", WithLables(map[string]string{
+			_, err := c1.Get(context.TODO(), "app.properties", WithLabels(map[string]string{
 				"app": "mall",
 			}))
 			It("should be 404 error", func() {
diff --git a/client/options.go b/client/options.go
index 351b476..374dcfc 100644
--- a/client/options.go
+++ b/client/options.go
@@ -25,11 +25,15 @@ type GetOptions struct {
 	MatchMode string
 }
 
-func WithLables(l map[string]string) GetOption {
+//WithLabels query kv by labels
+func WithLabels(l map[string]string) GetOption {
 	return func(options *GetOptions) {
 		options.Labels = l
 	}
 }
+
+//WithMatchMode has 2 modes
+//exact and greedy
 func WithMatchMode(m string) GetOption {
 	return func(options *GetOptions) {
 		options.MatchMode = m
diff --git a/go.mod b/go.mod
index dd87b23..d5efedc 100644
--- a/go.mod
+++ b/go.mod
@@ -2,9 +2,9 @@ module github.com/apache/servicecomb-kie
 
 require (
 	github.com/emicklei/go-restful v2.8.0+incompatible
-	github.com/go-chassis/foundation v0.0.0-20190203091418-304855ea28bf
+	github.com/go-chassis/foundation v0.0.0-20190516083152-b8b2476b6db7
 	github.com/go-chassis/go-archaius v0.16.0
-	github.com/go-chassis/go-chassis v1.4.0
+	github.com/go-chassis/go-chassis v1.4.1
 	github.com/go-chassis/paas-lager v1.0.2-0.20190328010332-cf506050ddb2
 	github.com/go-mesh/openlogging v1.0.1-0.20181205082104-3d418c478b2d
 	github.com/onsi/ginkgo v1.8.0
diff --git a/pkg/model/kv.go b/pkg/model/kv.go
index 042cd20..be9830e 100644
--- a/pkg/model/kv.go
+++ b/pkg/model/kv.go
@@ -17,25 +17,9 @@
 
 package model
 
-import (
-	"go.mongodb.org/mongo-driver/bson/primitive"
-)
 
-type Labels map[string]string
 
-type KV struct {
-	ID        primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"`
-	Key       string             `json:"key"`
-	Value     string             `json:"value"`
-	ValueType string             `json:"valueType"`        //ini,json,text,yaml,properties
-	Domain    string             `json:"domain"`           //tenant info
-	Labels    map[string]string  `json:"labels,omitempty"` //key has labels
-	Checker   string             `json:"check,omitempty"`  //python script
-	Revision  int                `json:"revision"`
-}
-type KVHistory struct {
-	KID      string `json:"id,omitempty" bson:"kvID"`
-	Value    string `json:"value"`
-	Checker  string `json:"check,omitempty"` //python script
-	Revision int    `json:"revision"`
+
+
+type KVResponse struct {
 }
diff --git a/pkg/model/kv_test.go b/pkg/model/kv_test.go
index cbb05c0..feb1ce3 100644
--- a/pkg/model/kv_test.go
+++ b/pkg/model/kv_test.go
@@ -25,7 +25,7 @@ import (
 )
 
 func TestKV_UnmarshalJSON(t *testing.T) {
-	kv := &model.KV{
+	kv := &model.KVDoc{
 		Value: "test",
 		Labels: map[string]string{
 			"test": "env",
@@ -34,7 +34,7 @@ func TestKV_UnmarshalJSON(t *testing.T) {
 	b, _ := json.Marshal(kv)
 	t.Log(string(b))
 
-	var kv2 model.KV
+	var kv2 model.KVDoc
 	err := json.Unmarshal([]byte(` 
         {"value": "1","labels":{"test":"env"}}
     `), &kv2)
diff --git a/pkg/model/mongodb_doc.go b/pkg/model/mongodb_doc.go
new file mode 100644
index 0000000..a298ca2
--- /dev/null
+++ b/pkg/model/mongodb_doc.go
@@ -0,0 +1,47 @@
+/*
+ * 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 model
+
+import "go.mongodb.org/mongo-driver/bson/primitive"
+
+type LabelDoc struct {
+	ID       primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"`
+	Labels   map[string]string  `json:"labels,omitempty"`
+	Revision int                `json:"revision"`
+	Domain   string             `json:"domain,omitempty"` //tenant info
+}
+type KVDoc struct {
+	ID        primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"`
+	LabelID   string             `json:"label_id,omitempty" bson:"label_id,omitempty"`
+	Key       string             `json:"key"`
+	Value     string             `json:"value,omitempty"`
+	ValueType string             `json:"value_type,omitempty" bson:"value_type,omitempty"` //ini,json,text,yaml,properties
+	Checker   string             `json:"check,omitempty"`                                  //python script
+
+	Labels   map[string]string `json:"labels,omitempty"` //redundant
+	Domain   string            `json:"domain,omitempty"` //redundant
+	Revision int               `json:"revision,omitempty" bson:"-"`
+}
+type LabelRevisionDoc struct {
+	ID       primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"`
+	LabelID  string             `json:"label_id,omitempty"  bson:"label_id,omitempty"`
+	Labels   map[string]string  `json:"labels,omitempty"` //redundant
+	Domain   string             `json:"domain,omitempty"` //redundant
+	KVs      []*KVDoc           `json:"data,omitempty"`   // save states of this revision
+	Revision int                `json:"revision"`
+}
diff --git a/proxy.sh b/proxy.sh
new file mode 100755
index 0000000..da4430b
--- /dev/null
+++ b/proxy.sh
@@ -0,0 +1,3 @@
+#!/usr/bin/env bash
+
+export GOPROXY=https://goproxy.io
diff --git a/server/dao/errors.go b/server/dao/errors.go
index 31074f8..349ca6d 100644
--- a/server/dao/errors.go
+++ b/server/dao/errors.go
@@ -21,14 +21,13 @@ import (
 	"errors"
 	"fmt"
 
-	"github.com/apache/servicecomb-kie/pkg/model"
 	"github.com/go-mesh/openlogging"
 )
 
 //ErrAction will wrap raw error to biz error and return
-//it record audit log for mongodb operation failure like find, insert, update, deletion
-func ErrAction(action, key string, labels model.Labels, domain string, err error) error {
-	msg := fmt.Sprintf("can not [%s] [%s] in [%s] with [%s],err: %s", action, key, domain, labels, err.Error())
+//it record audit log for mongodb operation failure like find, insert, updateKey, deletion
+func ErrAction(action, filter interface{}, err error) error {
+	msg := fmt.Sprintf("can not [%s] [%v],err: %s", action, filter, err.Error())
 	openlogging.Error(msg)
 	return errors.New(msg)
 
diff --git a/server/dao/mongodb.go b/server/dao/kie_api.go
similarity index 55%
rename from server/dao/mongodb.go
rename to server/dao/kie_api.go
index 9fc6ad0..c5ae9bd 100644
--- a/server/dao/mongodb.go
+++ b/server/dao/kie_api.go
@@ -32,11 +32,12 @@ import (
 var client *mongo.Client
 
 const (
-	DB                 = "kie"
-	CollectionKV       = "kv"
-	CollectionRevision = "revision"
-	DefaultTimeout     = 5 * time.Second
-	DefaultValueType   = "text"
+	DB                      = "kie"
+	CollectionLabel         = "label"
+	CollectionKV            = "kv"
+	CollectionLabelRevision = "label_revision"
+	DefaultTimeout          = 5 * time.Second
+	DefaultValueType        = "text"
 )
 
 type MongodbService struct {
@@ -44,104 +45,146 @@ type MongodbService struct {
 	timeout time.Duration
 }
 
-func (s *MongodbService) CreateOrUpdate(kv *model.KV) (*model.KV, error) {
-	if kv.Domain == "" {
+func (s *MongodbService) CreateOrUpdate(ctx context.Context, domain string, kv *model.KVDoc) (*model.KVDoc, error) {
+	if domain == "" {
 		return nil, ErrMissingDomain
 	}
-	ctx, _ := context.WithTimeout(context.Background(), DefaultTimeout)
-	collection := s.c.Database(DB).Collection(CollectionKV)
-	oid, err := s.Exist(kv.Key, kv.Domain, kv.Labels)
+	ctx, _ = context.WithTimeout(ctx, DefaultTimeout)
+	//check labels exits or not
+	labelID, err := s.LabelsExist(ctx, domain, kv.Labels)
+	var l *model.LabelDoc
 	if err != nil {
-		if err != ErrNotExists {
-			return nil, err
-		}
-	}
-	if oid != "" {
-		hex, err := primitive.ObjectIDFromHex(oid)
-		if err != nil {
-			openlogging.Error(fmt.Sprintf("convert %s ,err:%s", oid, err))
-			return nil, err
-		}
-		kv.ID = hex
-		if err := s.update(ctx, collection, kv); err != nil {
+		if err == ErrLabelNotExists {
+			l, err = s.createLabel(ctx, domain, kv.Labels)
+			if err != nil {
+				return nil, err
+			}
+			labelID = l.ID
+		} else {
 			return nil, err
 		}
-		return kv, nil
+
 	}
+	kv.LabelID = labelID.Hex()
+	kv.Domain = domain
 	if kv.ValueType == "" {
 		kv.ValueType = DefaultValueType
 	}
-	//set 1 to revision for insertion
-	kv.Revision = 1
-	res, err := collection.InsertOne(ctx, kv)
+	keyID, err := s.KVExist(ctx, domain, kv.Key, WithLabelID(kv.LabelID))
 	if err != nil {
+		if err == ErrKeyNotExists {
+			kv, err := s.createKey(ctx, kv)
+			if err != nil {
+				return nil, err
+			}
+			return kv, nil
+		}
 		return nil, err
 	}
-	objectID, _ := res.InsertedID.(primitive.ObjectID)
-	kv.ID = objectID
-	if err := s.AddHistory(kv); err != nil {
-		openlogging.Warn(
-			fmt.Sprintf("can not update version for [%s] [%s] in [%s]",
-				kv.Key, kv.Labels, kv.Domain))
+	kv.ID = keyID
+	revision, err := s.updateKey(ctx, kv)
+	if err != nil {
+		return nil, err
 	}
-	openlogging.Debug(fmt.Sprintf("create %s with labels %s value [%s]", kv.Key, kv.Labels, kv.Value))
+	kv.Revision = revision
 	return kv, nil
+
 }
 
-//update get latest revision from history
-//and increase revision
-//and update and them add new history
-func (s *MongodbService) update(ctx context.Context, collection *mongo.Collection, kv *model.KV) error {
-	h, err := s.getLatest(kv.ID)
-	if err != nil {
-		openlogging.Error(fmt.Sprintf("get latest [%s][%s] in [%s],err: %s",
-			kv.Key, kv.Labels, kv.Domain, err.Error()))
-		return err
+//FindLabels find label doc by labels
+//if map is empty. will return default labels doc which has no labels
+func (s *MongodbService) FindLabels(ctx context.Context, domain string, labels map[string]string) (*model.LabelDoc, error) {
+	collection := s.c.Database(DB).Collection(CollectionLabel)
+	ctx, _ = context.WithTimeout(context.Background(), DefaultTimeout)
+	filter := bson.M{"domain": domain}
+	for k, v := range labels {
+		filter["labels."+k] = v
 	}
-	if h != nil {
-		kv.Revision = h.Revision + 1
+	if len(labels) == 0 {
+		filter["labels"] = "default" //allow key without labels
 	}
-	ur, err := collection.UpdateOne(ctx, bson.M{"_id": kv.ID}, bson.D{
-		{"$set", bson.D{
-			{"value", kv.Value},
-			{"revision", kv.Revision},
-			{"checker", kv.Checker},
-		}},
-	})
+	cur, err := collection.Find(ctx, filter)
 	if err != nil {
-		return err
+		if err.Error() == context.DeadlineExceeded.Error() {
+			return nil, ErrAction("find label", filter, fmt.Errorf("can not reach mongodb in %s", s.timeout))
+		}
+		return nil, err
 	}
-	openlogging.Debug(
-		fmt.Sprintf("update %s with labels %s value [%s] %d ",
-			kv.Key, kv.Labels, kv.Value, ur.ModifiedCount))
-	if err := s.AddHistory(kv); err != nil {
-		openlogging.Warn(
-			fmt.Sprintf("can not update version for [%s] [%s] in [%s]",
-				kv.Key, kv.Labels, kv.Domain))
-	}
-	openlogging.Debug(
-		fmt.Sprintf("add history %s with labels %s value [%s] %d ",
-			kv.Key, kv.Labels, kv.Value, ur.ModifiedCount))
-	return nil
+	defer cur.Close(ctx)
+	if cur.Err() != nil {
+		return nil, err
+	}
+	openlogging.Debug(fmt.Sprintf("find lables [%s] in [%s]", labels, domain))
+	curLabel := &model.LabelDoc{} //reuse this pointer to reduce GC, only clear label
+	//check label length to get the exact match
+	for cur.Next(ctx) { //although complexity is O(n), but there won't be so much labels
+		curLabel.Labels = nil
+		err := cur.Decode(curLabel)
+		if err != nil {
+			openlogging.Error("decode error: " + err.Error())
+			return nil, err
+		}
+		if len(curLabel.Labels) == len(labels) {
+			openlogging.Debug("hit exact labels")
+			curLabel.Labels = nil //exact match don't need to return labels
+			return curLabel, nil
+		}
 
+	}
+	return nil, ErrLabelNotExists
 }
-func (s *MongodbService) Exist(key, domain string, labels model.Labels) (string, error) {
-	kvs, err := s.Find(domain, WithExactLabels(), WithLabels(labels), WithKey(key))
+
+func (s *MongodbService) findKeys(ctx context.Context, filter bson.M, withoutLabel bool) ([]*model.KVDoc, error) {
+	collection := s.c.Database(DB).Collection(CollectionKV)
+	cur, err := collection.Find(ctx, filter)
 	if err != nil {
-		return "", err
+		if err.Error() == context.DeadlineExceeded.Error() {
+			return nil, ErrAction("find", filter, fmt.Errorf("can not reach mongodb in %s", s.timeout))
+		}
+		return nil, err
+	}
+	defer cur.Close(ctx)
+	if cur.Err() != nil {
+		return nil, err
+	}
+	kvs := make([]*model.KVDoc, 0)
+	curKV := &model.KVDoc{} //reduce GC,but need to clear labels
+	for cur.Next(ctx) {
+		curKV.Labels = nil
+		if err := cur.Decode(curKV); err != nil {
+			openlogging.Error("decode to KVs error: " + err.Error())
+			return nil, err
+		}
+		if withoutLabel {
+			curKV.Labels = nil
+		}
+		kvs = append(kvs, curKV)
+
 	}
-	if len(kvs) != 1 {
-		return "", ErrTooMany
+	if len(kvs) == 0 {
+		return nil, ErrKeyNotExists
 	}
+	return kvs, nil
+}
 
-	return kvs[0].ID.Hex(), nil
+//FindKVByLabelID get kvs by key and label id
+//key can be empty, then it will return all key values
+//if key is given, will return 0-1 key value
+func (s *MongodbService) FindKVByLabelID(ctx context.Context, domain, labelID, key string) ([]*model.KVDoc, error) {
+	ctx, _ = context.WithTimeout(context.Background(), DefaultTimeout)
+	filter := bson.M{"label_id": labelID, "domain": domain}
+	if key != "" {
+		return s.findOneKey(ctx, filter, key)
+	} else {
+		return s.findKeys(ctx, filter, true)
+	}
 
 }
 
-//Find get kvs by key, labels
+//FindKV get kvs by key, labels
 //because labels has a a lot of combination,
 //you can use WithExactLabels to return only one kv which's labels exactly match the criteria
-func (s *MongodbService) Find(domain string, options ...FindOption) ([]*model.KV, error) {
+func (s *MongodbService) FindKV(ctx context.Context, domain string, options ...FindOption) ([]*model.KVDoc, error) {
 	opts := FindOptions{}
 	for _, o := range options {
 		o(&opts)
@@ -150,7 +193,7 @@ func (s *MongodbService) Find(domain string, options ...FindOption) ([]*model.KV
 		return nil, ErrMissingDomain
 	}
 	collection := s.c.Database(DB).Collection(CollectionKV)
-	ctx, _ := context.WithTimeout(context.Background(), DefaultTimeout)
+	ctx, _ = context.WithTimeout(ctx, DefaultTimeout)
 	filter := bson.M{"domain": domain}
 	if opts.Key != "" {
 		filter["key"] = opts.Key
@@ -162,7 +205,7 @@ func (s *MongodbService) Find(domain string, options ...FindOption) ([]*model.KV
 	cur, err := collection.Find(ctx, filter)
 	if err != nil {
 		if err.Error() == context.DeadlineExceeded.Error() {
-			return nil, ErrAction("find", opts.Key, opts.Labels, domain, fmt.Errorf("can not reach mongodb in %s", s.timeout))
+			return nil, ErrAction("find", filter, fmt.Errorf("can not reach mongodb in %s", s.timeout))
 		}
 		return nil, err
 	}
@@ -172,7 +215,7 @@ func (s *MongodbService) Find(domain string, options ...FindOption) ([]*model.KV
 	}
 	if opts.ExactLabels {
 		openlogging.Debug(fmt.Sprintf("find one [%s] with lables [%s] in [%s]", opts.Key, opts.Labels, domain))
-		curKV := &model.KV{} //reuse this pointer to reduce GC, only clear label
+		curKV := &model.KVDoc{} //reuse this pointer to reduce GC, only clear label
 		//check label length to get the exact match
 		for cur.Next(ctx) { //although complexity is O(n), but there won't be so much labels for one key
 			curKV.Labels = nil
@@ -182,16 +225,17 @@ func (s *MongodbService) Find(domain string, options ...FindOption) ([]*model.KV
 				return nil, err
 			}
 			if len(curKV.Labels) == len(opts.Labels) {
-				openlogging.Debug("hit")
-				return []*model.KV{curKV}, nil
+				openlogging.Debug("hit exact labels")
+				curKV.Labels = nil //exact match don't need to return labels
+				return []*model.KVDoc{curKV}, nil
 			}
 
 		}
-		return nil, ErrNotExists
+		return nil, ErrKeyNotExists
 	} else {
-		kvs := make([]*model.KV, 0)
+		kvs := make([]*model.KVDoc, 0)
 		for cur.Next(ctx) {
-			curKV := &model.KV{}
+			curKV := &model.KVDoc{}
 			if err := cur.Decode(curKV); err != nil {
 				openlogging.Error("decode to KVs error: " + err.Error())
 				return nil, err
@@ -200,7 +244,7 @@ func (s *MongodbService) Find(domain string, options ...FindOption) ([]*model.KV
 
 		}
 		if len(kvs) == 0 {
-			return nil, ErrNotExists
+			return nil, ErrKeyNotExists
 		}
 		return kvs, nil
 	}
@@ -253,7 +297,7 @@ func (s *MongodbService) Delete(ids []string, domain string) error {
 	dr, err := collection.DeleteMany(ctx, filter)
 	//check error and delete number
 	if err != nil {
-		openlogging.Error(fmt.Sprintf("delete [%s] failed : [%s]", filter, err))
+		openlogging.Error(fmt.Sprintf("delete [%v] failed : [%s]", filter, err))
 		return err
 	}
 	if dr.DeletedCount != int64(len(oid)) {
@@ -263,51 +307,7 @@ func (s *MongodbService) Delete(ids []string, domain string) error {
 	}
 	return nil
 }
-func (s *MongodbService) AddHistory(kv *model.KV) error {
-	collection := s.c.Database(DB).Collection(CollectionRevision)
-	ctx, _ := context.WithTimeout(context.Background(), DefaultTimeout)
-	h := &model.KVHistory{
-		KID:      kv.ID.Hex(),
-		Value:    kv.Value,
-		Revision: kv.Revision,
-		Checker:  kv.Checker,
-	}
-	_, err := collection.InsertOne(ctx, h)
-	if err != nil {
-		openlogging.Error(err.Error())
-		return err
-	}
-	return nil
-}
-func (s *MongodbService) getLatest(id primitive.ObjectID) (*model.KVHistory, error) {
-	collection := s.c.Database(DB).Collection(CollectionRevision)
-	ctx, _ := context.WithTimeout(context.Background(), DefaultTimeout)
-
-	filter := bson.M{"kvID": id.Hex()}
-
-	cur, err := collection.Find(ctx, filter,
-		options.Find().SetSort(map[string]interface{}{
-			"revision": -1,
-		}), options.Find().SetLimit(1))
-	if err != nil {
-		return nil, err
-	}
-	h := &model.KVHistory{}
-	var exist bool
-	for cur.Next(ctx) {
-		if err := cur.Decode(h); err != nil {
-			openlogging.Error("decode to KVs error: " + err.Error())
-			return nil, err
-		}
-		exist = true
-		break
-	}
-	if !exist {
-		return nil, nil
-	}
-	return h, nil
-}
-func NewMongoService(opts Options) (KV, error) {
+func NewMongoService(opts Options) (*MongodbService, error) {
 	if opts.Timeout == 0 {
 		opts.Timeout = DefaultTimeout
 	}
diff --git a/server/dao/kv.go b/server/dao/kv.go
index 9cf40fe..1f7eccf 100644
--- a/server/dao/kv.go
+++ b/server/dao/kv.go
@@ -19,27 +19,26 @@
 package dao
 
 import (
+	"context"
 	"crypto/tls"
 	"errors"
 	"github.com/apache/servicecomb-kie/pkg/model"
 	"github.com/apache/servicecomb-kie/server/config"
+	"github.com/go-mesh/openlogging"
+	"go.mongodb.org/mongo-driver/bson"
+	"go.mongodb.org/mongo-driver/bson/primitive"
+	"go.mongodb.org/mongo-driver/mongo"
 	"time"
 )
 
-var ErrMissingDomain = errors.New("domain info missing, illegal access")
-var ErrNotExists = errors.New("key with labels does not exits")
-var ErrTooMany = errors.New("key with labels should be only one")
-var ErrKeyMustNotEmpty = errors.New("must supply key if you want to get exact one result")
-
-type KV interface {
-	CreateOrUpdate(kv *model.KV) (*model.KV, error)
-	//do not use primitive.ObjectID as return to decouple with mongodb, we can afford perf lost
-	Exist(key, domain string, labels model.Labels) (string, error)
-	Delete(ids []string, domain string) error
-	Find(domain string, options ...FindOption) ([]*model.KV, error)
-	AddHistory(kv *model.KV) error
-	//RollBack(kv *KV, version string) error
-}
+var (
+	ErrMissingDomain    = errors.New("domain info missing, illegal access")
+	ErrKeyNotExists     = errors.New("key with labels does not exits")
+	ErrLabelNotExists   = errors.New("labels does not exits")
+	ErrTooMany          = errors.New("key with labels should be only one")
+	ErrKeyMustNotEmpty  = errors.New("must supply key if you want to get exact one result")
+	ErrRevisionNotExist = errors.New("label revision not exist")
+)
 
 type Options struct {
 	URI      string
@@ -49,7 +48,7 @@ type Options struct {
 	Timeout  time.Duration
 }
 
-func NewKVService() (KV, error) {
+func NewKVService() (*MongodbService, error) {
 	opts := Options{
 		URI:      config.GetDB().URI,
 		PoolSize: config.GetDB().PoolSize,
@@ -60,3 +59,47 @@ func NewKVService() (KV, error) {
 	}
 	return NewMongoService(opts)
 }
+func (s *MongodbService) findOneKey(ctx context.Context, filter bson.M, key string) ([]*model.KVDoc, error) {
+	collection := s.c.Database(DB).Collection(CollectionKV)
+	filter["key"] = key
+	sr := collection.FindOne(ctx, filter)
+	if sr.Err() != nil {
+		return nil, sr.Err()
+	}
+	curKV := &model.KVDoc{}
+	err := sr.Decode(curKV)
+	if err != nil {
+		if err == mongo.ErrNoDocuments {
+			return nil, ErrKeyNotExists
+		}
+		openlogging.Error("decode error: " + err.Error())
+		return nil, err
+	}
+	return []*model.KVDoc{curKV}, nil
+}
+
+//KVExist supports you query by label map or labels id
+func (s *MongodbService) KVExist(ctx context.Context, domain, key string, options ...FindOption) (primitive.ObjectID, error) {
+	opts := FindOptions{}
+	for _, o := range options {
+		o(&opts)
+	}
+	if opts.LabelID != "" {
+		kvs, err := s.FindKVByLabelID(ctx, domain, opts.LabelID, key)
+		if err != nil {
+			return primitive.NilObjectID, err
+		}
+		return kvs[0].ID, nil
+	} else {
+		kvs, err := s.FindKV(ctx, domain, WithExactLabels(), WithLabels(opts.Labels), WithKey(key))
+		if err != nil {
+			return primitive.NilObjectID, err
+		}
+		if len(kvs) != 1 {
+			return primitive.NilObjectID, ErrTooMany
+		}
+
+		return kvs[0].ID, nil
+	}
+
+}
diff --git a/server/dao/kv_test.go b/server/dao/kv_test.go
index 81bd106..7e2a5eb 100644
--- a/server/dao/kv_test.go
+++ b/server/dao/kv_test.go
@@ -18,15 +18,15 @@
 package dao_test
 
 import (
+	"context"
 	"github.com/apache/servicecomb-kie/pkg/model"
-	. "github.com/apache/servicecomb-kie/pkg/model"
 	"github.com/apache/servicecomb-kie/server/dao"
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
 )
 
 var _ = Describe("Kv mongodb service", func() {
-	var s dao.KV
+	var s *dao.MongodbService
 	var err error
 	Describe("connecting db", func() {
 		s, err = dao.NewMongoService(dao.Options{
@@ -39,10 +39,9 @@ var _ = Describe("Kv mongodb service", func() {
 
 	Describe("put kv timeout", func() {
 		Context("with labels app and service", func() {
-			kv, err := s.CreateOrUpdate(&model.KV{
-				Key:    "timeout",
-				Value:  "2s",
-				Domain: "default",
+			kv, err := s.CreateOrUpdate(context.TODO(), "default", &model.KVDoc{
+				Key:   "timeout",
+				Value: "2s",
 				Labels: map[string]string{
 					"app":     "mall",
 					"service": "cart",
@@ -51,36 +50,29 @@ var _ = Describe("Kv mongodb service", func() {
 			It("should not return err", func() {
 				Expect(err).Should(BeNil())
 			})
-			It("should has revision", func() {
-				Expect(kv.Revision).ShouldNot(BeZero())
-			})
 			It("should has ID", func() {
 				Expect(kv.ID.Hex()).ShouldNot(BeEmpty())
 			})
 
 		})
 		Context("with labels app, service and version", func() {
-			kv, err := s.CreateOrUpdate(&KV{
-				Key:    "timeout",
-				Value:  "2s",
-				Domain: "default",
+			kv, err := s.CreateOrUpdate(context.TODO(), "default", &model.KVDoc{
+				Key:   "timeout",
+				Value: "2s",
 				Labels: map[string]string{
 					"app":     "mall",
 					"service": "cart",
 					"version": "1.0.0",
 				},
 			})
-			oid, err := s.Exist("timeout", "default", map[string]string{
+			oid, err := s.KVExist(context.TODO(), "default", "timeout", dao.WithLabels(map[string]string{
 				"app":     "mall",
 				"service": "cart",
 				"version": "1.0.0",
-			})
+			}))
 			It("should not return err", func() {
 				Expect(err).Should(BeNil())
 			})
-			It("should has revision", func() {
-				Expect(kv.Revision).ShouldNot(BeZero())
-			})
 			It("should has ID", func() {
 				Expect(kv.ID.Hex()).ShouldNot(BeEmpty())
 			})
@@ -89,7 +81,7 @@ var _ = Describe("Kv mongodb service", func() {
 			})
 		})
 		Context("with labels app,and update value", func() {
-			beforeKV, err := s.CreateOrUpdate(&KV{
+			beforeKV, err := s.CreateOrUpdate(context.Background(), "default", &model.KVDoc{
 				Key:    "timeout",
 				Value:  "1s",
 				Domain: "default",
@@ -100,13 +92,13 @@ var _ = Describe("Kv mongodb service", func() {
 			It("should not return err", func() {
 				Expect(err).Should(BeNil())
 			})
-			kvs1, err := s.Find("default", dao.WithKey("timeout"), dao.WithLabels(map[string]string{
+			kvs1, err := s.FindKV(context.Background(), "default", dao.WithKey("timeout"), dao.WithLabels(map[string]string{
 				"app": "mall",
 			}), dao.WithExactLabels())
 			It("should be 1s", func() {
 				Expect(kvs1[0].Value).Should(Equal(beforeKV.Value))
 			})
-			afterKV, err := s.CreateOrUpdate(&KV{
+			afterKV, err := s.CreateOrUpdate(context.Background(), "default", &model.KVDoc{
 				Key:    "timeout",
 				Value:  "3s",
 				Domain: "default",
@@ -117,13 +109,13 @@ var _ = Describe("Kv mongodb service", func() {
 			It("should has same id", func() {
 				Expect(afterKV.ID.Hex()).Should(Equal(beforeKV.ID.Hex()))
 			})
-			oid, err := s.Exist("timeout", "default", map[string]string{
+			oid, err := s.KVExist(context.Background(), "default", "timeout", dao.WithLabels(map[string]string{
 				"app": "mall",
-			})
+			}))
 			It("should exists", func() {
-				Expect(oid).Should(Equal(beforeKV.ID.Hex()))
+				Expect(oid.Hex()).Should(Equal(beforeKV.ID.Hex()))
 			})
-			kvs, err := s.Find("default", dao.WithKey("timeout"), dao.WithLabels(map[string]string{
+			kvs, err := s.FindKV(context.Background(), "default", dao.WithKey("timeout"), dao.WithLabels(map[string]string{
 				"app": "mall",
 			}), dao.WithExactLabels())
 			It("should be 3s", func() {
@@ -134,7 +126,7 @@ var _ = Describe("Kv mongodb service", func() {
 
 	Describe("greedy find by kv and labels", func() {
 		Context("with labels app ", func() {
-			kvs, err := s.Find("default", dao.WithKey("timeout"), dao.WithLabels(map[string]string{
+			kvs, err := s.FindKV(context.Background(), "default", dao.WithKey("timeout"), dao.WithLabels(map[string]string{
 				"app": "mall",
 			}))
 			It("should not return err", func() {
@@ -148,7 +140,7 @@ var _ = Describe("Kv mongodb service", func() {
 	})
 	Describe("exact find by kv and labels", func() {
 		Context("with labels app ", func() {
-			kvs, err := s.Find("default", dao.WithKey("timeout"), dao.WithLabels(map[string]string{
+			kvs, err := s.FindKV(context.Background(), "default", dao.WithKey("timeout"), dao.WithLabels(map[string]string{
 				"app": "mall",
 			}), dao.WithExactLabels())
 			It("should not return err", func() {
@@ -162,7 +154,7 @@ var _ = Describe("Kv mongodb service", func() {
 	})
 	Describe("exact find by labels", func() {
 		Context("with labels app ", func() {
-			kvs, err := s.Find("default", dao.WithLabels(map[string]string{
+			kvs, err := s.FindKV(context.Background(), "default", dao.WithLabels(map[string]string{
 				"app": "mall",
 			}), dao.WithExactLabels())
 			It("should not return err", func() {
@@ -176,7 +168,7 @@ var _ = Describe("Kv mongodb service", func() {
 	})
 	Describe("greedy find by labels", func() {
 		Context("with labels app ans service ", func() {
-			kvs, err := s.Find("default", dao.WithLabels(map[string]string{
+			kvs, err := s.FindKV(context.Background(), "default", dao.WithLabels(map[string]string{
 				"app":     "mall",
 				"service": "cart",
 			}))
@@ -192,10 +184,9 @@ var _ = Describe("Kv mongodb service", func() {
 
 	Describe("delete key", func() {
 		Context("delete key by id,seperated by ',' ", func() {
-			kv1, err := s.CreateOrUpdate(&model.KV{
-				Key:    "timeout",
-				Value:  "20s",
-				Domain: "default",
+			kv1, err := s.CreateOrUpdate(context.Background(), "default", &model.KVDoc{
+				Key:   "timeout",
+				Value: "20s",
 				Labels: map[string]string{
 					"env": "test",
 				},
@@ -204,7 +195,7 @@ var _ = Describe("Kv mongodb service", func() {
 				Expect(err).Should(BeNil())
 			})
 
-			kv2, err := s.CreateOrUpdate(&model.KV{
+			kv2, err := s.CreateOrUpdate(context.Background(), "default", &model.KVDoc{
 				Key:    "times",
 				Value:  "3",
 				Domain: "default",
diff --git a/server/dao/label.go b/server/dao/label.go
new file mode 100644
index 0000000..3fddd2f
--- /dev/null
+++ b/server/dao/label.go
@@ -0,0 +1,69 @@
+/*
+ * 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 dao
+
+import (
+	"context"
+	"github.com/apache/servicecomb-kie/pkg/model"
+	"github.com/go-mesh/openlogging"
+	"go.mongodb.org/mongo-driver/bson"
+	"go.mongodb.org/mongo-driver/bson/primitive"
+	"go.mongodb.org/mongo-driver/mongo"
+)
+
+func (s *MongodbService) createLabel(ctx context.Context, domain string, labels map[string]string) (*model.LabelDoc, error) {
+	l := &model.LabelDoc{
+		Domain: domain,
+		Labels: labels,
+	}
+	collection := s.c.Database(DB).Collection(CollectionLabel)
+	res, err := collection.InsertOne(ctx, l)
+	if err != nil {
+		return nil, err
+	}
+	objectID, _ := res.InsertedID.(primitive.ObjectID)
+	l.ID = objectID
+	return l, nil
+}
+func (s *MongodbService) findOneLabels(ctx context.Context, filter bson.M) (*model.LabelDoc, error) {
+	collection := s.c.Database(DB).Collection(CollectionLabel)
+	ctx, _ = context.WithTimeout(context.Background(), DefaultTimeout)
+	sr := collection.FindOne(ctx, filter)
+	if sr.Err() != nil {
+		return nil, sr.Err()
+	}
+	l := &model.LabelDoc{}
+	err := sr.Decode(l)
+	if err != nil {
+		if err == mongo.ErrNoDocuments {
+			return nil, ErrLabelNotExists
+		}
+		openlogging.Error("decode error: " + err.Error())
+		return nil, err
+	}
+	return l, nil
+}
+func (s *MongodbService) LabelsExist(ctx context.Context, domain string, labels map[string]string) (primitive.ObjectID, error) {
+	l, err := s.FindLabels(ctx, domain, labels)
+	if err != nil {
+		return primitive.NilObjectID, err
+	}
+
+	return l.ID, nil
+
+}
diff --git a/server/dao/label_history.go b/server/dao/label_history.go
new file mode 100644
index 0000000..fb8164f
--- /dev/null
+++ b/server/dao/label_history.go
@@ -0,0 +1,111 @@
+/*
+ * 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 dao
+
+import (
+	"context"
+
+	"fmt"
+	"github.com/apache/servicecomb-kie/pkg/model"
+	"github.com/go-mesh/openlogging"
+	"go.mongodb.org/mongo-driver/bson"
+	"go.mongodb.org/mongo-driver/bson/primitive"
+	"go.mongodb.org/mongo-driver/mongo/options"
+)
+
+func (s *MongodbService) getLatestLabel(ctx context.Context, labelID string) (*model.LabelRevisionDoc, error) {
+	collection := s.c.Database(DB).Collection(CollectionLabelRevision)
+	ctx, _ = context.WithTimeout(ctx, DefaultTimeout)
+
+	filter := bson.M{"label_id": labelID}
+
+	cur, err := collection.Find(ctx, filter,
+		options.Find().SetSort(map[string]interface{}{
+			"revision": -1,
+		}), options.Find().SetLimit(1))
+	if err != nil {
+		return nil, err
+	}
+	h := &model.LabelRevisionDoc{}
+	var exist bool
+	for cur.Next(ctx) {
+		if err := cur.Decode(h); err != nil {
+			openlogging.Error("decode to KVs error: " + err.Error())
+			return nil, err
+		}
+		exist = true
+		break
+	}
+	if !exist {
+		return nil, ErrRevisionNotExist
+	}
+	return h, nil
+}
+func (s *MongodbService) AddHistory(ctx context.Context, labelID string, labels map[string]string, domain string) (int, error) {
+	r, err := s.getLatestLabel(ctx, labelID)
+	if err != nil {
+		if err == ErrRevisionNotExist {
+			openlogging.Warn(fmt.Sprintf("label revision not exists, create first label revision"))
+			r = &model.LabelRevisionDoc{
+				LabelID:  labelID,
+				Labels:   labels,
+				Domain:   domain,
+				Revision: 0,
+			}
+		} else {
+			openlogging.Error(fmt.Sprintf("get latest [%s] in [%s],err: %s",
+				labelID, domain, err.Error()))
+			return 0, err
+		}
+
+	}
+	r.Revision = r.Revision + 1
+
+	kvs, err := s.findKeys(ctx, bson.M{"label_id": labelID}, true)
+	if err != nil {
+		return 0, err
+	}
+	//save current kv states
+	r.KVs = kvs
+	//clear prev id
+	r.ID = primitive.NilObjectID
+	collection := s.c.Database(DB).Collection(CollectionLabelRevision)
+	_, err = collection.InsertOne(ctx, r)
+	if err != nil {
+		openlogging.Error(err.Error())
+		return 0, err
+	}
+
+	hex, err := primitive.ObjectIDFromHex(labelID)
+	if err != nil {
+		openlogging.Error(fmt.Sprintf("convert %s,err:%s", labelID, err))
+		return 0, err
+	}
+	labelCollection := s.c.Database(DB).Collection(CollectionLabel)
+	_, err = labelCollection.UpdateOne(ctx, bson.M{"_id": hex}, bson.D{
+		{"$set", bson.D{
+			{"revision", r.Revision},
+		}},
+	})
+	if err != nil {
+		return 0, err
+	}
+	openlogging.Debug(fmt.Sprintf("update revision to %d", r.Revision))
+
+	return r.Revision, nil
+}
diff --git a/server/dao/mongodb_operator.go b/server/dao/mongodb_operator.go
new file mode 100644
index 0000000..ce672d1
--- /dev/null
+++ b/server/dao/mongodb_operator.go
@@ -0,0 +1,95 @@
+/*
+ * 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 dao
+
+import (
+	"context"
+
+	"fmt"
+	"github.com/apache/servicecomb-kie/pkg/model"
+	"github.com/go-mesh/openlogging"
+	"go.mongodb.org/mongo-driver/bson"
+	"go.mongodb.org/mongo-driver/bson/primitive"
+)
+
+//createKey get latest revision from history
+//and increase revision of label
+//and insert key
+func (s *MongodbService) createKey(ctx context.Context, kv *model.KVDoc) (*model.KVDoc, error) {
+	r, err := s.getLatestLabel(ctx, kv.LabelID)
+	if err != nil {
+		if err != ErrRevisionNotExist {
+			openlogging.Error(fmt.Sprintf("get latest [%s][%s] in [%s],err: %s",
+				kv.Key, kv.Labels, kv.Domain, err.Error()))
+			return nil, err
+		}
+		//the first time labels is created, at this time, labels has no revision yet
+		//after first key created, labels got revision 1
+		r = &model.LabelRevisionDoc{Revision: 0}
+	}
+	if r != nil {
+		r.Revision = r.Revision + 1
+	}
+	collection := s.c.Database(DB).Collection(CollectionKV)
+	res, err := collection.InsertOne(ctx, kv)
+	if err != nil {
+		return nil, err
+	}
+	objectID, _ := res.InsertedID.(primitive.ObjectID)
+	kv.ID = objectID
+	revision, err := s.AddHistory(ctx, kv.LabelID, kv.Labels, kv.Domain)
+	if err != nil {
+		openlogging.Warn(
+			fmt.Sprintf("can not updateKey version for [%s] [%s] in [%s]",
+				kv.Key, kv.Labels, kv.Domain))
+	}
+	openlogging.Debug(fmt.Sprintf("create %s with labels %s value [%s]", kv.Key, kv.Labels, kv.Value))
+	kv.Revision = revision
+	return kv, nil
+
+}
+
+//updateKey get latest revision from history
+//and increase revision of label
+//and updateKey and them add new revision
+func (s *MongodbService) updateKey(ctx context.Context, kv *model.KVDoc) (int, error) {
+	collection := s.c.Database(DB).Collection(CollectionKV)
+	ur, err := collection.UpdateOne(ctx, bson.M{"key": kv.Key, "label_id": kv.LabelID}, bson.D{
+		{"$set", bson.D{
+			{"value", kv.Value},
+			{"checker", kv.Checker},
+		}},
+	})
+	if err != nil {
+		return 0, err
+	}
+	openlogging.Debug(
+		fmt.Sprintf("updateKey %s with labels %s value [%s] %d ",
+			kv.Key, kv.Labels, kv.Value, ur.ModifiedCount))
+	revision, err := s.AddHistory(ctx, kv.LabelID, kv.Labels, kv.Domain)
+	if err != nil {
+		openlogging.Warn(
+			fmt.Sprintf("can not label revision for [%s] [%s] in [%s],err: %s",
+				kv.Key, kv.Labels, kv.Domain, err))
+	}
+	openlogging.Debug(
+		fmt.Sprintf("add history %s with labels %s value [%s] %d ",
+			kv.Key, kv.Labels, kv.Value, ur.ModifiedCount))
+	return revision, nil
+
+}
diff --git a/server/dao/options.go b/server/dao/options.go
index 2116b67..e1af384 100644
--- a/server/dao/options.go
+++ b/server/dao/options.go
@@ -17,12 +17,12 @@
 
 package dao
 
-import "github.com/apache/servicecomb-kie/pkg/model"
-
 type FindOptions struct {
 	ExactLabels bool
 	Key         string
-	Labels      model.Labels
+	Labels      map[string]string
+	LabelID     string
+	ClearLabel  bool
 }
 
 type FindOption func(*FindOptions)
@@ -42,8 +42,22 @@ func WithKey(key string) FindOption {
 }
 
 //WithLabels find kv by labels
-func WithLabels(labels model.Labels) FindOption {
+func WithLabels(labels map[string]string) FindOption {
 	return func(o *FindOptions) {
 		o.Labels = labels
 	}
 }
+
+//WithLabels find kv by labelID
+func WithLabelID(label string) FindOption {
+	return func(o *FindOptions) {
+		o.LabelID = label
+	}
+}
+
+//WithOutLabelField will clear all labels attributes in kv doc
+func WithOutLabelField() FindOption {
+	return func(o *FindOptions) {
+		o.ClearLabel = true
+	}
+}
diff --git a/server/resource/v1/common.go b/server/resource/v1/common.go
index c9fb5bb..2293b72 100644
--- a/server/resource/v1/common.go
+++ b/server/resource/v1/common.go
@@ -54,11 +54,11 @@ func WriteErrResponse(context *restful.Context, status int, msg string) {
 	context.Write(b)
 }
 
-func ErrLog(action string, kv *model.KV, err error) {
+func ErrLog(action string, kv *model.KVDoc, err error) {
 	openlogging.Error(fmt.Sprintf("[%s] [%v] err:%s", action, kv, err.Error()))
 }
 
-func InfoLog(action string, kv *model.KV) {
+func InfoLog(action string, kv *model.KVDoc) {
 	openlogging.Info(
 		fmt.Sprintf("[%s] [%s:%s] in [%s] success", action, kv.Key, kv.Value, kv.Domain))
 }
diff --git a/client/options.go b/server/resource/v1/history_resource.go
similarity index 70%
copy from client/options.go
copy to server/resource/v1/history_resource.go
index 351b476..3952a19 100644
--- a/client/options.go
+++ b/server/resource/v1/history_resource.go
@@ -15,23 +15,7 @@
  * limitations under the License.
  */
 
-package client
+package v1
 
-
-
-type GetOption func(*GetOptions)
-type GetOptions struct {
-	Labels    map[string]string
-	MatchMode string
-}
-
-func WithLables(l map[string]string) GetOption {
-	return func(options *GetOptions) {
-		options.Labels = l
-	}
-}
-func WithMatchMode(m string) GetOption {
-	return func(options *GetOptions) {
-		options.MatchMode = m
-	}
+type HistoryResource struct {
 }
diff --git a/server/resource/v1/kv_resource.go b/server/resource/v1/kv_resource.go
index 0ecd74c..db2d2b6 100644
--- a/server/resource/v1/kv_resource.go
+++ b/server/resource/v1/kv_resource.go
@@ -37,7 +37,7 @@ type KVResource struct {
 func (r *KVResource) Put(context *restful.Context) {
 	var err error
 	key := context.ReadPathParameter("key")
-	kv := new(model.KV)
+	kv := new(model.KVDoc)
 	decoder := json.NewDecoder(context.ReadRequest().Body)
 	if err = decoder.Decode(kv); err != nil {
 		WriteErrResponse(context, http.StatusInternalServerError, err.Error())
@@ -48,13 +48,12 @@ func (r *KVResource) Put(context *restful.Context) {
 		WriteErrResponse(context, http.StatusInternalServerError, MsgDomainMustNotBeEmpty)
 	}
 	kv.Key = key
-	kv.Domain = domain.(string)
 	s, err := dao.NewKVService()
 	if err != nil {
 		WriteErrResponse(context, http.StatusInternalServerError, err.Error())
 		return
 	}
-	kv, err = s.CreateOrUpdate(kv)
+	kv, err = s.CreateOrUpdate(context.Ctx, domain.(string), kv)
 	if err != nil {
 		ErrLog("put", kv, err)
 		WriteErrResponse(context, http.StatusInternalServerError, err.Error())
@@ -92,18 +91,18 @@ func (r *KVResource) FindWithKey(context *restful.Context) {
 		return
 	}
 	policy := ReadMatchPolicy(context)
-	var kvs []*model.KV
+	var kvs []*model.KVDoc
 	switch policy {
 	case common.MatchGreedy:
-		kvs, err = s.Find(domain.(string), dao.WithKey(key), dao.WithLabels(labels))
+		kvs, err = s.FindKV(context.Ctx, domain.(string), dao.WithKey(key), dao.WithLabels(labels))
 	case common.MatchExact:
-		kvs, err = s.Find(domain.(string), dao.WithKey(key), dao.WithLabels(labels),
+		kvs, err = s.FindKV(context.Ctx, domain.(string), dao.WithKey(key), dao.WithLabels(labels),
 			dao.WithExactLabels())
 	default:
 		WriteErrResponse(context, http.StatusBadRequest, MsgIllegalFindPolicy)
 		return
 	}
-	if err == dao.ErrNotExists {
+	if err == dao.ErrKeyNotExists {
 		WriteErrResponse(context, http.StatusNotFound, err.Error())
 		return
 	}
@@ -139,18 +138,18 @@ func (r *KVResource) FindByLabels(context *restful.Context) {
 		return
 	}
 	policy := ReadMatchPolicy(context)
-	var kvs []*model.KV
+	var kvs []*model.KVDoc
 	switch policy {
 	case common.MatchGreedy:
-		kvs, err = s.Find(domain.(string), dao.WithLabels(labels))
+		kvs, err = s.FindKV(context.Ctx, domain.(string), dao.WithLabels(labels))
 	case common.MatchExact:
-		kvs, err = s.Find(domain.(string), dao.WithLabels(labels),
+		kvs, err = s.FindKV(context.Ctx, domain.(string), dao.WithLabels(labels),
 			dao.WithExactLabels())
 	default:
 		WriteErrResponse(context, http.StatusBadRequest, MsgIllegalFindPolicy)
 		return
 	}
-	if err == dao.ErrNotExists {
+	if err == dao.ErrKeyNotExists {
 		WriteErrResponse(context, http.StatusNotFound, err.Error())
 		return
 	}
@@ -280,7 +279,7 @@ func (r *KVResource) URLPatterns() []restful.Route {
 			Method:           http.MethodDelete,
 			Path:             "/v1/kv/{ids}",
 			ResourceFuncName: "Delete",
-			FuncDesc:         "delete key by id,seperated by ','",
+			FuncDesc:         "delete key by id,separated by ','",
 			Parameters: []*restful.Parameters{
 				{
 					DataType:  "string",


[servicecomb-kie] 20/29: SCB-1312 Create CI for servicecomb-kie

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

asifdxtreme pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git

commit 33c124181d8f7046c5b08cf02fa564815a269b63
Author: Shawn <xi...@gmail.com>
AuthorDate: Tue Jun 11 08:24:12 2019 +0800

    SCB-1312 Create CI for servicecomb-kie
---
 .travis.yml                       | 50 +++++++++++++++++++++++++++++++++++++++
 scripts/travis/deadCodeChecker.sh | 24 +++++++++++++++++++
 scripts/travis/formatChecker.sh   | 24 +++++++++++++++++++
 scripts/travis/goConstChecker.sh  | 24 +++++++++++++++++++
 scripts/travis/goCycloChecker.sh  | 24 +++++++++++++++++++
 scripts/travis/goLintChecker.sh   | 24 +++++++++++++++++++
 scripts/travis/goVetChecker.sh    |  8 +++++++
 scripts/travis/misspellChecker.sh | 24 +++++++++++++++++++
 scripts/travis/start_deps.sh      | 18 ++++++++++++++
 scripts/travis/unit_test.sh       | 32 +++++++++++++++++++++++++
 10 files changed, 252 insertions(+)

diff --git a/.travis.yml b/.travis.yml
new file mode 100755
index 0000000..a619141
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,50 @@
+language: go
+sudo: required
+go: 
+  - 1.11
+install: true
+
+before_script:
+  - mkdir -p $HOME/gopath/src/github.com/apache/servicecomb-kie
+  - rsync -az ${TRAVIS_BUILD_DIR}/ $HOME/gopath/src/github.com/apache/servicecomb-kie/
+  - export TRAVIS_BUILD_DIR=$HOME/gopath/src/github.com/apache/servicecomb-kie
+  - cd $HOME/gopath/src/github.com/apache/servicecomb-kie
+
+jobs:
+  include:
+    - stage: Format Checker
+      script: bash scripts/travis/formatChecker.sh
+    - stage: DeadCode Checker
+      script: 
+        - go get -u github.com/tsenart/deadcode
+        - bash scripts/travis/deadCodeChecker.sh
+    - stage: Misspell Checker
+      script: 
+        - go get -u github.com/client9/misspell
+        - bash scripts/travis/misspellChecker.sh
+    - stage: GoConst Checker
+      script:
+        - go get -u github.com/jgautheron/goconst/cmd/goconst
+        - bash scripts/travis/goConstChecker.sh
+    - stage: GoLint Checker
+      script:
+        - go get -u github.com/golang/lint/golint
+        - bash scripts/travis/goLintChecker.sh
+    - stage: GoCyclo Checker
+      script:
+        - go get github.com/fzipp/gocyclo
+        - bash scripts/travis/goCycloChecker.sh
+    - stage: Unit Test
+      script:
+        - bash scripts/travis/start_deps.sh
+        - go get github.com/mattn/goveralls
+        - go get golang.org/x/tools/cmd/cover
+        - GO111MODULE=on go mod download
+        - GO111MODULE=on go mod vendor
+        - bash scripts/travis/unit_test.sh && $HOME/gopath/bin/goveralls -coverprofile=coverage.txt -service=travis-ci
+
+    - stage: Build
+      script: 
+        - cd build
+        - ./build_server.sh
+
diff --git a/scripts/travis/deadCodeChecker.sh b/scripts/travis/deadCodeChecker.sh
new file mode 100755
index 0000000..70f9879
--- /dev/null
+++ b/scripts/travis/deadCodeChecker.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+
+# 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.
+diff -u <(echo -n) <(find . -type d -not -path "./vendor/*" | xargs deadcode)
+if [ $? == 0 ]; then
+	echo "Hurray....all code's are reachable and utilised..."
+	exit 0
+else
+	echo "There are some deadcode in the project...please remove the unused code"
+	exit 1
+fi
diff --git a/scripts/travis/formatChecker.sh b/scripts/travis/formatChecker.sh
new file mode 100755
index 0000000..8d45994
--- /dev/null
+++ b/scripts/travis/formatChecker.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+
+# 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.
+diff -u <(echo -n) <(find . -name "*.go" -not -path "./vendor/*" -not -path ".git/*" | xargs gofmt -s -d)
+if [ $? == 0 ]; then
+	echo "Hurray....all code is formatted properly..."
+	exit 0
+else
+	echo "There is issues's with the code formatting....please run go fmt on your code"
+	exit 1
+fi
diff --git a/scripts/travis/goConstChecker.sh b/scripts/travis/goConstChecker.sh
new file mode 100755
index 0000000..ae9d86e
--- /dev/null
+++ b/scripts/travis/goConstChecker.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+
+# 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.
+diff -u <(echo -n) <(goconst ./... | grep -v vendor | grep -v third_party)
+if [ $? == 0 ]; then
+	echo "No goConst problem"
+	exit 0
+else
+	echo "Has goConst Problem"
+	exit 1
+fi
diff --git a/scripts/travis/goCycloChecker.sh b/scripts/travis/goCycloChecker.sh
new file mode 100755
index 0000000..11fd9d3
--- /dev/null
+++ b/scripts/travis/goCycloChecker.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+
+# 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.
+diff -u <(echo -n) <(find . -name "*.go" -not -path "./vendor/*" -not -path ".git/*" -not -path "./third_party/*" | grep -v _test | xargs gocyclo -over 16)
+if [ $? == 0 ]; then
+	echo "All function has less cyclomatic complexity..."
+	exit 0
+else
+	echo "Fucntions/function has more cyclomatic complexity..."
+	exit 1
+fi
diff --git a/scripts/travis/goLintChecker.sh b/scripts/travis/goLintChecker.sh
new file mode 100755
index 0000000..dfa3254
--- /dev/null
+++ b/scripts/travis/goLintChecker.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+
+# 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.
+diff -u <(echo -n) <(golint ./... | grep -v vendor | grep -v third_party | grep -v stutters | grep -v _test | grep -v examples | grep -v benchmark)
+if [ $? == 0 ]; then
+	echo "No GoLint warnings found"
+	exit 0
+else
+	echo "GoLint Warnings found"
+	exit 1
+fi
diff --git a/scripts/travis/goVetChecker.sh b/scripts/travis/goVetChecker.sh
new file mode 100755
index 0000000..8b15de5
--- /dev/null
+++ b/scripts/travis/goVetChecker.sh
@@ -0,0 +1,8 @@
+diff -u <(echo -n) <(find . -type d -not -path "./vendor/*" -not -path "./third_party/*"| xargs go vet )
+if [ $? == 0 ]; then
+	echo "Hurray....all OKAY..."
+	exit 0
+else
+	echo "There are some static issues in the project...please run go vet"
+	exit 1
+fi
diff --git a/scripts/travis/misspellChecker.sh b/scripts/travis/misspellChecker.sh
new file mode 100755
index 0000000..3d69e1e
--- /dev/null
+++ b/scripts/travis/misspellChecker.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+
+# 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.
+diff -u <(echo -n) <(find . -type f -not -path "./vendor/*" -not -path "./third_party/*" -print0 | xargs -0 misspell)
+if [ $? == 0 ]; then
+	echo "No Misspell found"
+	exit 0
+else
+	echo "Misspell found"
+	exit 1
+fi
diff --git a/scripts/travis/start_deps.sh b/scripts/travis/start_deps.sh
new file mode 100755
index 0000000..b4587ef
--- /dev/null
+++ b/scripts/travis/start_deps.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+
+# 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.
+
+docker-compose up -f $GOPATH/src/github.com/apache/servicecomb-kie/deployments/docker/docker-compose.yaml
\ No newline at end of file
diff --git a/scripts/travis/unit_test.sh b/scripts/travis/unit_test.sh
new file mode 100755
index 0000000..7568afd
--- /dev/null
+++ b/scripts/travis/unit_test.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+# 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.
+set -e
+# Make the Coverage File
+echo "mode: atomic" > coverage.txt
+
+#Start the Test
+for d in $(go list ./... | grep -v vendor |  grep -v third_party | grep -v examples); do
+    echo $d
+    echo $GOPATH
+    cd $GOPATH/src/$d
+    if [ $(ls | grep _test.go | wc -l) -gt 0 ]; then
+        go test -v -cover -covermode atomic -coverprofile coverage.out
+        if [ -f coverage.out ]; then
+            sed '1d;$d' coverage.out >> $GOPATH/src/github.com/apache/servicecomb-kie/coverage.txt
+        fi
+    fi
+done


[servicecomb-kie] 17/29: fix bug, key is duplicated

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

asifdxtreme pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git

commit 8f4f5e76d5c27d5b32ee475b098264b8481268a5
Author: tian <xi...@gmail.com>
AuthorDate: Thu Jun 6 18:47:09 2019 +0800

    fix bug, key is duplicated
---
 pkg/model/kv.go                       |  4 ++--
 pkg/model/mongodb_doc.go              |  4 ++++
 server/dao/kie_api.go                 | 19 +++++++++++--------
 pkg/model/kv.go => server/dao/tool.go | 12 ++++++++----
 4 files changed, 25 insertions(+), 14 deletions(-)

diff --git a/pkg/model/kv.go b/pkg/model/kv.go
index 332c074..73d33e3 100644
--- a/pkg/model/kv.go
+++ b/pkg/model/kv.go
@@ -18,6 +18,6 @@
 package model
 
 type KVResponse struct {
-	LabelDoc *LabelDoc `json:"labels"`
-	Data     []*KVDoc `json:"data"`
+	LabelDoc *LabelDocResponse `json:"label"`
+	Data     []*KVDoc          `json:"data"`
 }
diff --git a/pkg/model/mongodb_doc.go b/pkg/model/mongodb_doc.go
index 7645a14..71a9483 100644
--- a/pkg/model/mongodb_doc.go
+++ b/pkg/model/mongodb_doc.go
@@ -19,6 +19,10 @@ package model
 
 import "go.mongodb.org/mongo-driver/bson/primitive"
 
+type LabelDocResponse struct {
+	LabelID string            `json:"label_id,omitempty"`
+	Labels  map[string]string `json:"labels,omitempty"`
+}
 type LabelDoc struct {
 	ID       primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"`
 	Labels   map[string]string  `json:"labels,omitempty"`
diff --git a/server/dao/kie_api.go b/server/dao/kie_api.go
index aaf613f..323d8e7 100644
--- a/server/dao/kie_api.go
+++ b/server/dao/kie_api.go
@@ -229,15 +229,14 @@ func (s *MongodbService) FindKV(ctx context.Context, domain string, options ...F
 			}
 			if len(curKV.Labels) == len(opts.Labels) {
 				openlogging.Debug("hit exact labels")
-				curKV.Domain = ""
-				curKV.Labels = nil //exact match don't need to return labels
 				labelGroup := &model.KVResponse{
-					LabelDoc: &model.LabelDoc{
-						Labels: opts.Labels,
-						ID:     primitive.NilObjectID,
+					LabelDoc: &model.LabelDocResponse{
+						Labels:  opts.Labels,
+						LabelID: curKV.LabelID,
 					},
 					Data: make([]*model.KVDoc, 0),
 				}
+				clearKV(curKV)
 				labelGroup.Data = append(labelGroup.Data, curKV)
 				kvResp = append(kvResp, labelGroup)
 				return kvResp, nil
@@ -268,6 +267,7 @@ func (s *MongodbService) FindKV(ctx context.Context, domain string, options ...F
 			for _, labelGroup = range kvResp {
 				if reflect.DeepEqual(labelGroup.LabelDoc.Labels, curKV.Labels) {
 					groupExist = true
+					clearKV(curKV)
 					labelGroup.Data = append(labelGroup.Data, curKV)
 					break
 				}
@@ -275,14 +275,17 @@ func (s *MongodbService) FindKV(ctx context.Context, domain string, options ...F
 			}
 			if !groupExist {
 				labelGroup = &model.KVResponse{
-					LabelDoc: &model.LabelDoc{
-						Labels: curKV.Labels,
+					LabelDoc: &model.LabelDocResponse{
+						Labels:  curKV.Labels,
+						LabelID: curKV.LabelID,
 					},
 					Data: []*model.KVDoc{curKV},
 				}
+				clearKV(curKV)
 				openlogging.Debug("add new label group")
+				kvResp = append(kvResp, labelGroup)
 			}
-			kvResp = append(kvResp, labelGroup)
+
 		}
 		if len(kvResp) == 0 {
 			return nil, ErrKeyNotExists
diff --git a/pkg/model/kv.go b/server/dao/tool.go
similarity index 79%
copy from pkg/model/kv.go
copy to server/dao/tool.go
index 332c074..b3d5ea4 100644
--- a/pkg/model/kv.go
+++ b/server/dao/tool.go
@@ -15,9 +15,13 @@
  * limitations under the License.
  */
 
-package model
+package dao
 
-type KVResponse struct {
-	LabelDoc *LabelDoc `json:"labels"`
-	Data     []*KVDoc `json:"data"`
+import "github.com/apache/servicecomb-kie/pkg/model"
+
+//clearKV clean attr which don't need to return to client side
+func clearKV(kv *model.KVDoc) {
+	kv.Domain = ""
+	kv.Labels = nil
+	kv.LabelID = ""
 }


[servicecomb-kie] 09/29: add license

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

asifdxtreme pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git

commit ebcea39c60d289c77dcec0d4f654aa58b6b44e7f
Author: tian <xi...@gmail.com>
AuthorDate: Wed May 15 16:43:03 2019 +0800

    add license
---
 build/build_server.sh | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/build/build_server.sh b/build/build_server.sh
index 63693a7..4aeeded 100755
--- a/build/build_server.sh
+++ b/build/build_server.sh
@@ -1,4 +1,19 @@
 #!/usr/bin/env bash
+# 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.
+
 export BUILD_DIR=$(cd "$(dirname "$0")"; pwd)
 export PROJECT_DIR=$(dirname ${BUILD_DIR})
 echo "downloading dependencies"


[servicecomb-kie] 12/29: add delete by id string

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

asifdxtreme pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git

commit 49d238a4c3977fbf897fccdcdbfafa62bc9b1282
Author: wangqijun <wa...@sohu.com>
AuthorDate: Fri May 24 22:18:57 2019 +0800

    add delete by id string
---
 server/dao/kv.go                  |  7 +++--
 server/dao/kv_test.go             | 53 ++++++++++++++++++++++++++++++++++++
 server/dao/mongodb.go             | 38 +++++++++++++++++++++++++-
 server/resource/v1/common.go      |  5 +++-
 server/resource/v1/kv_resource.go | 57 ++++++++++++++++++++++++++++++++++++++-
 5 files changed, 153 insertions(+), 7 deletions(-)

diff --git a/server/dao/kv.go b/server/dao/kv.go
index de32cc3..9cf40fe 100644
--- a/server/dao/kv.go
+++ b/server/dao/kv.go
@@ -21,9 +21,9 @@ package dao
 import (
 	"crypto/tls"
 	"errors"
-	"time"
-	"github.com/apache/servicecomb-kie/server/config"
 	"github.com/apache/servicecomb-kie/pkg/model"
+	"github.com/apache/servicecomb-kie/server/config"
+	"time"
 )
 
 var ErrMissingDomain = errors.New("domain info missing, illegal access")
@@ -35,8 +35,7 @@ type KV interface {
 	CreateOrUpdate(kv *model.KV) (*model.KV, error)
 	//do not use primitive.ObjectID as return to decouple with mongodb, we can afford perf lost
 	Exist(key, domain string, labels model.Labels) (string, error)
-	DeleteByID(id string) error
-	Delete(key, domain string, labels model.Labels) error
+	Delete(ids []string, domain string) error
 	Find(domain string, options ...FindOption) ([]*model.KV, error)
 	AddHistory(kv *model.KV) error
 	//RollBack(kv *KV, version string) error
diff --git a/server/dao/kv_test.go b/server/dao/kv_test.go
index 9cb23ad..81bd106 100644
--- a/server/dao/kv_test.go
+++ b/server/dao/kv_test.go
@@ -189,4 +189,57 @@ var _ = Describe("Kv mongodb service", func() {
 
 		})
 	})
+
+	Describe("delete key", func() {
+		Context("delete key by id,seperated by ',' ", func() {
+			kv1, err := s.CreateOrUpdate(&model.KV{
+				Key:    "timeout",
+				Value:  "20s",
+				Domain: "default",
+				Labels: map[string]string{
+					"env": "test",
+				},
+			})
+			It("should not return err", func() {
+				Expect(err).Should(BeNil())
+			})
+
+			kv2, err := s.CreateOrUpdate(&model.KV{
+				Key:    "times",
+				Value:  "3",
+				Domain: "default",
+				Labels: map[string]string{
+					"env": "test",
+				},
+			})
+			It("should not return err", func() {
+				Expect(err).Should(BeNil())
+			})
+
+			ids := []string{kv1.ID.Hex(), kv2.ID.Hex()}
+			err = s.Delete(ids, "default")
+			It("should not return err", func() {
+				Expect(err).Should(BeNil())
+			})
+
+		})
+		Context("test miss ids, no panic", func() {
+			err := s.Delete(nil, "default")
+			It("should not return err", func() {
+				Expect(err).Should(BeNil())
+			})
+		})
+		Context("Test encode error ", func() {
+			err := s.Delete([]string{"12312312321"}, "default")
+			It("should return err", func() {
+				Expect(err).To(HaveOccurred())
+			})
+		})
+		Context("Test miss domain error ", func() {
+			err := s.Delete([]string{"5ce3602381fc6e33708b9621"}, "")
+			It("should return err", func() {
+				Expect(err).Should(Equal(dao.ErrMissingDomain))
+			})
+		})
+	})
 })
diff --git a/server/dao/mongodb.go b/server/dao/mongodb.go
index cbaabad..9fc6ad0 100644
--- a/server/dao/mongodb.go
+++ b/server/dao/mongodb.go
@@ -224,7 +224,43 @@ func (s *MongodbService) DeleteByID(id string) error {
 	return nil
 }
 
-func (s *MongodbService) Delete(key, domain string, labels model.Labels) error {
+func (s *MongodbService) Delete(ids []string, domain string) error {
+	if len(ids) == 0 {
+		openlogging.Warn("delete error,ids is blank")
+		return nil
+	}
+	if domain == "" {
+		return ErrMissingDomain
+	}
+	collection := s.c.Database(DB).Collection(CollectionKV)
+	//transfer id
+	var oid []primitive.ObjectID
+	for _, v := range ids {
+		if v == "" {
+			openlogging.Warn("ids contains continuous ','")
+			continue
+		}
+		hex, err := primitive.ObjectIDFromHex(v)
+		if err != nil {
+			openlogging.Error(fmt.Sprintf("convert %s ,err:%s", v, err))
+			return err
+		}
+		oid = append(oid, hex)
+	}
+	//use in filter
+	filter := &bson.M{"_id": &bson.M{"$in": oid}, "domain": domain}
+	ctx, _ := context.WithTimeout(context.Background(), DefaultTimeout)
+	dr, err := collection.DeleteMany(ctx, filter)
+	//check error and delete number
+	if err != nil {
+		openlogging.Error(fmt.Sprintf("delete [%s] failed : [%s]", filter, err))
+		return err
+	}
+	if dr.DeletedCount != int64(len(oid)) {
+		openlogging.Warn(fmt.Sprintf(" The actual number of deletions[%d] is not equal to the parameters[%d].", dr.DeletedCount, len(oid)))
+	} else {
+		openlogging.Info(fmt.Sprintf("delete success,count=%d", dr.DeletedCount))
+	}
 	return nil
 }
 func (s *MongodbService) AddHistory(kv *model.KV) error {
diff --git a/server/resource/v1/common.go b/server/resource/v1/common.go
index bee9f36..e246602 100644
--- a/server/resource/v1/common.go
+++ b/server/resource/v1/common.go
@@ -27,10 +27,13 @@ import (
 )
 
 const (
+	FindExact               = "exact"
+	FindMany                = "greedy"
 	MsgDomainMustNotBeEmpty = "domain must not be empty"
-	MsgIllegalFindPolicy    = "value of header "+common.HeaderMatch+" can be greedy or exact"
+	MsgIllegalFindPolicy    = "value of header " + common.HeaderMatch + " can be greedy or exact"
 	MsgIllegalLabels        = "label's value can not be empty, " +
 		"label can not be duplicated, please check your query parameters"
+	ErrIDMustNotEmpty = "must supply id if you want to remove key"
 )
 
 func ReadDomain(context *restful.Context) interface{} {
diff --git a/server/resource/v1/kv_resource.go b/server/resource/v1/kv_resource.go
index 0030e7b..4839279 100644
--- a/server/resource/v1/kv_resource.go
+++ b/server/resource/v1/kv_resource.go
@@ -20,6 +20,7 @@ package v1
 
 import (
 	"encoding/json"
+	"fmt"
 	"github.com/apache/servicecomb-kie/pkg/common"
 	"github.com/apache/servicecomb-kie/pkg/model"
 	"github.com/apache/servicecomb-kie/server/dao"
@@ -27,6 +28,7 @@ import (
 	"github.com/go-chassis/go-chassis/server/restful"
 	"github.com/go-mesh/openlogging"
 	"net/http"
+	"strings"
 )
 
 type KVResource struct {
@@ -159,7 +161,28 @@ func (r *KVResource) FindByLabels(context *restful.Context) {
 
 }
 func (r *KVResource) Delete(context *restful.Context) {
-
+	domain := ReadDomain(context)
+	if domain == nil {
+		WriteErrResponse(context, http.StatusInternalServerError, MsgDomainMustNotBeEmpty)
+	}
+	ids := context.ReadPathParameter("ids")
+	if ids == "" {
+		WriteErrResponse(context, http.StatusBadRequest, ErrIDMustNotEmpty)
+		return
+	}
+	idArray := strings.Split(ids, ",")
+	s, err := dao.NewKVService()
+	if err != nil {
+		WriteErrResponse(context, http.StatusInternalServerError, err.Error())
+		return
+	}
+	err = s.Delete(idArray, domain.(string))
+	if err != nil {
+		openlogging.Error(fmt.Sprintf("delete ids=%s,err=%s", ids, err.Error()))
+		WriteErrResponse(context, http.StatusInternalServerError, err.Error())
+		return
+	}
+	context.WriteHeader(http.StatusNoContent)
 }
 
 //URLPatterns defined config operations
@@ -253,6 +276,38 @@ func (r *KVResource) URLPatterns() []restful.Route {
 			},
 			Consumes: []string{"application/json"},
 			Produces: []string{"application/json"},
+		}, {
+			Method:           http.MethodDelete,
+			Path:             "/v1/kv/{ids}",
+			ResourceFuncName: "Delete",
+			FuncDesc:         "delete key by id,seperated by ','",
+			Parameters: []*restful.Parameters{
+				{
+					DataType:  "string",
+					Name:      "X-Domain-Name",
+					ParamType: goRestful.HeaderParameterKind,
+				}, {
+					DataType:  "string",
+					Name:      "ids",
+					ParamType: goRestful.PathParameterKind,
+					Desc: "The id strings to be removed are separated by ',',If the actual number of deletions " +
+						"and the number of parameters are not equal, no error will be returned and only warn log will be printed.",
+				},
+			},
+			Returns: []*restful.Returns{
+				{
+					Code:    http.StatusNoContent,
+					Message: "Delete success",
+				},
+				{
+					Code:    http.StatusBadRequest,
+					Message: "Failed,check url",
+				},
+				{
+					Code:    http.StatusInternalServerError,
+					Message: "Server error",
+				},
+			},
 		},
 	}
 }


[servicecomb-kie] 10/29: add go client, return 404 if key not exist

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

asifdxtreme pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git

commit e2b43842ef6dd237f4e3d9bcf70207a5e3b3e8aa
Author: tian <xi...@gmail.com>
AuthorDate: Fri May 17 10:46:30 2019 +0800

    add go client, return 404 if key not exist
---
 build/build_server.sh                              |   6 +-
 client/client.go                                   | 106 +++++++++++++++++++++
 .../client_suite_test.go                           |   6 +-
 client/client_test.go                              |  65 +++++++++++++
 .../dao/model_suite_test.go => client/options.go   |  37 +++----
 go.mod                                             |   1 +
 .../model_suite_test.go => pkg/common/common.go    |  31 ++----
 .../dao/{model_suite_test.go => dao_suite_test.go} |   2 +-
 server/resource/v1/common.go                       |  12 +--
 server/resource/v1/kv_resource.go                  |  29 ++++--
 10 files changed, 228 insertions(+), 67 deletions(-)

diff --git a/build/build_server.sh b/build/build_server.sh
index 4aeeded..2ffe85b 100755
--- a/build/build_server.sh
+++ b/build/build_server.sh
@@ -13,7 +13,11 @@
 # 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.
-
+if [ -z "${GOPATH}" ]; then
+ echo "missing GOPATH env, can not build"
+ exit 1
+fi
+echo "GOPATH is "${GOPATH}
 export BUILD_DIR=$(cd "$(dirname "$0")"; pwd)
 export PROJECT_DIR=$(dirname ${BUILD_DIR})
 echo "downloading dependencies"
diff --git a/client/client.go b/client/client.go
new file mode 100644
index 0000000..cb78d7c
--- /dev/null
+++ b/client/client.go
@@ -0,0 +1,106 @@
+/*
+ * 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 client
+
+import (
+	"context"
+	"crypto/tls"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"github.com/apache/servicecomb-kie/pkg/common"
+	"github.com/apache/servicecomb-kie/pkg/model"
+	"github.com/go-chassis/foundation/httpclient"
+	"github.com/go-chassis/foundation/security"
+	"github.com/go-chassis/go-chassis/pkg/util/httputil"
+	"github.com/go-mesh/openlogging"
+	"net/http"
+	"net/url"
+)
+
+const (
+	APIPathKV = "v1/kv"
+)
+
+var (
+	ErrKeyNotExist = errors.New("can not find value")
+)
+
+type Client struct {
+	opts   Config
+	cipher security.Cipher
+	c      *httpclient.URLClient
+}
+type Config struct {
+	Endpoint      string
+	DefaultLabels map[string]string
+	VerifyPeer    bool //TODO make it works, now just keep it false
+}
+
+func New(config Config) (*Client, error) {
+	u, err := url.Parse(config.Endpoint)
+	if err != nil {
+		return nil, err
+	}
+	httpOpts := &httpclient.URLClientOption{}
+	if u.Scheme == "https" {
+		httpOpts.TLSConfig = &tls.Config{
+			InsecureSkipVerify: !config.VerifyPeer,
+		}
+	}
+	c, err := httpclient.GetURLClient(httpOpts)
+	if err != nil {
+		return nil, err
+	}
+	return &Client{
+		opts: config,
+		c:    c,
+	}, nil
+}
+
+//GetValue get value of a key
+func (c *Client) Get(ctx context.Context, key string, opts ...GetOption) ([]*model.KV, error) {
+	options := GetOptions{}
+	for _, o := range opts {
+		o(&options)
+	}
+	url := fmt.Sprintf("%s/%s/%s", c.opts.Endpoint, APIPathKV, key)
+	h := http.Header{}
+	if options.MatchMode != "" {
+		h.Set(common.HeaderMatch, options.MatchMode)
+	}
+	resp, err := c.c.HTTPDo("GET", url, h, nil)
+	if err != nil {
+		return nil, err
+	}
+	b := httputil.ReadBody(resp)
+	if resp.StatusCode != http.StatusOK {
+		if resp.StatusCode == http.StatusNotFound {
+			return nil, ErrKeyNotExist
+		}
+		return nil, fmt.Errorf("get %s failed,http status [%s], body [%s]", key, resp.Status, b)
+	}
+
+	kvs := make([]*model.KV, 0)
+	err = json.Unmarshal(b, kvs)
+	if err != nil {
+		openlogging.Error("unmarshal kv failed:" + err.Error())
+		return nil, err
+	}
+	return kvs, nil
+}
diff --git a/server/dao/model_suite_test.go b/client/client_suite_test.go
similarity index 90%
copy from server/dao/model_suite_test.go
copy to client/client_suite_test.go
index a57389e..27a4f23 100644
--- a/server/dao/model_suite_test.go
+++ b/client/client_suite_test.go
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package dao_test
+package client_test
 
 import (
 	"testing"
@@ -27,10 +27,10 @@ import (
 	. "github.com/onsi/gomega"
 )
 
-func TestModel(t *testing.T) {
+func TestClient(t *testing.T) {
 	RegisterFailHandler(Fail)
 	junitReporter := reporters.NewJUnitReporter("junit.xml")
-	RunSpecsWithDefaultAndCustomReporters(t, "Model Suite", []Reporter{junitReporter})
+	RunSpecsWithDefaultAndCustomReporters(t, "Client Suite", []Reporter{junitReporter})
 }
 
 var _ = BeforeSuite(func() {
diff --git a/client/client_test.go b/client/client_test.go
new file mode 100644
index 0000000..3e02b02
--- /dev/null
+++ b/client/client_test.go
@@ -0,0 +1,65 @@
+/*
+ * 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 client_test
+
+import (
+	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/gomega"
+
+	"context"
+	. "github.com/apache/servicecomb-kie/client"
+	"os"
+)
+
+var _ = Describe("Client", func() {
+	var c1 *Client
+	os.Setenv("HTTP_DEBUG", "1")
+	Describe("new client ", func() {
+		Context("with http protocol", func() {
+			var err error
+			c1, err = New(Config{
+				Endpoint: "http://127.0.0.1:30110",
+			})
+			It("should not return err", func() {
+				Expect(err).Should(BeNil())
+			})
+			It("should return client", func() {
+				Expect(c1).ShouldNot(BeNil())
+			})
+
+		})
+	})
+	Describe("get ", func() {
+		Context("only by key", func() {
+			_, err := c1.Get(context.TODO(), "app.properties")
+			It("should be 404 error", func() {
+				Expect(err).Should(Equal(ErrKeyNotExist))
+			})
+
+		})
+		Context("by key and labels", func() {
+			_, err := c1.Get(context.TODO(), "app.properties", WithLables(map[string]string{
+				"app": "mall",
+			}))
+			It("should be 404 error", func() {
+				Expect(err).Should(Equal(ErrKeyNotExist))
+			})
+
+		})
+	})
+})
diff --git a/server/dao/model_suite_test.go b/client/options.go
similarity index 58%
copy from server/dao/model_suite_test.go
copy to client/options.go
index a57389e..351b476 100644
--- a/server/dao/model_suite_test.go
+++ b/client/options.go
@@ -15,30 +15,23 @@
  * limitations under the License.
  */
 
-package dao_test
+package client
 
-import (
-	"testing"
 
-	"github.com/go-chassis/paas-lager"
-	"github.com/go-mesh/openlogging"
-	. "github.com/onsi/ginkgo"
-	"github.com/onsi/ginkgo/reporters"
-	. "github.com/onsi/gomega"
-)
 
-func TestModel(t *testing.T) {
-	RegisterFailHandler(Fail)
-	junitReporter := reporters.NewJUnitReporter("junit.xml")
-	RunSpecsWithDefaultAndCustomReporters(t, "Model Suite", []Reporter{junitReporter})
+type GetOption func(*GetOptions)
+type GetOptions struct {
+	Labels    map[string]string
+	MatchMode string
 }
 
-var _ = BeforeSuite(func() {
-	log.Init(log.Config{
-		Writers:     []string{"stdout"},
-		LoggerLevel: "DEBUG",
-	})
-
-	logger := log.NewLogger("ut")
-	openlogging.SetLogger(logger)
-})
+func WithLables(l map[string]string) GetOption {
+	return func(options *GetOptions) {
+		options.Labels = l
+	}
+}
+func WithMatchMode(m string) GetOption {
+	return func(options *GetOptions) {
+		options.MatchMode = m
+	}
+}
diff --git a/go.mod b/go.mod
index 2161b5c..dd87b23 100644
--- a/go.mod
+++ b/go.mod
@@ -2,6 +2,7 @@ module github.com/apache/servicecomb-kie
 
 require (
 	github.com/emicklei/go-restful v2.8.0+incompatible
+	github.com/go-chassis/foundation v0.0.0-20190203091418-304855ea28bf
 	github.com/go-chassis/go-archaius v0.16.0
 	github.com/go-chassis/go-chassis v1.4.0
 	github.com/go-chassis/paas-lager v1.0.2-0.20190328010332-cf506050ddb2
diff --git a/server/dao/model_suite_test.go b/pkg/common/common.go
similarity index 58%
copy from server/dao/model_suite_test.go
copy to pkg/common/common.go
index a57389e..47e224e 100644
--- a/server/dao/model_suite_test.go
+++ b/pkg/common/common.go
@@ -15,30 +15,13 @@
  * limitations under the License.
  */
 
-package dao_test
+package common
 
-import (
-	"testing"
-
-	"github.com/go-chassis/paas-lager"
-	"github.com/go-mesh/openlogging"
-	. "github.com/onsi/ginkgo"
-	"github.com/onsi/ginkgo/reporters"
-	. "github.com/onsi/gomega"
+const (
+	MatchGreedy = "greedy"
+	MatchExact  = "exact"
 )
 
-func TestModel(t *testing.T) {
-	RegisterFailHandler(Fail)
-	junitReporter := reporters.NewJUnitReporter("junit.xml")
-	RunSpecsWithDefaultAndCustomReporters(t, "Model Suite", []Reporter{junitReporter})
-}
-
-var _ = BeforeSuite(func() {
-	log.Init(log.Config{
-		Writers:     []string{"stdout"},
-		LoggerLevel: "DEBUG",
-	})
-
-	logger := log.NewLogger("ut")
-	openlogging.SetLogger(logger)
-})
+const (
+	HeaderMatch = "X-Match"
+)
diff --git a/server/dao/model_suite_test.go b/server/dao/dao_suite_test.go
similarity index 93%
rename from server/dao/model_suite_test.go
rename to server/dao/dao_suite_test.go
index a57389e..8be7dc3 100644
--- a/server/dao/model_suite_test.go
+++ b/server/dao/dao_suite_test.go
@@ -30,7 +30,7 @@ import (
 func TestModel(t *testing.T) {
 	RegisterFailHandler(Fail)
 	junitReporter := reporters.NewJUnitReporter("junit.xml")
-	RunSpecsWithDefaultAndCustomReporters(t, "Model Suite", []Reporter{junitReporter})
+	RunSpecsWithDefaultAndCustomReporters(t, "Dao Suite", []Reporter{junitReporter})
 }
 
 var _ = BeforeSuite(func() {
diff --git a/server/resource/v1/common.go b/server/resource/v1/common.go
index 5d7bceb..bee9f36 100644
--- a/server/resource/v1/common.go
+++ b/server/resource/v1/common.go
@@ -20,16 +20,15 @@ package v1
 import (
 	"encoding/json"
 	"fmt"
+	"github.com/apache/servicecomb-kie/pkg/common"
 	"github.com/apache/servicecomb-kie/pkg/model"
 	"github.com/go-chassis/go-chassis/server/restful"
 	"github.com/go-mesh/openlogging"
 )
 
 const (
-	FindExact               = "exact"
-	FindMany                = "greedy"
 	MsgDomainMustNotBeEmpty = "domain must not be empty"
-	MsgIllegalFindPolicy    = "value of header X-Find can be greedy or exact"
+	MsgIllegalFindPolicy    = "value of header "+common.HeaderMatch+" can be greedy or exact"
 	MsgIllegalLabels        = "label's value can not be empty, " +
 		"label can not be duplicated, please check your query parameters"
 )
@@ -37,10 +36,11 @@ const (
 func ReadDomain(context *restful.Context) interface{} {
 	return context.ReadRestfulRequest().Attribute("domain")
 }
-func ReadFindPolicy(context *restful.Context) string {
-	policy := context.ReadRestfulRequest().HeaderParameter("X-Find")
+func ReadMatchPolicy(context *restful.Context) string {
+	policy := context.ReadRestfulRequest().HeaderParameter(common.HeaderMatch)
 	if policy == "" {
-		return FindMany
+		//default is exact to reduce network traffic
+		return common.MatchExact
 	}
 	return policy
 }
diff --git a/server/resource/v1/kv_resource.go b/server/resource/v1/kv_resource.go
index 7a9d66d..0030e7b 100644
--- a/server/resource/v1/kv_resource.go
+++ b/server/resource/v1/kv_resource.go
@@ -20,6 +20,7 @@ package v1
 
 import (
 	"encoding/json"
+	"github.com/apache/servicecomb-kie/pkg/common"
 	"github.com/apache/servicecomb-kie/pkg/model"
 	"github.com/apache/servicecomb-kie/server/dao"
 	goRestful "github.com/emicklei/go-restful"
@@ -62,7 +63,7 @@ func (r *KVResource) Put(context *restful.Context) {
 	context.WriteHeaderAndJSON(http.StatusOK, kv, goRestful.MIME_JSON)
 
 }
-func (r *KVResource) Find(context *restful.Context) {
+func (r *KVResource) FindWithKey(context *restful.Context) {
 	var err error
 	key := context.ReadPathParameter("key")
 	if key == "" {
@@ -88,18 +89,22 @@ func (r *KVResource) Find(context *restful.Context) {
 		WriteErrResponse(context, http.StatusInternalServerError, MsgDomainMustNotBeEmpty)
 		return
 	}
-	policy := ReadFindPolicy(context)
+	policy := ReadMatchPolicy(context)
 	var kvs []*model.KV
 	switch policy {
-	case FindMany:
+	case common.MatchGreedy:
 		kvs, err = s.Find(domain.(string), dao.WithKey(key), dao.WithLabels(labels))
-	case FindExact:
+	case common.MatchExact:
 		kvs, err = s.Find(domain.(string), dao.WithKey(key), dao.WithLabels(labels),
 			dao.WithExactLabels())
 	default:
 		WriteErrResponse(context, http.StatusBadRequest, MsgIllegalFindPolicy)
 		return
 	}
+	if err == dao.ErrNotExists {
+		WriteErrResponse(context, http.StatusNotFound, err.Error())
+		return
+	}
 	if err != nil {
 		WriteErrResponse(context, http.StatusInternalServerError, err.Error())
 		return
@@ -131,18 +136,22 @@ func (r *KVResource) FindByLabels(context *restful.Context) {
 		WriteErrResponse(context, http.StatusInternalServerError, MsgDomainMustNotBeEmpty)
 		return
 	}
-	policy := ReadFindPolicy(context)
+	policy := ReadMatchPolicy(context)
 	var kvs []*model.KV
 	switch policy {
-	case FindMany:
+	case common.MatchGreedy:
 		kvs, err = s.Find(domain.(string), dao.WithLabels(labels))
-	case FindExact:
+	case common.MatchExact:
 		kvs, err = s.Find(domain.(string), dao.WithLabels(labels),
 			dao.WithExactLabels())
 	default:
 		WriteErrResponse(context, http.StatusBadRequest, MsgIllegalFindPolicy)
 		return
 	}
+	if err == dao.ErrNotExists {
+		WriteErrResponse(context, http.StatusNotFound, err.Error())
+		return
+	}
 	err = context.WriteHeaderAndJSON(http.StatusOK, kvs, goRestful.MIME_JSON)
 	if err != nil {
 		openlogging.Error(err.Error())
@@ -190,7 +199,7 @@ func (r *KVResource) URLPatterns() []restful.Route {
 		}, {
 			Method:           http.MethodGet,
 			Path:             "/v1/kv/{key}",
-			ResourceFuncName: "Find",
+			ResourceFuncName: "FindWithKey",
 			FuncDesc:         "get key values by key and labels",
 			Parameters: []*restful.Parameters{
 				{
@@ -203,7 +212,7 @@ func (r *KVResource) URLPatterns() []restful.Route {
 					ParamType: goRestful.HeaderParameterKind,
 				}, {
 					DataType:  "string",
-					Name:      "X-Find",
+					Name:      common.HeaderMatch,
 					ParamType: goRestful.HeaderParameterKind,
 					Desc:      "greedy or exact",
 				},
@@ -230,7 +239,7 @@ func (r *KVResource) URLPatterns() []restful.Route {
 					ParamType: goRestful.HeaderParameterKind,
 				}, {
 					DataType:  "string",
-					Name:      "X-Find",
+					Name:      common.HeaderMatch,
 					ParamType: goRestful.HeaderParameterKind,
 					Desc:      "greedy or exact",
 				},


[servicecomb-kie] 08/29: add docker compose deployment build script for release a binary default port is 30110 upgrade go-archaius

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

asifdxtreme pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git

commit 849ec5edca0cbc4bcab06d0301f9901fcc54dfc9
Author: tian <xi...@gmail.com>
AuthorDate: Tue May 14 15:33:35 2019 +0800

    add docker compose deployment
    build script for release a binary
    default port is 30110
    upgrade go-archaius
---
 .gitignore                             |  1 +
 README.md                              | 29 ++++++++++--
 build/build_server.sh                  | 80 ++++++++++++++++++++++++++++++++++
 build/docker/server/Dockerfile         | 26 +++++++++++
 deployments/docker/db.js               | 29 ++++++++++++
 deployments/docker/docker-compose.yaml | 17 ++++++--
 examples/dev/REAMDME.md                | 23 ++++++----
 examples/dev/conf/chassis.yaml         |  2 +-
 go.mod                                 |  2 +-
 scripts/start.sh                       | 58 ++++++++++++++++++++++++
 10 files changed, 251 insertions(+), 16 deletions(-)

diff --git a/.gitignore b/.gitignore
index fcf40a7..8d99bb8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,6 +14,7 @@ vendor/**
 !vendor/manifest
 
 **/conf/servicecomb-kie/
+release
 !etc/conf/
 etc/data/
 etc/ssl/
diff --git a/README.md b/README.md
index c427b6a..21b98ae 100644
--- a/README.md
+++ b/README.md
@@ -36,11 +36,12 @@ based on template language
 - frontend: web console for kie
 
 ## Features
-
-TODO
 - simple key name with rich labels: user can define labels for a key, 
 that distinguish from key to another key.  
-a key will not be stringed by fixed schema. 
+
+TODO
+
+- a key will not be stringed by fixed schema. 
 labels for a key is like "env=test, service=cart, version=1.0" or "cluster=xxx"  
 or "env=test, service=cart, version=1.0, ip=x.x.x.x"
 - validator: value can be checked by user defined python script, 
@@ -63,10 +64,32 @@ to a distributed system in separated views.
 - kv change history: all kv changes is recorded and can be easily roll back by UI
 ## Quick Start
 
+### Run locally with Docker compose
+
+```bash
+git clone git@github.com:apache/servicecomb-kie.git
+cd servicecomb-kie/deployments/docker
+sudo docker-compose up
+```
+it will launch 3 components 
+- mongodb: 127.0.0.1:27017
+- mongodb UI:http://127.0.0.1:8081
+- servicecomb-kie: http://127.0.0.1:30110
+
 
 ## Development
 To see how to build a local dev environment, check [here](examples/dev)
 
+### Build
+```bash
+cd build
+export VERSION=0.0.1
+./build_server.sh
+```
+
+this will generate a "servicecomb-kie-0.0.1-linux-amd64.tar" in "release" folder,
+and a docker image "servicecomb/kie:0.0.1"
+
 ## Contact
 
 Bugs: [issues](https://issues.apache.org/jira/browse/SCB)
diff --git a/build/build_server.sh b/build/build_server.sh
new file mode 100755
index 0000000..63693a7
--- /dev/null
+++ b/build/build_server.sh
@@ -0,0 +1,80 @@
+#!/usr/bin/env bash
+export BUILD_DIR=$(cd "$(dirname "$0")"; pwd)
+export PROJECT_DIR=$(dirname ${BUILD_DIR})
+echo "downloading dependencies"
+cd ${PROJECT_DIR}
+GO111MODULE=on go mod vendor
+version="latest"
+release_dir=${PROJECT_DIR}/release/kie
+
+if [ -z "${VERSION}" ]; then
+ echo "missing VERSION env, use ${version} as release version"
+else
+ version=${VERSION}
+fi
+
+
+
+if [ -d ${release_dir} ]; then
+    rm -rf ${release_dir}
+fi
+
+mkdir -p ${release_dir}/conf
+pkg_name="servicecomb-kie-$version-linux-amd64.tar.gz"
+
+export GIT_COMMIT=`git rev-parse HEAD | cut -b 1-7`
+echo "build from ${GIT_COMMIT}"
+
+
+echo "building..."
+go build -o ${release_dir}/kie github.com/apache/servicecomb-kie/cmd/kie
+
+
+writeConfig(){
+echo "write template config..."
+cat <<EOM > ${release_dir}/conf/chassis.yaml
+cse:
+  service:
+    registry:
+      disabled: true
+      address: http://127.0.0.1:30100
+  protocols:
+    rest:
+      listenAddress: 127.0.0.1:30108
+    rest-consul: #consul compatible API
+      listenAddress: 127.0.0.1:8500
+  handler:
+    chain:
+      Provider:
+        default: auth-handler,ratelimiter-provider
+EOM
+
+cat <<EOM > ${release_dir}/conf/microservice.yaml
+service_description:
+  name: servicecomb-kie
+  version: ${version}
+EOM
+
+cat <<EOM > ${release_dir}/conf/kie-conf.yaml
+db:
+  uri: mongodb://admin:123@127.0.0.1:27017/kie
+  type: mongodb
+  poolSize: 10
+  ssl: false
+  sslCA:
+  sslCert:
+EOM
+}
+
+writeConfig
+
+echo "packaging tar.gz..."
+cd ${release_dir}
+tar zcf ${pkg_name} conf kie
+
+
+
+echo "building docker..."
+cp ${PROJECT_DIR}/scripts/start.sh ./
+
+sudo docker build -t servicecomb/kie:${version} -f ${PROJECT_DIR}/build/docker/server/Dockerfile .
\ No newline at end of file
diff --git a/build/docker/server/Dockerfile b/build/docker/server/Dockerfile
new file mode 100644
index 0000000..2eb34d0
--- /dev/null
+++ b/build/docker/server/Dockerfile
@@ -0,0 +1,26 @@
+# 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.
+
+FROM ubuntu:19.04
+
+RUN apt-get update && apt-get install -y net-tools
+RUN mkdir -p /etc/servicecomb-kie/
+RUN mkdir -p /opt/servicecomb-kie/conf
+RUN export GO_CHASSIS=/opt/servicecomb-kie
+
+ADD ./kie /opt/servicecomb-kie/
+ADD ./start.sh /opt/servicecomb-kie/
+ADD ./conf/microservice.yaml /opt/servicecomb-kie/conf/
+ENTRYPOINT ["/opt/servicecomb-kie/start.sh"]
\ No newline at end of file
diff --git a/deployments/docker/db.js b/deployments/docker/db.js
new file mode 100644
index 0000000..2f1ff7a
--- /dev/null
+++ b/deployments/docker/db.js
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+db.createUser(
+    {
+        user: "kie",
+        pwd: "123",
+        roles:[
+            {
+                role: "readWrite",
+                db:   "kie"
+            }
+        ]
+    }
+);
\ No newline at end of file
diff --git a/deployments/docker/docker-compose.yaml b/deployments/docker/docker-compose.yaml
index 700fa28..4bcbca0 100644
--- a/deployments/docker/docker-compose.yaml
+++ b/deployments/docker/docker-compose.yaml
@@ -17,14 +17,16 @@
 version: '3.1'
 services:
   mongo:
-    image: mongo
+    image: mongo:3.4
     restart: always
     ports:
       - 27017:27017
     environment:
+      MONGO_INITDB_DATABASE: kie
       MONGO_INITDB_ROOT_USERNAME: kie
       MONGO_INITDB_ROOT_PASSWORD: 123
-
+    volumes:
+      - ./db.js:/docker-entrypoint-initdb.d/db.js:ro
   mongo-express:
     image: mongo-express
     restart: always
@@ -32,4 +34,13 @@ services:
       - 8081:8081
     environment:
       ME_CONFIG_MONGODB_ADMINUSERNAME: kie
-      ME_CONFIG_MONGODB_ADMINPASSWORD: 123
\ No newline at end of file
+      ME_CONFIG_MONGODB_ADMINPASSWORD: 123
+  servicecomb-kie:
+    image: servicecomb/kie:latest
+    restart: always
+    ports:
+      - 30110:30110
+    environment:
+      MONGODB_USER: kie
+      MONGODB_PWD: 123
+      MONGODB_ADDR: mongo
\ No newline at end of file
diff --git a/examples/dev/REAMDME.md b/examples/dev/REAMDME.md
index 5b770d1..9f85df0 100644
--- a/examples/dev/REAMDME.md
+++ b/examples/dev/REAMDME.md
@@ -1,10 +1,11 @@
 # Intro
-that is a simple example to run kie in you local machine
+this guide will show you how to develop servicecomb-kie in your local machine. 
 
-you only need to set up a mongodb and config credential 
-and related info in kie-conf.yaml
+servicecomb-kie only depend on mongodb, so you have 2 choices
+- setup a mongodb and give credential in kie-conf.yaml
+- setup a simple mongodb alone with admin UI by docker compose 
 
-you can setup a simple mongodb alone with admin UI by docker compose 
+in this guide, we will use mongodb launched by docker compose
 
 # Get started
 
@@ -20,8 +21,14 @@ sudo docker-compose up
 ./kie --config kie-conf.yaml
 ```
 
-3. check service API document
-```bash
-cd examples/dev/conf/servicecomb-kie/schema
-```
+# mongodb admin UI
+http://127.0.0.1:8081/
+
+#servicecomb-kie endpoint
+http://127.0.0.1:30110/
+
+# API document
+the API doc will be generated under 
+examples/dev/conf/servicecomb-kie/schema
+
 you can copy it to https://editor.swagger.io/ to see full API document
diff --git a/examples/dev/conf/chassis.yaml b/examples/dev/conf/chassis.yaml
index d3d4c4b..c98a93b 100755
--- a/examples/dev/conf/chassis.yaml
+++ b/examples/dev/conf/chassis.yaml
@@ -6,7 +6,7 @@ cse:
       address: http://127.0.0.1:30100
   protocols:
     rest:
-      listenAddress: 127.0.0.1:30108
+      listenAddress: 127.0.0.1:30110
     rest-consul: #consul compatible API
       listenAddress: 127.0.0.1:8500
   handler:
diff --git a/go.mod b/go.mod
index 368d3a8..2161b5c 100644
--- a/go.mod
+++ b/go.mod
@@ -2,7 +2,7 @@ module github.com/apache/servicecomb-kie
 
 require (
 	github.com/emicklei/go-restful v2.8.0+incompatible
-	github.com/go-chassis/go-archaius v0.14.0
+	github.com/go-chassis/go-archaius v0.16.0
 	github.com/go-chassis/go-chassis v1.4.0
 	github.com/go-chassis/paas-lager v1.0.2-0.20190328010332-cf506050ddb2
 	github.com/go-mesh/openlogging v1.0.1-0.20181205082104-3d418c478b2d
diff --git a/scripts/start.sh b/scripts/start.sh
new file mode 100755
index 0000000..35e62ea
--- /dev/null
+++ b/scripts/start.sh
@@ -0,0 +1,58 @@
+#!/bin/bash
+# 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.
+
+
+
+root_dir=/opt/servicecomb-kie
+net_name=$(ip -o -4 route show to default | awk '{print $5}')
+listen_addr=$(ifconfig ${net_name} | grep -E 'inet\W' | grep -o -E [0-9]+.[0-9]+.[0-9]+.[0-9]+ | head -n 1)
+
+
+writeConfig(){
+echo "write template config..."
+cat <<EOM > ${root_dir}/conf/chassis.yaml
+cse:
+  service:
+    registry:
+      disabled: true
+  protocols:
+    rest:
+      listenAddress: ${listen_addr}:30110
+    rest-consul: #consul compatible API
+      listenAddress: ${listen_addr}:8500
+  handler:
+    chain:
+      Provider:
+        default: auth-handler,ratelimiter-provider
+EOM
+
+cat <<EOM > /etc/servicecomb-kie/kie-conf.yaml
+db:
+  uri: mongodb://${MONGODB_USER}:${MONGODB_PWD}@${MONGODB_ADDR}/kie
+  type: mongodb
+  poolSize: 10
+  ssl: false
+  sslCA:
+  sslCert:
+EOM
+}
+
+
+echo "prepare config file...."
+writeConfig
+
+echo "start kie server"
+/opt/servicecomb-kie/kie --config /etc/servicecomb-kie/kie-conf.yaml
\ No newline at end of file


[servicecomb-kie] 18/29: SCB-1311 Merge pull request #8 from tianxiaoliang/master

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

asifdxtreme pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git

commit 1266142439a09731a8233f837769b6676ddf954d
Merge: 818dd48 8f4f5e7
Author: Willem Jiang <wi...@gmail.com>
AuthorDate: Thu Jun 6 19:24:42 2019 +0800

    SCB-1311 Merge pull request #8 from tianxiaoliang/master
    
    SCB-1311 fix bug, key is duplicated

 pkg/model/kv.go                       |  4 ++--
 pkg/model/mongodb_doc.go              |  4 ++++
 server/dao/kie_api.go                 | 19 +++++++++++--------
 pkg/model/kv.go => server/dao/tool.go | 12 ++++++++----
 4 files changed, 25 insertions(+), 14 deletions(-)


[servicecomb-kie] 02/29: add project introduction

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

asifdxtreme pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git

commit bfc05b37c9e710f2f3997b18b6203421899dcacd
Author: tian <xi...@gmail.com>
AuthorDate: Mon Apr 29 15:23:44 2019 +0800

    add project introduction
---
 README.md | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 58 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 91353db..244cf63 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,66 @@
 # Apache-ServiceComb-Kie
 
-Introduction of the project
+A service for key value management in distributed system.
+
+## Conceptions
+
+### Key
+key could indicate a configuration like "timeout",
+then the value could be "3s"
+or indicates a file name "app.properties", 
+then the value could be content of app.properties
+
+### labels
+Each key could has labels. labels indicates a unique key.
+A key "log_level" with labels "env=production" 
+may saves the value "INFO" for all application log level in production environment.
+A key "log_level" with labels "env=production, component=payment" 
+may saves the value "DEBUG" for payment service in production environment.
+
+it means all payment service print debug log, but for other service print info log.
+
+so you can control your application runtime behaviors 
+by setting different labels to a key.
+
+
+
+## Components
+it includes 5 components
+
+- server: rest api service to manage kv
+- client: restful client for go
+- kie-template: agent can be deployed in your k8s pod 
+or VM, it connects to server and writes kv into config file 
+based on template language
+- kiectl: CLI tool for kie
+- frontend: web console for kie
 
 ## Features
 
+TODO
+- simple key name with rich labels: user can define labels for a key, 
+that distinguish from key to another key.  
+a key will not be stringed by fixed schema. 
+labels for a key is like "env=test, service=cart, version=1.0" or "cluster=xxx"  
+or "env=test, service=cart, version=1.0, ip=x.x.x.x"
+- validator: value can be checked by user defined python script, 
+so in runtime if someone want to change this value, 
+the script will check if this value is appropriate.
+- encryption web hook: value can by encrypt 
+by your custom encryption service like vault.
+- Long polling: client can get key value changes by long polling
+- config view: by setting labels criteria, servicecomb-kie 
+is able to aggregate a view to return all key values which match those labels, 
+so that operator can mange key in their own understanding 
+to a distributed system in separated views.
+- rich value type: not only plain text, but support to be aware of ini, json,yaml,xml and java properties
+- heterogeneous config server: able to fetch configuration in k8s and consul 
+ even more, you can update, delete, 
+ and use config view for those systems, 
+ and you can integrate with your own config system to MetaConfig by 
+ following standardized API and model
+- consul compatible: partially compatible with consul kv management API
+- kv change history: all kv changes is recorded and can be easily roll back by UI
 ## Quick Start
 
 ## Contact


[servicecomb-kie] 22/29: SCB-1312 Updated the README.md

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

asifdxtreme pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git

commit 0226af9c7f055b3ba51de153feb2d4d206c1b1bc
Author: Willem Jiang <wi...@gmail.com>
AuthorDate: Wed Jun 12 08:48:20 2019 +0800

    SCB-1312 Updated the README.md
    
    Updated the README md for the travis build status.
---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 21b98ae..3bd18e5 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Apache-ServiceComb-Kie
+# Apache-ServiceComb-Kie [![Build Status](https://travis-ci.org/apache/servicecomb-pack.svg?branch=master)](https://travis-ci.org/apache/servicecomb-pack?branch=master) [![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)
 
 A service for configuration management in distributed system.
 


[servicecomb-kie] 26/29: support combination query

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

asifdxtreme pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git

commit 999a22414e4ff0340d883e28e149d83fcab60648
Author: tian <xi...@gmail.com>
AuthorDate: Wed Jun 19 18:35:34 2019 +0800

    support combination query
---
 go.mod                              |  3 +-
 pkg/common/common.go                |  3 +-
 server/dao/kie_api.go               |  7 +---
 server/dao/kv_test.go               |  8 ++--
 server/resource/v1/common.go        | 31 +++++++++++----
 server/resource/v1/common_test.go   | 31 +++++++++++++++
 server/resource/v1/doc_struct.go    | 14 ++++---
 server/resource/v1/kv_resource.go   | 77 ++++++++++++++-----------------------
 server/resource/v1/v1_suite_test.go | 13 +++++++
 9 files changed, 113 insertions(+), 74 deletions(-)

diff --git a/go.mod b/go.mod
index d5efedc..6646204 100644
--- a/go.mod
+++ b/go.mod
@@ -4,11 +4,12 @@ require (
 	github.com/emicklei/go-restful v2.8.0+incompatible
 	github.com/go-chassis/foundation v0.0.0-20190516083152-b8b2476b6db7
 	github.com/go-chassis/go-archaius v0.16.0
-	github.com/go-chassis/go-chassis v1.4.1
+	github.com/go-chassis/go-chassis v1.4.3
 	github.com/go-chassis/paas-lager v1.0.2-0.20190328010332-cf506050ddb2
 	github.com/go-mesh/openlogging v1.0.1-0.20181205082104-3d418c478b2d
 	github.com/onsi/ginkgo v1.8.0
 	github.com/onsi/gomega v1.5.0
+	github.com/pkg/errors v0.8.0
 	github.com/stretchr/testify v1.2.2
 	github.com/urfave/cli v1.20.0
 	github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c // indirect
diff --git a/pkg/common/common.go b/pkg/common/common.go
index e39dca6..f111bce 100644
--- a/pkg/common/common.go
+++ b/pkg/common/common.go
@@ -19,8 +19,7 @@ package common
 
 //match mode
 const (
-	MatchGreedy = "greedy"
-	MatchExact  = "exact"
+	QueryParamQ = "q"
 )
 
 //http headers
diff --git a/server/dao/kie_api.go b/server/dao/kie_api.go
index a5cca3d..0e0020d 100644
--- a/server/dao/kie_api.go
+++ b/server/dao/kie_api.go
@@ -191,7 +191,7 @@ func (s *MongodbService) FindKVByLabelID(ctx context.Context, domain, labelID, k
 
 //FindKV get kvs by key, labels
 //because labels has a a lot of combination,
-//you can use WithExactLabels to return only one kv which's labels exactly match the criteria
+//you can use WithDepth(0) to return only one kv which's labels exactly match the criteria
 func (s *MongodbService) FindKV(ctx context.Context, domain string, options ...FindOption) ([]*model.KVResponse, error) {
 	opts := FindOptions{}
 	for _, o := range options {
@@ -208,7 +208,7 @@ func (s *MongodbService) FindKV(ctx context.Context, domain string, options ...F
 	defer cur.Close(ctx)
 
 	kvResp := make([]*model.KVResponse, 0)
-	if opts.ExactLabels {
+	if opts.Depth == 0 {
 		openlogging.Debug("find one key", openlogging.WithTags(
 			map[string]interface{}{
 				"key":    opts.Key,
@@ -218,9 +218,6 @@ func (s *MongodbService) FindKV(ctx context.Context, domain string, options ...F
 		))
 		return cursorToOneKV(ctx, cur, opts.Labels)
 	}
-	if opts.Depth == 0 {
-		opts.Depth = 1
-	}
 	for cur.Next(ctx) {
 		curKV := &model.KVDoc{}
 
diff --git a/server/dao/kv_test.go b/server/dao/kv_test.go
index efbe6d4..db92857 100644
--- a/server/dao/kv_test.go
+++ b/server/dao/kv_test.go
@@ -132,8 +132,8 @@ var _ = Describe("Kv mongodb service", func() {
 			It("should not return err", func() {
 				Expect(err).Should(BeNil())
 			})
-			It("should has 2 records", func() {
-				Expect(len(kvs)).Should(Equal(2))
+			It("should has 1 records", func() {
+				Expect(len(kvs)).Should(Equal(1))
 			})
 
 		})
@@ -189,8 +189,8 @@ var _ = Describe("Kv mongodb service", func() {
 			It("should not return err", func() {
 				Expect(err).Should(BeNil())
 			})
-			It("should has 2 records", func() {
-				Expect(len(kvs)).Should(Equal(2))
+			It("should has 1 records", func() {
+				Expect(len(kvs)).Should(Equal(1))
 			})
 
 		})
diff --git a/server/resource/v1/common.go b/server/resource/v1/common.go
index 48baa22..dcf9901 100644
--- a/server/resource/v1/common.go
+++ b/server/resource/v1/common.go
@@ -22,15 +22,17 @@ import (
 	"fmt"
 	"github.com/apache/servicecomb-kie/pkg/common"
 	"github.com/apache/servicecomb-kie/pkg/model"
+	goRestful "github.com/emicklei/go-restful"
 	"github.com/go-chassis/go-chassis/server/restful"
 	"github.com/go-mesh/openlogging"
+	"github.com/pkg/errors"
 	"strconv"
+	"strings"
 )
 
 //const of server
 const (
 	MsgDomainMustNotBeEmpty = "domain must not be empty"
-	MsgIllegalFindPolicy    = "value of header " + common.HeaderMatch + " can be greedy or exact"
 	MsgIllegalLabels        = "label's value can not be empty, " +
 		"label can not be duplicated, please check your query parameters"
 	MsgIllegalDepth   = "X-Depth must be number"
@@ -55,14 +57,27 @@ func ReadFindDepth(context *restful.Context) (int, error) {
 	return depth, nil
 }
 
-//ReadMatchPolicy get match policy
-func ReadMatchPolicy(context *restful.Context) string {
-	policy := context.ReadRestfulRequest().HeaderParameter(common.HeaderMatch)
-	if policy == "" {
-		//default is exact to reduce network traffic
-		return common.MatchExact
+//ReadLabelCombinations get query combination from url
+//q=app:default+service:payment&q=app:default
+func ReadLabelCombinations(req *goRestful.Request) ([]map[string]string, error) {
+	queryCombinations := req.QueryParameters(common.QueryParamQ)
+	labelCombinations := make([]map[string]string, 0)
+	for _, queryStr := range queryCombinations {
+		labelStr := strings.Split(queryStr, " ")
+		labels := make(map[string]string, len(labelStr))
+		for _, label := range labelStr {
+			l := strings.Split(label, ":")
+			if len(l) != 2 {
+				return nil, errors.New("wrong query syntax:" + label)
+			}
+			labels[l[0]] = l[1]
+		}
+		if len(labels) == 0 {
+			continue
+		}
+		labelCombinations = append(labelCombinations, labels)
 	}
-	return policy
+	return labelCombinations, nil
 }
 
 //WriteErrResponse write error message to client
diff --git a/server/resource/v1/common_test.go b/server/resource/v1/common_test.go
new file mode 100644
index 0000000..6f3b139
--- /dev/null
+++ b/server/resource/v1/common_test.go
@@ -0,0 +1,31 @@
+package v1_test
+
+import (
+	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/gomega"
+
+	. "github.com/apache/servicecomb-kie/server/resource/v1"
+	"github.com/emicklei/go-restful"
+	"net/http"
+)
+
+var _ = Describe("Common", func() {
+	Describe("set query combination", func() {
+		Context("valid param", func() {
+			r, err := http.NewRequest("GET",
+				"/kv?q=app:mall+service:payment&q=app:mall+service:payment+version:1.0.0",
+				nil)
+			It("should not return err ", func() {
+				Expect(err).Should(BeNil())
+			})
+			c, err := ReadLabelCombinations(restful.NewRequest(r))
+			It("should not return err ", func() {
+				Expect(err).Should(BeNil())
+			})
+			It("should has 2 combinations", func() {
+				Expect(len(c)).Should(Equal(2))
+			})
+
+		})
+	})
+})
diff --git a/server/resource/v1/doc_struct.go b/server/resource/v1/doc_struct.go
index 37f7432..33f0eb7 100644
--- a/server/resource/v1/doc_struct.go
+++ b/server/resource/v1/doc_struct.go
@@ -31,17 +31,19 @@ var (
 		ParamType: goRestful.HeaderParameterKind,
 		Desc:      "integer, default is 1, if you set match policy, you can set,depth to decide label number",
 	}
+	DocQueryCombination = &restful.Parameters{
+		DataType:  "string",
+		Name:      common.QueryParamQ,
+		ParamType: goRestful.QueryParameterKind,
+		Desc: "the combination format is {label_key}:{label_value}+{label_key}:{label_value} " +
+			"for example: /v1/kv?q=app:mall&q=app:mall+service:cart " +
+			"that will query key values from 2 kinds of labels",
+	}
 	DocPathKey = &restful.Parameters{
 		DataType:  "string",
 		Name:      "key",
 		ParamType: goRestful.PathParameterKind,
 	}
-	DocHeaderMath = &restful.Parameters{
-		DataType:  "string",
-		Name:      common.HeaderMatch,
-		ParamType: goRestful.HeaderParameterKind,
-		Desc:      "greedy or exact",
-	}
 )
 
 //KVBody is open api doc
diff --git a/server/resource/v1/kv_resource.go b/server/resource/v1/kv_resource.go
index a1f94b6..c072dc6 100644
--- a/server/resource/v1/kv_resource.go
+++ b/server/resource/v1/kv_resource.go
@@ -21,7 +21,6 @@ package v1
 import (
 	"encoding/json"
 	"fmt"
-	"github.com/apache/servicecomb-kie/pkg/common"
 	"github.com/apache/servicecomb-kie/pkg/model"
 	"github.com/apache/servicecomb-kie/server/dao"
 	goRestful "github.com/emicklei/go-restful"
@@ -67,8 +66,8 @@ func (r *KVResource) Put(context *restful.Context) {
 
 }
 
-//FindWithKey search key by label and key
-func (r *KVResource) FindWithKey(context *restful.Context) {
+//GetByKey search key by label and key
+func (r *KVResource) GetByKey(context *restful.Context) {
 	var err error
 	key := context.ReadPathParameter("key")
 	if key == "" {
@@ -94,23 +93,12 @@ func (r *KVResource) FindWithKey(context *restful.Context) {
 		WriteErrResponse(context, http.StatusInternalServerError, MsgDomainMustNotBeEmpty)
 		return
 	}
-	policy := ReadMatchPolicy(context)
 	d, err := ReadFindDepth(context)
 	if err != nil {
 		WriteErrResponse(context, http.StatusBadRequest, MsgIllegalDepth)
 		return
 	}
-	var kvs []*model.KVResponse
-	switch policy {
-	case common.MatchGreedy:
-		kvs, err = s.FindKV(context.Ctx, domain.(string), dao.WithKey(key), dao.WithLabels(labels), dao.WithDepth(d))
-	case common.MatchExact:
-		kvs, err = s.FindKV(context.Ctx, domain.(string), dao.WithKey(key), dao.WithLabels(labels),
-			dao.WithExactLabels())
-	default:
-		WriteErrResponse(context, http.StatusBadRequest, MsgIllegalFindPolicy)
-		return
-	}
+	kvs, err := s.FindKV(context.Ctx, domain.(string), dao.WithKey(key), dao.WithLabels(labels), dao.WithDepth(d))
 	if err == dao.ErrKeyNotExists {
 		WriteErrResponse(context, http.StatusNotFound, err.Error())
 		return
@@ -126,17 +114,13 @@ func (r *KVResource) FindWithKey(context *restful.Context) {
 
 }
 
-//FindByLabels search key only by label
-func (r *KVResource) FindByLabels(context *restful.Context) {
+//SearchByLabels search key only by label
+func (r *KVResource) SearchByLabels(context *restful.Context) {
 	var err error
-	values := context.ReadRequest().URL.Query()
-	labels := make(map[string]string, len(values))
-	for k, v := range values {
-		if len(v) != 1 {
-			WriteErrResponse(context, http.StatusBadRequest, MsgIllegalLabels)
-			return
-		}
-		labels[k] = v[0]
+	labelCombinations, err := ReadLabelCombinations(context.ReadRestfulRequest())
+	if err != nil {
+		WriteErrResponse(context, http.StatusBadRequest, err.Error())
+		return
 	}
 	s, err := dao.NewKVService()
 	if err != nil {
@@ -148,27 +132,24 @@ func (r *KVResource) FindByLabels(context *restful.Context) {
 		WriteErrResponse(context, http.StatusInternalServerError, MsgDomainMustNotBeEmpty)
 		return
 	}
-	policy := ReadMatchPolicy(context)
-	d, err := ReadFindDepth(context)
-	if err != nil {
-		WriteErrResponse(context, http.StatusBadRequest, MsgIllegalDepth)
-		return
-	}
 	var kvs []*model.KVResponse
-	switch policy {
-	case common.MatchGreedy:
-		kvs, err = s.FindKV(context.Ctx, domain.(string), dao.WithLabels(labels), dao.WithDepth(d))
-	case common.MatchExact:
-		kvs, err = s.FindKV(context.Ctx, domain.(string), dao.WithLabels(labels),
-			dao.WithExactLabels())
-	default:
-		WriteErrResponse(context, http.StatusBadRequest, MsgIllegalFindPolicy)
-		return
+	for _, labels := range labelCombinations {
+		result, err := s.FindKV(context.Ctx, domain.(string), dao.WithLabels(labels))
+		if err != nil {
+			if err == dao.ErrKeyNotExists {
+				continue
+			}
+			WriteErrResponse(context, http.StatusInternalServerError, err.Error())
+			return
+		}
+		kvs = append(kvs, result...)
+
 	}
-	if err == dao.ErrKeyNotExists {
+	if len(kvs) == 0 {
 		WriteErrResponse(context, http.StatusNotFound, err.Error())
 		return
 	}
+
 	err = context.WriteHeaderAndJSON(http.StatusOK, kvs, goRestful.MIME_JSON)
 	if err != nil {
 		openlogging.Error(err.Error())
@@ -215,7 +196,7 @@ func (r *KVResource) URLPatterns() []restful.Route {
 					DataType:  "string",
 					Name:      "X-Realm",
 					ParamType: goRestful.HeaderParameterKind,
-					Desc:      "set kv to heterogeneous config server",
+					Desc:      "set kv to heterogeneous config server, not implement yet",
 				},
 			},
 			Returns: []*restful.Returns{
@@ -230,7 +211,7 @@ func (r *KVResource) URLPatterns() []restful.Route {
 		}, {
 			Method:           http.MethodGet,
 			Path:             "/v1/kv/{key}",
-			ResourceFuncName: "FindWithKey",
+			ResourceFuncName: "GetByKey",
 			FuncDesc:         "get key values by key and labels",
 			Parameters: []*restful.Parameters{
 				DocPathKey, DocHeaderMath, DocHeaderDepth,
@@ -239,7 +220,7 @@ func (r *KVResource) URLPatterns() []restful.Route {
 				{
 					Code:    http.StatusOK,
 					Message: "get key value success",
-					Model:   []*KVBody{},
+					Model:   []*model.KVResponse{},
 				},
 			},
 			Consumes: []string{goRestful.MIME_JSON},
@@ -248,16 +229,16 @@ func (r *KVResource) URLPatterns() []restful.Route {
 		}, {
 			Method:           http.MethodGet,
 			Path:             "/v1/kv",
-			ResourceFuncName: "FindByLabels",
-			FuncDesc:         "find key values only by labels",
+			ResourceFuncName: "SearchByLabels",
+			FuncDesc:         "search key values by labels combination",
 			Parameters: []*restful.Parameters{
-				DocHeaderMath, DocHeaderDepth,
+				DocHeaderMath, DocQueryCombination,
 			},
 			Returns: []*restful.Returns{
 				{
 					Code:    http.StatusOK,
 					Message: "get key value success",
-					Model:   []*KVBody{},
+					Model:   []*model.KVResponse{},
 				},
 			},
 			Consumes: []string{goRestful.MIME_JSON},
diff --git a/server/resource/v1/v1_suite_test.go b/server/resource/v1/v1_suite_test.go
new file mode 100644
index 0000000..23b7482
--- /dev/null
+++ b/server/resource/v1/v1_suite_test.go
@@ -0,0 +1,13 @@
+package v1_test
+
+import (
+	"testing"
+
+	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/gomega"
+)
+
+func TestV1(t *testing.T) {
+	RegisterFailHandler(Fail)
+	RunSpecs(t, "V1 Suite")
+}


[servicecomb-kie] 07/29: add rest api for put and find, (#3)

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

asifdxtreme pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git

commit 78341650e6617d4fd97df6feec86c0918f21772b
Author: Shawn <xi...@gmail.com>
AuthorDate: Mon May 13 10:00:45 2019 +0800

    add rest api for put and find, (#3)
    
    add example for local dev
---
 .gitignore                                         |   4 +-
 README.md                                          |   6 +-
 cmd/kie/cmd.go                                     |  63 ++++++
 server/kv/model_suite_test.go => cmd/kie/main.go   |  43 ++--
 examples/dev/REAMDME.md                            |  27 +++
 examples/dev/conf/chassis.yaml                     |  24 ++
 examples/dev/conf/microservice.yaml                |   4 +
 examples/dev/docker-compose.yaml                   |  35 +++
 examples/dev/kie-conf.yaml                         |   7 +
 go.mod                                             |   5 +-
 server/{kv => dao}/errors.go                       |   2 +-
 server/{kv => dao}/kv.go                           |   9 +-
 server/{kv => dao}/kv_test.go                      |  30 +--
 server/{kv => dao}/model_suite_test.go             |   2 +-
 server/{kv => dao}/mongodb.go                      |   8 +-
 server/{kv => dao}/options.go                      |  18 +-
 .../noop_auth_handler.go}                          |  39 ++--
 server/resource/v1/common.go                       |  60 +++++
 server/{kv/errors.go => resource/v1/doc_struct.go} |  23 +-
 server/resource/v1/kv_resource.go                  | 249 +++++++++++++++++++++
 20 files changed, 563 insertions(+), 95 deletions(-)

diff --git a/.gitignore b/.gitignore
index 901a1e4..fcf40a7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,12 +10,10 @@ output
 **/*junit.xml
 **/*.exe
 **/*.tgz
-
 vendor/**
 !vendor/manifest
 
-# for local UT
-**/conf/
+**/conf/servicecomb-kie/
 !etc/conf/
 etc/data/
 etc/ssl/
diff --git a/README.md b/README.md
index 244cf63..c427b6a 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 # Apache-ServiceComb-Kie
 
-A service for key value management in distributed system.
+A service for configuration management in distributed system.
 
 ## Conceptions
 
@@ -63,6 +63,10 @@ to a distributed system in separated views.
 - kv change history: all kv changes is recorded and can be easily roll back by UI
 ## Quick Start
 
+
+## Development
+To see how to build a local dev environment, check [here](examples/dev)
+
 ## Contact
 
 Bugs: [issues](https://issues.apache.org/jira/browse/SCB)
diff --git a/cmd/kie/cmd.go b/cmd/kie/cmd.go
new file mode 100644
index 0000000..45ffb60
--- /dev/null
+++ b/cmd/kie/cmd.go
@@ -0,0 +1,63 @@
+/*
+ * 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 main
+
+import (
+	"os"
+
+	"github.com/urfave/cli"
+)
+
+const (
+	defaultConfigFile = "/etc/servicecomb-kie/kie-conf.yaml"
+)
+
+//ConfigFromCmd store cmd params
+type ConfigFromCmd struct {
+	ConfigFile string
+}
+
+//Configs is a pointer of struct ConfigFromCmd
+var Configs *ConfigFromCmd
+
+// parseConfigFromCmd
+func parseConfigFromCmd(args []string) (err error) {
+	app := cli.NewApp()
+	app.HideVersion = true
+	app.Usage = "servicecomb-kie server cmd line."
+	app.Flags = []cli.Flag{
+		cli.StringFlag{
+			Name:        "config",
+			Usage:       "config file, example: --config=kie-conf.yaml",
+			Destination: &Configs.ConfigFile,
+			Value:       defaultConfigFile,
+		},
+	}
+	app.Action = func(c *cli.Context) error {
+		return nil
+	}
+
+	err = app.Run(args)
+	return
+}
+
+//Init get config and parses those command
+func Init() error {
+	Configs = &ConfigFromCmd{}
+	return parseConfigFromCmd(os.Args)
+}
diff --git a/server/kv/model_suite_test.go b/cmd/kie/main.go
similarity index 56%
copy from server/kv/model_suite_test.go
copy to cmd/kie/main.go
index 965802e..a70ab9e 100644
--- a/server/kv/model_suite_test.go
+++ b/cmd/kie/main.go
@@ -15,30 +15,33 @@
  * limitations under the License.
  */
 
-package kv_test
+package main
 
 import (
-	"testing"
+	_ "github.com/apache/servicecomb-kie/server/handler"
 
-	"github.com/go-chassis/paas-lager"
+	"github.com/apache/servicecomb-kie/server/config"
+	"github.com/apache/servicecomb-kie/server/resource/v1"
+	"github.com/go-chassis/go-chassis"
 	"github.com/go-mesh/openlogging"
-	. "github.com/onsi/ginkgo"
-	"github.com/onsi/ginkgo/reporters"
-	. "github.com/onsi/gomega"
+	"os"
 )
 
-func TestModel(t *testing.T) {
-	RegisterFailHandler(Fail)
-	junitReporter := reporters.NewJUnitReporter("junit.xml")
-	RunSpecsWithDefaultAndCustomReporters(t, "Model Suite", []Reporter{junitReporter})
+func main() {
+	if err := Init(); err != nil {
+		openlogging.Fatal(err.Error())
+	}
+	chassis.RegisterSchema("rest", &v1.KVResource{})
+	if err := chassis.Init(); err != nil {
+		openlogging.Error(err.Error())
+		os.Exit(1)
+	}
+	if err := config.Init(Configs.ConfigFile); err != nil {
+		openlogging.Error(err.Error())
+		os.Exit(1)
+	}
+	if err := chassis.Run(); err != nil {
+		openlogging.Error("service exit: " + err.Error())
+		os.Exit(1)
+	}
 }
-
-var _ = BeforeSuite(func() {
-	log.Init(log.Config{
-		Writers:     []string{"stdout"},
-		LoggerLevel: "DEBUG",
-	})
-
-	logger := log.NewLogger("ut")
-	openlogging.SetLogger(logger)
-})
diff --git a/examples/dev/REAMDME.md b/examples/dev/REAMDME.md
new file mode 100644
index 0000000..5b770d1
--- /dev/null
+++ b/examples/dev/REAMDME.md
@@ -0,0 +1,27 @@
+# Intro
+that is a simple example to run kie in you local machine
+
+you only need to set up a mongodb and config credential 
+and related info in kie-conf.yaml
+
+you can setup a simple mongodb alone with admin UI by docker compose 
+
+# Get started
+
+1.Build 
+```bash
+cd examples/dev
+go build github.com/apache/servicecomb-kie/cmd/kie
+```
+
+2.Run mongodb and servicecomb-kie
+```bash
+sudo docker-compose up
+./kie --config kie-conf.yaml
+```
+
+3. check service API document
+```bash
+cd examples/dev/conf/servicecomb-kie/schema
+```
+you can copy it to https://editor.swagger.io/ to see full API document
diff --git a/examples/dev/conf/chassis.yaml b/examples/dev/conf/chassis.yaml
new file mode 100755
index 0000000..d3d4c4b
--- /dev/null
+++ b/examples/dev/conf/chassis.yaml
@@ -0,0 +1,24 @@
+---
+cse:
+  service:
+    registry:
+      disabled: true
+      address: http://127.0.0.1:30100
+  protocols:
+    rest:
+      listenAddress: 127.0.0.1:30108
+    rest-consul: #consul compatible API
+      listenAddress: 127.0.0.1:8500
+  handler:
+    chain:
+      Provider:
+        default: auth-handler,ratelimiter-provider
+# ssl:
+#   Provider.cipherPlugin: default
+#   Provider.verifyPeer: false
+#   Provider.cipherSuits: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
+#   Provider.protocol: TLSv1.2
+#   Provider.caFile:
+#   Provider.certFile:
+#   Provider.keyFile:
+#   Provider.certPwdFile:
diff --git a/examples/dev/conf/microservice.yaml b/examples/dev/conf/microservice.yaml
new file mode 100755
index 0000000..38aad04
--- /dev/null
+++ b/examples/dev/conf/microservice.yaml
@@ -0,0 +1,4 @@
+---
+service_description:
+  name: servicecomb-kie
+  version: 0.0.1
diff --git a/examples/dev/docker-compose.yaml b/examples/dev/docker-compose.yaml
new file mode 100644
index 0000000..700fa28
--- /dev/null
+++ b/examples/dev/docker-compose.yaml
@@ -0,0 +1,35 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+version: '3.1'
+services:
+  mongo:
+    image: mongo
+    restart: always
+    ports:
+      - 27017:27017
+    environment:
+      MONGO_INITDB_ROOT_USERNAME: kie
+      MONGO_INITDB_ROOT_PASSWORD: 123
+
+  mongo-express:
+    image: mongo-express
+    restart: always
+    ports:
+      - 8081:8081
+    environment:
+      ME_CONFIG_MONGODB_ADMINUSERNAME: kie
+      ME_CONFIG_MONGODB_ADMINPASSWORD: 123
\ No newline at end of file
diff --git a/examples/dev/kie-conf.yaml b/examples/dev/kie-conf.yaml
new file mode 100644
index 0000000..5de5ee0
--- /dev/null
+++ b/examples/dev/kie-conf.yaml
@@ -0,0 +1,7 @@
+db:
+  uri: mongodb://admin:123@127.0.0.1:27017/kie
+  type: mongodb
+  poolSize: 10
+  ssl: false
+  sslCA:
+  sslCert:
\ No newline at end of file
diff --git a/go.mod b/go.mod
index da3d3eb..368d3a8 100644
--- a/go.mod
+++ b/go.mod
@@ -1,14 +1,15 @@
 module github.com/apache/servicecomb-kie
 
 require (
+	github.com/emicklei/go-restful v2.8.0+incompatible
 	github.com/go-chassis/go-archaius v0.14.0
-	github.com/go-chassis/go-chassis v1.4.0 // indirect
+	github.com/go-chassis/go-chassis v1.4.0
 	github.com/go-chassis/paas-lager v1.0.2-0.20190328010332-cf506050ddb2
 	github.com/go-mesh/openlogging v1.0.1-0.20181205082104-3d418c478b2d
 	github.com/onsi/ginkgo v1.8.0
 	github.com/onsi/gomega v1.5.0
 	github.com/stretchr/testify v1.2.2
-	github.com/urfave/cli v1.20.0 // indirect
+	github.com/urfave/cli v1.20.0
 	github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c // indirect
 	github.com/xdg/stringprep v1.0.0 // indirect
 	go.mongodb.org/mongo-driver v1.0.0
diff --git a/server/kv/errors.go b/server/dao/errors.go
similarity index 99%
copy from server/kv/errors.go
copy to server/dao/errors.go
index 958a015..31074f8 100644
--- a/server/kv/errors.go
+++ b/server/dao/errors.go
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package kv
+package dao
 
 import (
 	"errors"
diff --git a/server/kv/kv.go b/server/dao/kv.go
similarity index 91%
rename from server/kv/kv.go
rename to server/dao/kv.go
index 9513e60..de32cc3 100644
--- a/server/kv/kv.go
+++ b/server/dao/kv.go
@@ -15,7 +15,8 @@
  * limitations under the License.
  */
 
-package kv
+//package dao is a persis layer of kie
+package dao
 
 import (
 	"crypto/tls"
@@ -30,13 +31,13 @@ var ErrNotExists = errors.New("key with labels does not exits")
 var ErrTooMany = errors.New("key with labels should be only one")
 var ErrKeyMustNotEmpty = errors.New("must supply key if you want to get exact one result")
 
-type Service interface {
+type KV interface {
 	CreateOrUpdate(kv *model.KV) (*model.KV, error)
 	//do not use primitive.ObjectID as return to decouple with mongodb, we can afford perf lost
 	Exist(key, domain string, labels model.Labels) (string, error)
 	DeleteByID(id string) error
 	Delete(key, domain string, labels model.Labels) error
-	Find(domain string, options ...CallOption) ([]*model.KV, error)
+	Find(domain string, options ...FindOption) ([]*model.KV, error)
 	AddHistory(kv *model.KV) error
 	//RollBack(kv *KV, version string) error
 }
@@ -49,7 +50,7 @@ type Options struct {
 	Timeout  time.Duration
 }
 
-func NewKVService() (Service, error) {
+func NewKVService() (KV, error) {
 	opts := Options{
 		URI:      config.GetDB().URI,
 		PoolSize: config.GetDB().PoolSize,
diff --git a/server/kv/kv_test.go b/server/dao/kv_test.go
similarity index 86%
rename from server/kv/kv_test.go
rename to server/dao/kv_test.go
index 4bdd043..9cb23ad 100644
--- a/server/kv/kv_test.go
+++ b/server/dao/kv_test.go
@@ -15,21 +15,21 @@
  * limitations under the License.
  */
 
-package kv_test
+package dao_test
 
 import (
+	"github.com/apache/servicecomb-kie/pkg/model"
 	. "github.com/apache/servicecomb-kie/pkg/model"
+	"github.com/apache/servicecomb-kie/server/dao"
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
-	"github.com/apache/servicecomb-kie/pkg/model"
-	"github.com/apache/servicecomb-kie/server/kv"
 )
 
 var _ = Describe("Kv mongodb service", func() {
-	var s kv.Service
+	var s dao.KV
 	var err error
 	Describe("connecting db", func() {
-		s, err = kv.NewMongoService(kv.Options{
+		s, err = dao.NewMongoService(dao.Options{
 			URI: "mongodb://kie:123@127.0.0.1:27017",
 		})
 		It("should not return err", func() {
@@ -100,9 +100,9 @@ var _ = Describe("Kv mongodb service", func() {
 			It("should not return err", func() {
 				Expect(err).Should(BeNil())
 			})
-			kvs1, err := s.Find("default", kv.WithKey("timeout"), kv.WithLabels(map[string]string{
+			kvs1, err := s.Find("default", dao.WithKey("timeout"), dao.WithLabels(map[string]string{
 				"app": "mall",
-			}), kv.WithExactLabels())
+			}), dao.WithExactLabels())
 			It("should be 1s", func() {
 				Expect(kvs1[0].Value).Should(Equal(beforeKV.Value))
 			})
@@ -123,9 +123,9 @@ var _ = Describe("Kv mongodb service", func() {
 			It("should exists", func() {
 				Expect(oid).Should(Equal(beforeKV.ID.Hex()))
 			})
-			kvs, err := s.Find("default", kv.WithKey("timeout"), kv.WithLabels(map[string]string{
+			kvs, err := s.Find("default", dao.WithKey("timeout"), dao.WithLabels(map[string]string{
 				"app": "mall",
-			}), kv.WithExactLabels())
+			}), dao.WithExactLabels())
 			It("should be 3s", func() {
 				Expect(kvs[0].Value).Should(Equal(afterKV.Value))
 			})
@@ -134,7 +134,7 @@ var _ = Describe("Kv mongodb service", func() {
 
 	Describe("greedy find by kv and labels", func() {
 		Context("with labels app ", func() {
-			kvs, err := s.Find("default", kv.WithKey("timeout"), kv.WithLabels(map[string]string{
+			kvs, err := s.Find("default", dao.WithKey("timeout"), dao.WithLabels(map[string]string{
 				"app": "mall",
 			}))
 			It("should not return err", func() {
@@ -148,9 +148,9 @@ var _ = Describe("Kv mongodb service", func() {
 	})
 	Describe("exact find by kv and labels", func() {
 		Context("with labels app ", func() {
-			kvs, err := s.Find("default", kv.WithKey("timeout"), kv.WithLabels(map[string]string{
+			kvs, err := s.Find("default", dao.WithKey("timeout"), dao.WithLabels(map[string]string{
 				"app": "mall",
-			}), kv.WithExactLabels())
+			}), dao.WithExactLabels())
 			It("should not return err", func() {
 				Expect(err).Should(BeNil())
 			})
@@ -162,9 +162,9 @@ var _ = Describe("Kv mongodb service", func() {
 	})
 	Describe("exact find by labels", func() {
 		Context("with labels app ", func() {
-			kvs, err := s.Find("default", kv.WithLabels(map[string]string{
+			kvs, err := s.Find("default", dao.WithLabels(map[string]string{
 				"app": "mall",
-			}), kv.WithExactLabels())
+			}), dao.WithExactLabels())
 			It("should not return err", func() {
 				Expect(err).Should(BeNil())
 			})
@@ -176,7 +176,7 @@ var _ = Describe("Kv mongodb service", func() {
 	})
 	Describe("greedy find by labels", func() {
 		Context("with labels app ans service ", func() {
-			kvs, err := s.Find("default", kv.WithLabels(map[string]string{
+			kvs, err := s.Find("default", dao.WithLabels(map[string]string{
 				"app":     "mall",
 				"service": "cart",
 			}))
diff --git a/server/kv/model_suite_test.go b/server/dao/model_suite_test.go
similarity index 98%
copy from server/kv/model_suite_test.go
copy to server/dao/model_suite_test.go
index 965802e..a57389e 100644
--- a/server/kv/model_suite_test.go
+++ b/server/dao/model_suite_test.go
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package kv_test
+package dao_test
 
 import (
 	"testing"
diff --git a/server/kv/mongodb.go b/server/dao/mongodb.go
similarity index 98%
rename from server/kv/mongodb.go
rename to server/dao/mongodb.go
index 37664ae..cbaabad 100644
--- a/server/kv/mongodb.go
+++ b/server/dao/mongodb.go
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package kv
+package dao
 
 import (
 	"context"
@@ -141,8 +141,8 @@ func (s *MongodbService) Exist(key, domain string, labels model.Labels) (string,
 //Find get kvs by key, labels
 //because labels has a a lot of combination,
 //you can use WithExactLabels to return only one kv which's labels exactly match the criteria
-func (s *MongodbService) Find(domain string, options ...CallOption) ([]*model.KV, error) {
-	opts := CallOptions{}
+func (s *MongodbService) Find(domain string, options ...FindOption) ([]*model.KV, error) {
+	opts := FindOptions{}
 	for _, o := range options {
 		o(&opts)
 	}
@@ -271,7 +271,7 @@ func (s *MongodbService) getLatest(id primitive.ObjectID) (*model.KVHistory, err
 	}
 	return h, nil
 }
-func NewMongoService(opts Options) (Service, error) {
+func NewMongoService(opts Options) (KV, error) {
 	if opts.Timeout == 0 {
 		opts.Timeout = DefaultTimeout
 	}
diff --git a/server/kv/options.go b/server/dao/options.go
similarity index 79%
rename from server/kv/options.go
rename to server/dao/options.go
index aabe1ec..2116b67 100644
--- a/server/kv/options.go
+++ b/server/dao/options.go
@@ -15,35 +15,35 @@
  * limitations under the License.
  */
 
-package kv
+package dao
 
 import "github.com/apache/servicecomb-kie/pkg/model"
 
-type CallOptions struct {
+type FindOptions struct {
 	ExactLabels bool
 	Key         string
 	Labels      model.Labels
 }
 
-type CallOption func(*CallOptions)
+type FindOption func(*FindOptions)
 
 //WithExactLabels tell model service to return only one kv matches the labels
-func WithExactLabels() CallOption {
-	return func(o *CallOptions) {
+func WithExactLabels() FindOption {
+	return func(o *FindOptions) {
 		o.ExactLabels = true
 	}
 }
 
 //WithKey find by key
-func WithKey(key string) CallOption {
-	return func(o *CallOptions) {
+func WithKey(key string) FindOption {
+	return func(o *FindOptions) {
 		o.Key = key
 	}
 }
 
 //WithLabels find kv by labels
-func WithLabels(labels model.Labels) CallOption {
-	return func(o *CallOptions) {
+func WithLabels(labels model.Labels) FindOption {
+	return func(o *FindOptions) {
 		o.Labels = labels
 	}
 }
diff --git a/server/kv/model_suite_test.go b/server/handler/noop_auth_handler.go
similarity index 54%
rename from server/kv/model_suite_test.go
rename to server/handler/noop_auth_handler.go
index 965802e..b2c4a20 100644
--- a/server/kv/model_suite_test.go
+++ b/server/handler/noop_auth_handler.go
@@ -15,30 +15,29 @@
  * limitations under the License.
  */
 
-package kv_test
+package handler
 
 import (
-	"testing"
-
-	"github.com/go-chassis/paas-lager"
-	"github.com/go-mesh/openlogging"
-	. "github.com/onsi/ginkgo"
-	"github.com/onsi/ginkgo/reporters"
-	. "github.com/onsi/gomega"
+	"github.com/go-chassis/go-chassis/core/handler"
+	"github.com/go-chassis/go-chassis/core/invocation"
 )
 
-func TestModel(t *testing.T) {
-	RegisterFailHandler(Fail)
-	junitReporter := reporters.NewJUnitReporter("junit.xml")
-	RunSpecsWithDefaultAndCustomReporters(t, "Model Suite", []Reporter{junitReporter})
+//NoopAuthHandler not need implement any logic
+//developer can extend authenticate and authorization by set new handler in chassis.yaml
+type NoopAuthHandler struct{}
+
+func (bk *NoopAuthHandler) Handle(chain *handler.Chain, inv *invocation.Invocation, cb invocation.ResponseCallBack) {
+	inv.SetMetadata("domain", "default")
+	chain.Next(inv, cb)
 }
 
-var _ = BeforeSuite(func() {
-	log.Init(log.Config{
-		Writers:     []string{"stdout"},
-		LoggerLevel: "DEBUG",
-	})
+func newDomainResolver() handler.Handler {
+	return &NoopAuthHandler{}
+}
 
-	logger := log.NewLogger("ut")
-	openlogging.SetLogger(logger)
-})
+func (bk *NoopAuthHandler) Name() string {
+	return "auth-handler"
+}
+func init() {
+	handler.RegisterHandler("auth-handler", newDomainResolver)
+}
diff --git a/server/resource/v1/common.go b/server/resource/v1/common.go
new file mode 100644
index 0000000..5d7bceb
--- /dev/null
+++ b/server/resource/v1/common.go
@@ -0,0 +1,60 @@
+/*
+ * 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 v1
+
+import (
+	"encoding/json"
+	"fmt"
+	"github.com/apache/servicecomb-kie/pkg/model"
+	"github.com/go-chassis/go-chassis/server/restful"
+	"github.com/go-mesh/openlogging"
+)
+
+const (
+	FindExact               = "exact"
+	FindMany                = "greedy"
+	MsgDomainMustNotBeEmpty = "domain must not be empty"
+	MsgIllegalFindPolicy    = "value of header X-Find can be greedy or exact"
+	MsgIllegalLabels        = "label's value can not be empty, " +
+		"label can not be duplicated, please check your query parameters"
+)
+
+func ReadDomain(context *restful.Context) interface{} {
+	return context.ReadRestfulRequest().Attribute("domain")
+}
+func ReadFindPolicy(context *restful.Context) string {
+	policy := context.ReadRestfulRequest().HeaderParameter("X-Find")
+	if policy == "" {
+		return FindMany
+	}
+	return policy
+}
+func WriteErrResponse(context *restful.Context, status int, msg string) {
+	context.WriteHeader(status)
+	b, _ := json.MarshalIndent(&ErrorMsg{Msg: msg}, "", " ")
+	context.Write(b)
+}
+
+func ErrLog(action string, kv *model.KV, err error) {
+	openlogging.Error(fmt.Sprintf("[%s] [%v] err:%s", action, kv, err.Error()))
+}
+
+func InfoLog(action string, kv *model.KV) {
+	openlogging.Info(
+		fmt.Sprintf("[%s] [%s:%s] in [%s] success", action, kv.Key, kv.Value, kv.Domain))
+}
diff --git a/server/kv/errors.go b/server/resource/v1/doc_struct.go
similarity index 61%
rename from server/kv/errors.go
rename to server/resource/v1/doc_struct.go
index 958a015..a0402ae 100644
--- a/server/kv/errors.go
+++ b/server/resource/v1/doc_struct.go
@@ -15,21 +15,14 @@
  * limitations under the License.
  */
 
-package kv
+package v1
 
-import (
-	"errors"
-	"fmt"
-
-	"github.com/apache/servicecomb-kie/pkg/model"
-	"github.com/go-mesh/openlogging"
-)
-
-//ErrAction will wrap raw error to biz error and return
-//it record audit log for mongodb operation failure like find, insert, update, deletion
-func ErrAction(action, key string, labels model.Labels, domain string, err error) error {
-	msg := fmt.Sprintf("can not [%s] [%s] in [%s] with [%s],err: %s", action, key, domain, labels, err.Error())
-	openlogging.Error(msg)
-	return errors.New(msg)
+type KVBody struct {
+	Labels    map[string]string `json:"labels"`
+	ValueType string            `json:"valueType"`
+	Value     string            `json:"value"`
+}
 
+type ErrorMsg struct {
+	Msg string `json:"msg"`
 }
diff --git a/server/resource/v1/kv_resource.go b/server/resource/v1/kv_resource.go
new file mode 100644
index 0000000..7a9d66d
--- /dev/null
+++ b/server/resource/v1/kv_resource.go
@@ -0,0 +1,249 @@
+/*
+ * 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.
+ */
+
+//v1 package hold http rest v1 API
+package v1
+
+import (
+	"encoding/json"
+	"github.com/apache/servicecomb-kie/pkg/model"
+	"github.com/apache/servicecomb-kie/server/dao"
+	goRestful "github.com/emicklei/go-restful"
+	"github.com/go-chassis/go-chassis/server/restful"
+	"github.com/go-mesh/openlogging"
+	"net/http"
+)
+
+type KVResource struct {
+}
+
+func (r *KVResource) Put(context *restful.Context) {
+	var err error
+	key := context.ReadPathParameter("key")
+	kv := new(model.KV)
+	decoder := json.NewDecoder(context.ReadRequest().Body)
+	if err = decoder.Decode(kv); err != nil {
+		WriteErrResponse(context, http.StatusInternalServerError, err.Error())
+		return
+	}
+	domain := ReadDomain(context)
+	if domain == nil {
+		WriteErrResponse(context, http.StatusInternalServerError, MsgDomainMustNotBeEmpty)
+	}
+	kv.Key = key
+	kv.Domain = domain.(string)
+	s, err := dao.NewKVService()
+	if err != nil {
+		WriteErrResponse(context, http.StatusInternalServerError, err.Error())
+		return
+	}
+	kv, err = s.CreateOrUpdate(kv)
+	if err != nil {
+		ErrLog("put", kv, err)
+		WriteErrResponse(context, http.StatusInternalServerError, err.Error())
+		return
+	}
+	InfoLog("put", kv)
+	context.WriteHeader(http.StatusOK)
+	context.WriteHeaderAndJSON(http.StatusOK, kv, goRestful.MIME_JSON)
+
+}
+func (r *KVResource) Find(context *restful.Context) {
+	var err error
+	key := context.ReadPathParameter("key")
+	if key == "" {
+		WriteErrResponse(context, http.StatusForbidden, "key must not be empty")
+		return
+	}
+	values := context.ReadRequest().URL.Query()
+	labels := make(map[string]string, len(values))
+	for k, v := range values {
+		if len(v) != 1 {
+			WriteErrResponse(context, http.StatusBadRequest, MsgIllegalLabels)
+			return
+		}
+		labels[k] = v[0]
+	}
+	s, err := dao.NewKVService()
+	if err != nil {
+		WriteErrResponse(context, http.StatusInternalServerError, err.Error())
+		return
+	}
+	domain := ReadDomain(context)
+	if domain == nil {
+		WriteErrResponse(context, http.StatusInternalServerError, MsgDomainMustNotBeEmpty)
+		return
+	}
+	policy := ReadFindPolicy(context)
+	var kvs []*model.KV
+	switch policy {
+	case FindMany:
+		kvs, err = s.Find(domain.(string), dao.WithKey(key), dao.WithLabels(labels))
+	case FindExact:
+		kvs, err = s.Find(domain.(string), dao.WithKey(key), dao.WithLabels(labels),
+			dao.WithExactLabels())
+	default:
+		WriteErrResponse(context, http.StatusBadRequest, MsgIllegalFindPolicy)
+		return
+	}
+	if err != nil {
+		WriteErrResponse(context, http.StatusInternalServerError, err.Error())
+		return
+	}
+	err = context.WriteHeaderAndJSON(http.StatusOK, kvs, goRestful.MIME_JSON)
+	if err != nil {
+		openlogging.Error(err.Error())
+	}
+
+}
+func (r *KVResource) FindByLabels(context *restful.Context) {
+	var err error
+	values := context.ReadRequest().URL.Query()
+	labels := make(map[string]string, len(values))
+	for k, v := range values {
+		if len(v) != 1 {
+			WriteErrResponse(context, http.StatusBadRequest, MsgIllegalLabels)
+			return
+		}
+		labels[k] = v[0]
+	}
+	s, err := dao.NewKVService()
+	if err != nil {
+		WriteErrResponse(context, http.StatusInternalServerError, err.Error())
+		return
+	}
+	domain := ReadDomain(context)
+	if domain == nil {
+		WriteErrResponse(context, http.StatusInternalServerError, MsgDomainMustNotBeEmpty)
+		return
+	}
+	policy := ReadFindPolicy(context)
+	var kvs []*model.KV
+	switch policy {
+	case FindMany:
+		kvs, err = s.Find(domain.(string), dao.WithLabels(labels))
+	case FindExact:
+		kvs, err = s.Find(domain.(string), dao.WithLabels(labels),
+			dao.WithExactLabels())
+	default:
+		WriteErrResponse(context, http.StatusBadRequest, MsgIllegalFindPolicy)
+		return
+	}
+	err = context.WriteHeaderAndJSON(http.StatusOK, kvs, goRestful.MIME_JSON)
+	if err != nil {
+		openlogging.Error(err.Error())
+	}
+
+}
+func (r *KVResource) Delete(context *restful.Context) {
+
+}
+
+//URLPatterns defined config operations
+func (r *KVResource) URLPatterns() []restful.Route {
+	return []restful.Route{
+		{
+			Method:           http.MethodPut,
+			Path:             "/v1/kv/{key}",
+			ResourceFuncName: "Put",
+			FuncDesc:         "create or update key value",
+			Parameters: []*restful.Parameters{
+				{
+					DataType:  "string",
+					Name:      "key",
+					ParamType: goRestful.PathParameterKind,
+				}, {
+					DataType:  "string",
+					Name:      "X-Domain-Name",
+					ParamType: goRestful.HeaderParameterKind,
+					Desc:      "set kv to other tenant",
+				}, {
+					DataType:  "string",
+					Name:      "X-Realm",
+					ParamType: goRestful.HeaderParameterKind,
+					Desc:      "set kv to heterogeneous config server",
+				},
+			},
+			Returns: []*restful.Returns{
+				{
+					Code:    http.StatusOK,
+					Message: "true",
+				},
+			},
+			Consumes: []string{"application/json"},
+			Produces: []string{"application/json"},
+			Read:     &KVBody{},
+		}, {
+			Method:           http.MethodGet,
+			Path:             "/v1/kv/{key}",
+			ResourceFuncName: "Find",
+			FuncDesc:         "get key values by key and labels",
+			Parameters: []*restful.Parameters{
+				{
+					DataType:  "string",
+					Name:      "key",
+					ParamType: goRestful.PathParameterKind,
+				}, {
+					DataType:  "string",
+					Name:      "X-Domain-Name",
+					ParamType: goRestful.HeaderParameterKind,
+				}, {
+					DataType:  "string",
+					Name:      "X-Find",
+					ParamType: goRestful.HeaderParameterKind,
+					Desc:      "greedy or exact",
+				},
+			},
+			Returns: []*restful.Returns{
+				{
+					Code:    http.StatusOK,
+					Message: "get key value success",
+					Model:   []*KVBody{},
+				},
+			},
+			Consumes: []string{"application/json"},
+			Produces: []string{"application/json"},
+			Read:     &KVBody{},
+		}, {
+			Method:           http.MethodGet,
+			Path:             "/v1/kv",
+			ResourceFuncName: "FindByLabels",
+			FuncDesc:         "find key values only by labels",
+			Parameters: []*restful.Parameters{
+				{
+					DataType:  "string",
+					Name:      "X-Domain-Name",
+					ParamType: goRestful.HeaderParameterKind,
+				}, {
+					DataType:  "string",
+					Name:      "X-Find",
+					ParamType: goRestful.HeaderParameterKind,
+					Desc:      "greedy or exact",
+				},
+			},
+			Returns: []*restful.Returns{
+				{
+					Code:    http.StatusOK,
+					Message: "get key value success",
+					Model:   []*KVBody{},
+				},
+			},
+			Consumes: []string{"application/json"},
+			Produces: []string{"application/json"},
+		},
+	}
+}


[servicecomb-kie] 19/29: SCB-1313 Fixed the undefined error when using goland debug

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

asifdxtreme pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git

commit 459904448e395cb4330863efcde0f7f027281e57
Author: Jon Wang <do...@126.com>
AuthorDate: Mon Jun 10 11:08:22 2019 +0800

    SCB-1313 Fixed the undefined error when using goland debug
---
 cmd/kie/cmd.go        | 2 +-
 cmd/{kie => }/main.go | 5 +++--
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/cmd/kie/cmd.go b/cmd/kie/cmd.go
index 45ffb60..4ddad70 100644
--- a/cmd/kie/cmd.go
+++ b/cmd/kie/cmd.go
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package main
+package kie
 
 import (
 	"os"
diff --git a/cmd/kie/main.go b/cmd/main.go
similarity index 90%
rename from cmd/kie/main.go
rename to cmd/main.go
index a70ab9e..4ce2316 100644
--- a/cmd/kie/main.go
+++ b/cmd/main.go
@@ -18,6 +18,7 @@
 package main
 
 import (
+	"github.com/apache/servicecomb-kie/cmd/kie"
 	_ "github.com/apache/servicecomb-kie/server/handler"
 
 	"github.com/apache/servicecomb-kie/server/config"
@@ -28,7 +29,7 @@ import (
 )
 
 func main() {
-	if err := Init(); err != nil {
+	if err := kie.Init(); err != nil {
 		openlogging.Fatal(err.Error())
 	}
 	chassis.RegisterSchema("rest", &v1.KVResource{})
@@ -36,7 +37,7 @@ func main() {
 		openlogging.Error(err.Error())
 		os.Exit(1)
 	}
-	if err := config.Init(Configs.ConfigFile); err != nil {
+	if err := config.Init(kie.Configs.ConfigFile); err != nil {
 		openlogging.Error(err.Error())
 		os.Exit(1)
 	}


[servicecomb-kie] 03/29: Add project introduction

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

asifdxtreme pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git

commit a1c07008c8f7cc2e2eb1918266980322b0b73101
Merge: e66eaec bfc05b3
Author: Willem Jiang <ji...@huawei.com>
AuthorDate: Mon Apr 29 15:54:27 2019 +0800

    Add project introduction
    
    add project introduction

 README.md | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 58 insertions(+), 1 deletion(-)


[servicecomb-kie] 23/29: SCB-1312 Update the README.md

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

asifdxtreme pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git

commit 4718e595158acc86647065b3b23e813860ca2c27
Author: Willem Jiang <wi...@gmail.com>
AuthorDate: Wed Jun 12 08:49:31 2019 +0800

    SCB-1312 Update the README.md
---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 3bd18e5..43ece75 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Apache-ServiceComb-Kie [![Build Status](https://travis-ci.org/apache/servicecomb-pack.svg?branch=master)](https://travis-ci.org/apache/servicecomb-pack?branch=master) [![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)
+# Apache-ServiceComb-Kie [![Build Status](https://travis-ci.org/apache/servicecomb-kie.svg?branch=master)](https://travis-ci.org/apache/servicecomb-kie?branch=master) [![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)
 
 A service for configuration management in distributed system.
 


[servicecomb-kie] 24/29: Fixed the format errors

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

asifdxtreme pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git

commit 1760ea7be250cd193ebc8a28013161ca03085355
Author: Willem Jiang <wi...@gmail.com>
AuthorDate: Wed Jun 12 13:57:17 2019 +0800

    Fixed the format errors
---
 client/client_suite_test.go | 2 +-
 client/options.go           | 2 --
 2 files changed, 1 insertion(+), 3 deletions(-)

diff --git a/client/client_suite_test.go b/client/client_suite_test.go
index f699279..9750391 100644
--- a/client/client_suite_test.go
+++ b/client/client_suite_test.go
@@ -42,5 +42,5 @@ var _ = BeforeSuite(func() {
 
 	logger := log.NewLogger("ut")
 	openlogging.SetLogger(logger)
-	os.Setenv("HTTP_DEBUG","1")
+	os.Setenv("HTTP_DEBUG", "1")
 })
diff --git a/client/options.go b/client/options.go
index 374dcfc..21f820b 100644
--- a/client/options.go
+++ b/client/options.go
@@ -17,8 +17,6 @@
 
 package client
 
-
-
 type GetOption func(*GetOptions)
 type GetOptions struct {
 	Labels    map[string]string


[servicecomb-kie] 15/29: add license, unify response kv struct

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

asifdxtreme pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git

commit 95972504161e9920fead916288bf817f22d9eada
Author: tian <xi...@gmail.com>
AuthorDate: Thu Jun 6 17:27:05 2019 +0800

    add license, unify response kv struct
---
 pkg/common/common.go              |  1 +
 pkg/model/kv.go                   |  6 ++---
 pkg/model/mongodb_doc.go          |  2 +-
 proxy.sh                          | 15 ++++++++++-
 scripts/start.sh                  | 18 ++++++++++++-
 server/dao/kie_api.go             | 53 ++++++++++++++++++++++++++++++++++-----
 server/dao/kv.go                  |  2 +-
 server/dao/kv_test.go             | 20 ++++++++++++---
 server/dao/options.go             |  8 ++++++
 server/resource/v1/common.go      | 16 +++++++++++-
 server/resource/v1/kv_resource.go | 26 +++++++++++++------
 11 files changed, 141 insertions(+), 26 deletions(-)

diff --git a/pkg/common/common.go b/pkg/common/common.go
index 47e224e..345086a 100644
--- a/pkg/common/common.go
+++ b/pkg/common/common.go
@@ -24,4 +24,5 @@ const (
 
 const (
 	HeaderMatch = "X-Match"
+	HeaderDepth = "X-Depth"
 )
diff --git a/pkg/model/kv.go b/pkg/model/kv.go
index be9830e..332c074 100644
--- a/pkg/model/kv.go
+++ b/pkg/model/kv.go
@@ -17,9 +17,7 @@
 
 package model
 
-
-
-
-
 type KVResponse struct {
+	LabelDoc *LabelDoc `json:"labels"`
+	Data     []*KVDoc `json:"data"`
 }
diff --git a/pkg/model/mongodb_doc.go b/pkg/model/mongodb_doc.go
index a298ca2..7645a14 100644
--- a/pkg/model/mongodb_doc.go
+++ b/pkg/model/mongodb_doc.go
@@ -22,7 +22,7 @@ import "go.mongodb.org/mongo-driver/bson/primitive"
 type LabelDoc struct {
 	ID       primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"`
 	Labels   map[string]string  `json:"labels,omitempty"`
-	Revision int                `json:"revision"`
+	Revision int                `json:"revision,omitempty"`
 	Domain   string             `json:"domain,omitempty"` //tenant info
 }
 type KVDoc struct {
diff --git a/proxy.sh b/proxy.sh
index da4430b..5fcc641 100755
--- a/proxy.sh
+++ b/proxy.sh
@@ -1,3 +1,16 @@
 #!/usr/bin/env bash
-
+# 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.
 export GOPROXY=https://goproxy.io
diff --git a/scripts/start.sh b/scripts/start.sh
index 35e62ea..682634c 100755
--- a/scripts/start.sh
+++ b/scripts/start.sh
@@ -19,7 +19,9 @@
 root_dir=/opt/servicecomb-kie
 net_name=$(ip -o -4 route show to default | awk '{print $5}')
 listen_addr=$(ifconfig ${net_name} | grep -E 'inet\W' | grep -o -E [0-9]+.[0-9]+.[0-9]+.[0-9]+ | head -n 1)
-
+if [ -z "${LOG_LEVEL}" ]; then
+ export LOG_LEVEL="DEBUG"
+fi
 
 writeConfig(){
 echo "write template config..."
@@ -38,7 +40,21 @@ cse:
       Provider:
         default: auth-handler,ratelimiter-provider
 EOM
+cat <<EOM > ${root_dir}/conf/lager.yaml
+logger_level: ${LOG_LEVEL}
+
+logger_file: log/chassis.log
+
+log_format_text: true
+
+rollingPolicy: size
 
+log_rotate_date: 1
+
+log_rotate_size: 10
+
+log_backup_count: 7
+EOM
 cat <<EOM > /etc/servicecomb-kie/kie-conf.yaml
 db:
   uri: mongodb://${MONGODB_USER}:${MONGODB_PWD}@${MONGODB_ADDR}/kie
diff --git a/server/dao/kie_api.go b/server/dao/kie_api.go
index c5ae9bd..aaf613f 100644
--- a/server/dao/kie_api.go
+++ b/server/dao/kie_api.go
@@ -26,6 +26,7 @@ import (
 	"go.mongodb.org/mongo-driver/bson/primitive"
 	"go.mongodb.org/mongo-driver/mongo"
 	"go.mongodb.org/mongo-driver/mongo/options"
+	"reflect"
 	"time"
 )
 
@@ -184,7 +185,7 @@ func (s *MongodbService) FindKVByLabelID(ctx context.Context, domain, labelID, k
 //FindKV get kvs by key, labels
 //because labels has a a lot of combination,
 //you can use WithExactLabels to return only one kv which's labels exactly match the criteria
-func (s *MongodbService) FindKV(ctx context.Context, domain string, options ...FindOption) ([]*model.KVDoc, error) {
+func (s *MongodbService) FindKV(ctx context.Context, domain string, options ...FindOption) ([]*model.KVResponse, error) {
 	opts := FindOptions{}
 	for _, o := range options {
 		o(&opts)
@@ -213,9 +214,11 @@ func (s *MongodbService) FindKV(ctx context.Context, domain string, options ...F
 	if cur.Err() != nil {
 		return nil, err
 	}
+	kvResp := make([]*model.KVResponse, 0)
 	if opts.ExactLabels {
 		openlogging.Debug(fmt.Sprintf("find one [%s] with lables [%s] in [%s]", opts.Key, opts.Labels, domain))
 		curKV := &model.KVDoc{} //reuse this pointer to reduce GC, only clear label
+
 		//check label length to get the exact match
 		for cur.Next(ctx) { //although complexity is O(n), but there won't be so much labels for one key
 			curKV.Labels = nil
@@ -226,27 +229,65 @@ func (s *MongodbService) FindKV(ctx context.Context, domain string, options ...F
 			}
 			if len(curKV.Labels) == len(opts.Labels) {
 				openlogging.Debug("hit exact labels")
+				curKV.Domain = ""
 				curKV.Labels = nil //exact match don't need to return labels
-				return []*model.KVDoc{curKV}, nil
+				labelGroup := &model.KVResponse{
+					LabelDoc: &model.LabelDoc{
+						Labels: opts.Labels,
+						ID:     primitive.NilObjectID,
+					},
+					Data: make([]*model.KVDoc, 0),
+				}
+				labelGroup.Data = append(labelGroup.Data, curKV)
+				kvResp = append(kvResp, labelGroup)
+				return kvResp, nil
 			}
 
 		}
 		return nil, ErrKeyNotExists
 	} else {
-		kvs := make([]*model.KVDoc, 0)
+		if opts.Depth == 0 {
+			opts.Depth = 1
+		}
 		for cur.Next(ctx) {
 			curKV := &model.KVDoc{}
+
 			if err := cur.Decode(curKV); err != nil {
 				openlogging.Error("decode to KVs error: " + err.Error())
 				return nil, err
 			}
-			kvs = append(kvs, curKV)
+			if (len(curKV.Labels) - len(opts.Labels)) > opts.Depth {
+				//because it is query by labels, so result can not be minus
+				//so many labels,then continue
+				openlogging.Debug("so deep, skip this key")
+				continue
+			}
+			openlogging.Info(fmt.Sprintf("%v", curKV))
+			var groupExist bool
+			var labelGroup *model.KVResponse
+			for _, labelGroup = range kvResp {
+				if reflect.DeepEqual(labelGroup.LabelDoc.Labels, curKV.Labels) {
+					groupExist = true
+					labelGroup.Data = append(labelGroup.Data, curKV)
+					break
+				}
 
+			}
+			if !groupExist {
+				labelGroup = &model.KVResponse{
+					LabelDoc: &model.LabelDoc{
+						Labels: curKV.Labels,
+					},
+					Data: []*model.KVDoc{curKV},
+				}
+				openlogging.Debug("add new label group")
+			}
+			kvResp = append(kvResp, labelGroup)
 		}
-		if len(kvs) == 0 {
+		if len(kvResp) == 0 {
 			return nil, ErrKeyNotExists
 		}
-		return kvs, nil
+		return kvResp, nil
 	}
 
 }
diff --git a/server/dao/kv.go b/server/dao/kv.go
index 1f7eccf..c48774b 100644
--- a/server/dao/kv.go
+++ b/server/dao/kv.go
@@ -99,7 +99,7 @@ func (s *MongodbService) KVExist(ctx context.Context, domain, key string, option
 			return primitive.NilObjectID, ErrTooMany
 		}
 
-		return kvs[0].ID, nil
+		return kvs[0].Data[0].ID, nil
 	}
 
 }
diff --git a/server/dao/kv_test.go b/server/dao/kv_test.go
index 7e2a5eb..efbe6d4 100644
--- a/server/dao/kv_test.go
+++ b/server/dao/kv_test.go
@@ -96,7 +96,7 @@ var _ = Describe("Kv mongodb service", func() {
 				"app": "mall",
 			}), dao.WithExactLabels())
 			It("should be 1s", func() {
-				Expect(kvs1[0].Value).Should(Equal(beforeKV.Value))
+				Expect(kvs1[0].Data[0].Value).Should(Equal(beforeKV.Value))
 			})
 			afterKV, err := s.CreateOrUpdate(context.Background(), "default", &model.KVDoc{
 				Key:    "timeout",
@@ -119,19 +119,33 @@ var _ = Describe("Kv mongodb service", func() {
 				"app": "mall",
 			}), dao.WithExactLabels())
 			It("should be 3s", func() {
-				Expect(kvs[0].Value).Should(Equal(afterKV.Value))
+				Expect(kvs[0].Data[0].Value).Should(Equal(afterKV.Value))
 			})
 		})
 	})
 
 	Describe("greedy find by kv and labels", func() {
-		Context("with labels app ", func() {
+		Context("with labels app,depth is 1 ", func() {
 			kvs, err := s.FindKV(context.Background(), "default", dao.WithKey("timeout"), dao.WithLabels(map[string]string{
 				"app": "mall",
 			}))
 			It("should not return err", func() {
 				Expect(err).Should(BeNil())
 			})
+			It("should has 2 records", func() {
+				Expect(len(kvs)).Should(Equal(2))
+			})
+
+		})
+		Context("with labels app,depth is 2 ", func() {
+			kvs, err := s.FindKV(context.Background(), "default", dao.WithKey("timeout"),
+				dao.WithLabels(map[string]string{
+					"app": "mall",
+				}),
+				dao.WithDepth(2))
+			It("should not return err", func() {
+				Expect(err).Should(BeNil())
+			})
 			It("should has 3 records", func() {
 				Expect(len(kvs)).Should(Equal(3))
 			})
diff --git a/server/dao/options.go b/server/dao/options.go
index e1af384..7e33798 100644
--- a/server/dao/options.go
+++ b/server/dao/options.go
@@ -19,6 +19,7 @@ package dao
 
 type FindOptions struct {
 	ExactLabels bool
+	Depth       int
 	Key         string
 	Labels      map[string]string
 	LabelID     string
@@ -55,6 +56,13 @@ func WithLabelID(label string) FindOption {
 	}
 }
 
+//WithDepth if you use greedy match this can specify the match depth
+func WithDepth(d int) FindOption {
+	return func(o *FindOptions) {
+		o.Depth = d
+	}
+}
+
 //WithOutLabelField will clear all labels attributes in kv doc
 func WithOutLabelField() FindOption {
 	return func(o *FindOptions) {
diff --git a/server/resource/v1/common.go b/server/resource/v1/common.go
index 2293b72..eca9fef 100644
--- a/server/resource/v1/common.go
+++ b/server/resource/v1/common.go
@@ -24,22 +24,36 @@ import (
 	"github.com/apache/servicecomb-kie/pkg/model"
 	"github.com/go-chassis/go-chassis/server/restful"
 	"github.com/go-mesh/openlogging"
+	"strconv"
 )
 
 const (
-	TenantHeaderParam       = "X-Domain-Name"
+	HeaderTenant = "X-Domain-Name"
+
 	FindExact               = "exact"
 	FindMany                = "greedy"
 	MsgDomainMustNotBeEmpty = "domain must not be empty"
 	MsgIllegalFindPolicy    = "value of header " + common.HeaderMatch + " can be greedy or exact"
 	MsgIllegalLabels        = "label's value can not be empty, " +
 		"label can not be duplicated, please check your query parameters"
+	MsgIllegalDepth   = "X-Depth must be number"
 	ErrIDMustNotEmpty = "must supply id if you want to remove key"
 )
 
 func ReadDomain(context *restful.Context) interface{} {
 	return context.ReadRestfulRequest().Attribute("domain")
 }
+func ReadFindDepth(context *restful.Context) (int, error) {
+	d := context.ReadRestfulRequest().HeaderParameter(common.HeaderDepth)
+	if d == "" {
+		return 1, nil
+	}
+	depth, err := strconv.Atoi(d)
+	if err != nil {
+		return 0, err
+	}
+	return depth, nil
+}
 func ReadMatchPolicy(context *restful.Context) string {
 	policy := context.ReadRestfulRequest().HeaderParameter(common.HeaderMatch)
 	if policy == "" {
diff --git a/server/resource/v1/kv_resource.go b/server/resource/v1/kv_resource.go
index db2d2b6..7832f23 100644
--- a/server/resource/v1/kv_resource.go
+++ b/server/resource/v1/kv_resource.go
@@ -91,10 +91,15 @@ func (r *KVResource) FindWithKey(context *restful.Context) {
 		return
 	}
 	policy := ReadMatchPolicy(context)
-	var kvs []*model.KVDoc
+	d, err := ReadFindDepth(context)
+	if err != nil {
+		WriteErrResponse(context, http.StatusBadRequest, MsgIllegalDepth)
+		return
+	}
+	var kvs []*model.KVResponse
 	switch policy {
 	case common.MatchGreedy:
-		kvs, err = s.FindKV(context.Ctx, domain.(string), dao.WithKey(key), dao.WithLabels(labels))
+		kvs, err = s.FindKV(context.Ctx, domain.(string), dao.WithKey(key), dao.WithLabels(labels), dao.WithDepth(d))
 	case common.MatchExact:
 		kvs, err = s.FindKV(context.Ctx, domain.(string), dao.WithKey(key), dao.WithLabels(labels),
 			dao.WithExactLabels())
@@ -138,10 +143,15 @@ func (r *KVResource) FindByLabels(context *restful.Context) {
 		return
 	}
 	policy := ReadMatchPolicy(context)
-	var kvs []*model.KVDoc
+	d, err := ReadFindDepth(context)
+	if err != nil {
+		WriteErrResponse(context, http.StatusBadRequest, MsgIllegalDepth)
+		return
+	}
+	var kvs []*model.KVResponse
 	switch policy {
 	case common.MatchGreedy:
-		kvs, err = s.FindKV(context.Ctx, domain.(string), dao.WithLabels(labels))
+		kvs, err = s.FindKV(context.Ctx, domain.(string), dao.WithLabels(labels), dao.WithDepth(d))
 	case common.MatchExact:
 		kvs, err = s.FindKV(context.Ctx, domain.(string), dao.WithLabels(labels),
 			dao.WithExactLabels())
@@ -199,7 +209,7 @@ func (r *KVResource) URLPatterns() []restful.Route {
 					ParamType: goRestful.PathParameterKind,
 				}, {
 					DataType:  "string",
-					Name:      TenantHeaderParam,
+					Name:      HeaderTenant,
 					ParamType: goRestful.HeaderParameterKind,
 					Desc:      "set kv to other tenant",
 				}, {
@@ -230,7 +240,7 @@ func (r *KVResource) URLPatterns() []restful.Route {
 					ParamType: goRestful.PathParameterKind,
 				}, {
 					DataType:  "string",
-					Name:      TenantHeaderParam,
+					Name:      HeaderTenant,
 					ParamType: goRestful.HeaderParameterKind,
 				}, {
 					DataType:  "string",
@@ -257,7 +267,7 @@ func (r *KVResource) URLPatterns() []restful.Route {
 			Parameters: []*restful.Parameters{
 				{
 					DataType:  "string",
-					Name:      TenantHeaderParam,
+					Name:      HeaderTenant,
 					ParamType: goRestful.HeaderParameterKind,
 				}, {
 					DataType:  "string",
@@ -283,7 +293,7 @@ func (r *KVResource) URLPatterns() []restful.Route {
 			Parameters: []*restful.Parameters{
 				{
 					DataType:  "string",
-					Name:      TenantHeaderParam,
+					Name:      HeaderTenant,
 					ParamType: goRestful.HeaderParameterKind,
 				}, {
 					DataType:  "string",


[servicecomb-kie] 21/29: SCB-1312 Add license header

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

asifdxtreme pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git

commit 87e0ea93347b7e88ea6843c2a04a044286e7552b
Author: Willem Jiang <wi...@gmail.com>
AuthorDate: Tue Jun 11 08:29:36 2019 +0800

    SCB-1312 Add license header
---
 .travis.yml                    | 24 +++++++++++++++++++-----
 scripts/travis/goVetChecker.sh | 17 +++++++++++++++++
 2 files changed, 36 insertions(+), 5 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index a619141..6e4794f 100755
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,21 @@
+# 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.
+
 language: go
 sudo: required
-go: 
+go:
   - 1.11
 install: true
 
@@ -15,11 +30,11 @@ jobs:
     - stage: Format Checker
       script: bash scripts/travis/formatChecker.sh
     - stage: DeadCode Checker
-      script: 
+      script:
         - go get -u github.com/tsenart/deadcode
         - bash scripts/travis/deadCodeChecker.sh
     - stage: Misspell Checker
-      script: 
+      script:
         - go get -u github.com/client9/misspell
         - bash scripts/travis/misspellChecker.sh
     - stage: GoConst Checker
@@ -44,7 +59,6 @@ jobs:
         - bash scripts/travis/unit_test.sh && $HOME/gopath/bin/goveralls -coverprofile=coverage.txt -service=travis-ci
 
     - stage: Build
-      script: 
+      script:
         - cd build
         - ./build_server.sh
-
diff --git a/scripts/travis/goVetChecker.sh b/scripts/travis/goVetChecker.sh
index 8b15de5..7a7384f 100755
--- a/scripts/travis/goVetChecker.sh
+++ b/scripts/travis/goVetChecker.sh
@@ -1,3 +1,20 @@
+#!/usr/bin/env bash
+
+# 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.
+
 diff -u <(echo -n) <(find . -type d -not -path "./vendor/*" -not -path "./third_party/*"| xargs go vet )
 if [ $? == 0 ]; then
 	echo "Hurray....all OKAY..."