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

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


The following commit(s) were added to refs/heads/master by this push:
     new 913ee43  SCB-1331 support mongodb TLS communication (#20)
913ee43 is described below

commit 913ee43f6c4a8a2785e7650d9db658e8e564c411
Author: Shawn <[email protected]>
AuthorDate: Sat Jul 13 17:36:23 2019 +0800

    SCB-1331 support mongodb TLS communication (#20)
---
 .gitignore                             |   1 +
 README.md                              |   6 +-
 examples/dev/conf/lager.yaml           |   1 +
 examples/dev/kie-conf.yaml             |   7 +-
 go.mod                                 |  11 ++-
 pkg/common/common.go                   |   5 ++
 server/config/struct.go                |  10 +--
 server/dao/errors.go                   |  34 -------
 server/dao/kie_api.go                  |  29 ++++--
 server/dao/kv.go                       |  36 +++++++-
 server/dao/label.go                    |   2 +-
 server/dao/label_history.go            |   2 +-
 server/resource/v1/common.go           |   7 +-
 server/resource/v1/kv_resource.go      |  56 +++++++-----
 server/resource/v1/kv_resource_test.go |   2 +-
 swagger/servicecomb-kie.yaml           | 157 +++++++++++++++++++++++++++++++++
 16 files changed, 275 insertions(+), 91 deletions(-)

diff --git a/.gitignore b/.gitignore
index 8d99bb8..89c876c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,6 +8,7 @@ output
 *.iml
 .idea/
 **/*junit.xml
+**/*crt
 **/*.exe
 **/*.tgz
 vendor/**
diff --git a/README.md b/README.md
index 43ece75..df84789 100644
--- a/README.md
+++ b/README.md
@@ -81,15 +81,19 @@ it will launch 3 components
 To see how to build a local dev environment, check [here](examples/dev)
 
 ### Build
+this will build your own service image and binary in local
 ```bash
 cd build
-export VERSION=0.0.1
+export VERSION=0.0.1 #optional, it is latest by default
 ./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"
 
+# API Doc
+swagger/servicecomb-kie.yaml
+
 ## Contact
 
 Bugs: [issues](https://issues.apache.org/jira/browse/SCB)
diff --git a/examples/dev/conf/lager.yaml b/examples/dev/conf/lager.yaml
new file mode 100644
index 0000000..419ae46
--- /dev/null
+++ b/examples/dev/conf/lager.yaml
@@ -0,0 +1 @@
+log_format_text: false
\ No newline at end of file
diff --git a/examples/dev/kie-conf.yaml b/examples/dev/kie-conf.yaml
index af99321..c9633fa 100644
--- a/examples/dev/kie-conf.yaml
+++ b/examples/dev/kie-conf.yaml
@@ -1,7 +1,8 @@
 db:
+  #uri: mongodb://rwuser:[email protected]:8635/test?authSource=admin
   uri: mongodb://kie:[email protected]:27017
   type: mongodb
   poolSize: 10
-  ssl: false
-  sslCA:
-  sslCert:
\ No newline at end of file
+  timeout:  5m
+  sslEnabled: false
+  rootCAFile: /opt/kie/ca.crt
\ No newline at end of file
diff --git a/go.mod b/go.mod
index 77abed3..b76a7cd 100644
--- a/go.mod
+++ b/go.mod
@@ -2,18 +2,17 @@ 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.18.0
-       github.com/go-chassis/go-chassis v1.5.0
+       github.com/go-chassis/foundation v0.0.0-20190621030543-c3b63f787f4c
+       github.com/go-chassis/go-archaius v0.19.0
+       github.com/go-chassis/go-chassis v1.5.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
        github.com/onsi/gomega v1.5.0
-       github.com/pkg/errors v0.8.0
-       github.com/stretchr/testify v1.2.2
+       github.com/stretchr/testify v1.3.0
        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
+       go.mongodb.org/mongo-driver v1.0.3
        gopkg.in/yaml.v2 v2.2.1
 )
diff --git a/pkg/common/common.go b/pkg/common/common.go
index f111bce..f6a2ead 100644
--- a/pkg/common/common.go
+++ b/pkg/common/common.go
@@ -28,3 +28,8 @@ const (
        HeaderDepth  = "X-Depth"
        HeaderTenant = "X-Domain-Name"
 )
+
+//ContentType
+const (
+       ContentTypeText = "application/text"
+)
diff --git a/server/config/struct.go b/server/config/struct.go
index 0e2cd55..d3ad4da 100644
--- a/server/config/struct.go
+++ b/server/config/struct.go
@@ -24,9 +24,9 @@ type Config struct {
 
 //DB is yaml file struct to set mongodb config
 type DB struct {
-       URI      string   `yaml:"uri"`
-       PoolSize int      `yaml:"poolSize"`
-       SSL      bool     `yaml:"ssl"`
-       CABundle []string `yaml:"sslCA"`
-       Cert     string   `yaml:"sslCert"`
+       URI        string `yaml:"uri"`
+       PoolSize   int    `yaml:"poolSize"`
+       SSLEnabled bool   `yaml:"sslEnabled"`
+       RootCA     string `yaml:"rootCAFile"`
+       Timeout    string `yaml:"timeout"`
 }
diff --git a/server/dao/errors.go b/server/dao/errors.go
deleted file mode 100644
index 349ca6d..0000000
--- a/server/dao/errors.go
+++ /dev/null
@@ -1,34 +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 dao
-
-import (
-       "errors"
-       "fmt"
-
-       "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, 
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/kie_api.go b/server/dao/kie_api.go
index de65dcd..37e5fa9 100644
--- a/server/dao/kie_api.go
+++ b/server/dao/kie_api.go
@@ -63,7 +63,7 @@ func (s *MongodbService) CreateOrUpdate(ctx context.Context, 
domain string, kv *
                        "default": "default",
                }
        }
-       ctx, _ = context.WithTimeout(ctx, DefaultTimeout)
+       ctx, _ = context.WithTimeout(ctx, s.timeout)
        //check labels exits or not
        labelID, err := s.LabelsExist(ctx, domain, kv.Labels)
        var l *model.LabelDoc
@@ -114,7 +114,7 @@ func (s *MongodbService) CreateOrUpdate(ctx 
context.Context, domain string, kv *
 //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)
+       ctx, _ = context.WithTimeout(context.Background(), s.timeout)
        filter := bson.M{"domain": domain}
        for k, v := range labels {
                filter["labels."+k] = v
@@ -125,7 +125,10 @@ func (s *MongodbService) FindLabels(ctx context.Context, 
domain string, labels m
        cur, err := collection.Find(ctx, filter)
        if err != nil {
                if err.Error() == context.DeadlineExceeded.Error() {
-                       return nil, ErrAction("find label", filter, 
fmt.Errorf("can not reach mongodb in %s", s.timeout))
+                       openlogging.Error("find label failed, dead line 
exceeded", openlogging.WithTags(openlogging.Tags{
+                               "timeout": s.timeout,
+                       }))
+                       return nil, fmt.Errorf("can not reach mongodb in %s", 
s.timeout)
                }
                return nil, err
        }
@@ -158,7 +161,10 @@ func (s *MongodbService) findKeys(ctx context.Context, 
filter bson.M, withoutLab
        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))
+                       openlogging.Error("find kvs failed, dead line 
exceeded", openlogging.WithTags(openlogging.Tags{
+                               "timeout": s.timeout,
+                       }))
+                       return nil, fmt.Errorf("can not reach mongodb in %s", 
s.timeout)
                }
                return nil, err
        }
@@ -190,7 +196,7 @@ func (s *MongodbService) findKeys(ctx context.Context, 
filter bson.M, withoutLab
 //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)
+       ctx, _ = context.WithTimeout(context.Background(), s.timeout)
        filter := bson.M{"label_id": labelID, "domain": domain}
        if key != "" {
                filter["key"] = key
@@ -284,7 +290,7 @@ func (s *MongodbService) FindKV(ctx context.Context, domain 
string, options ...F
 //domain=tenant
 //1.delete kv;2.add history
 func (s *MongodbService) Delete(kvID string, labelID string, domain string) 
error {
-       ctx, _ := context.WithTimeout(context.Background(), DefaultTimeout)
+       ctx, _ := context.WithTimeout(context.Background(), s.timeout)
        if domain == "" {
                return ErrMissingDomain
        }
@@ -354,17 +360,22 @@ func NewMongoService(opts Options) (*MongodbService, 
error) {
 func getClient(opts Options) (*mongo.Client, error) {
        if client == nil {
                var err error
-               client, err = 
mongo.NewClient(options.Client().ApplyURI(opts.URI))
+               clientOps := 
[]*options.ClientOptions{options.Client().ApplyURI(opts.URI)}
+               if opts.TLS != nil {
+                       clientOps = append(clientOps, 
options.Client().SetTLSConfig(opts.TLS))
+                       openlogging.Info("enabled ssl communication to mongodb")
+               }
+               client, err = mongo.NewClient(clientOps...)
                if err != nil {
                        return nil, err
                }
-               openlogging.Info("connecting to " + opts.URI)
+               openlogging.Info("DB connecting")
                ctx, _ := context.WithTimeout(context.Background(), 
10*time.Second)
                err = client.Connect(ctx)
                if err != nil {
                        return nil, err
                }
-               openlogging.Info("connected to " + opts.URI)
+               openlogging.Info("DB connected")
        }
        return client, nil
 }
diff --git a/server/dao/kv.go b/server/dao/kv.go
index e3dcad1..f2065a5 100644
--- a/server/dao/kv.go
+++ b/server/dao/kv.go
@@ -21,6 +21,7 @@ package dao
 import (
        "context"
        "crypto/tls"
+       "crypto/x509"
        "errors"
        "fmt"
        "github.com/apache/servicecomb-kie/pkg/model"
@@ -29,6 +30,7 @@ import (
        "go.mongodb.org/mongo-driver/bson"
        "go.mongodb.org/mongo-driver/bson/primitive"
        "go.mongodb.org/mongo-driver/mongo"
+       "io/ioutil"
        "time"
 )
 
@@ -42,6 +44,7 @@ var (
        ErrRevisionNotExist       = errors.New("label revision not exist")
        ErrKVIDIsNil              = errors.New("kvID id is nil")
        ErrKvIDAndLabelIDNotMatch = errors.New("kvID and labelID do not match")
+       ErrRootCAMissing          = errors.New("rootCAFile is empty in config 
file")
 )
 
 //Options mongodb options
@@ -56,13 +59,35 @@ type Options struct {
 //NewKVService create a kv service
 //TODO, multiple config server
 func NewKVService() (*MongodbService, error) {
+       var d time.Duration
+       var err error
+       if config.GetDB().Timeout != "" {
+               d, err = time.ParseDuration(config.GetDB().Timeout)
+               if err != nil {
+                       return nil, errors.New("timeout setting invalid:" + 
config.GetDB().Timeout)
+               }
+       }
        opts := Options{
                URI:      config.GetDB().URI,
                PoolSize: config.GetDB().PoolSize,
-               SSL:      config.GetDB().SSL,
+               SSL:      config.GetDB().SSLEnabled,
+               Timeout:  d,
        }
        if opts.SSL {
-               //TODO tls config
+               if config.GetDB().RootCA == "" {
+                       return nil, ErrRootCAMissing
+               }
+               pool := x509.NewCertPool()
+               caCert, err := ioutil.ReadFile(config.GetDB().RootCA)
+               if err != nil {
+                       return nil, fmt.Errorf("read ca cert file %s failed", 
caCert)
+               }
+               pool.AppendCertsFromPEM(caCert)
+               opts.TLS = &tls.Config{
+                       RootCAs:            pool,
+                       InsecureSkipVerify: true,
+               }
+
        }
        return NewMongoService(opts)
 }
@@ -111,7 +136,7 @@ func (s *MongodbService) KVExist(ctx context.Context, 
domain, key string, option
 
 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)
+       ctx, _ = context.WithTimeout(ctx, s.timeout)
        filter := bson.M{"domain": domain}
        if opts.Key != "" {
                filter["key"] = opts.Key
@@ -123,7 +148,10 @@ func (s *MongodbService) findKV(ctx context.Context, 
domain string, opts FindOpt
        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))
+                       openlogging.Error("find kv failed, deadline exceeded", 
openlogging.WithTags(openlogging.Tags{
+                               "timeout": s.timeout,
+                       }))
+                       return nil, fmt.Errorf("can not reach mongodb in %s", 
s.timeout)
                }
                return nil, err
        }
diff --git a/server/dao/label.go b/server/dao/label.go
index 742c3dc..f80088f 100644
--- a/server/dao/label.go
+++ b/server/dao/label.go
@@ -42,7 +42,7 @@ func (s *MongodbService) createLabel(ctx context.Context, 
domain string, labels
 }
 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)
+       ctx, _ = context.WithTimeout(context.Background(), s.timeout)
        sr := collection.FindOne(ctx, filter)
        if sr.Err() != nil {
                return nil, sr.Err()
diff --git a/server/dao/label_history.go b/server/dao/label_history.go
index c796e7b..08f8766 100644
--- a/server/dao/label_history.go
+++ b/server/dao/label_history.go
@@ -29,7 +29,7 @@ import (
 
 func (s *MongodbService) getLatestLabel(ctx context.Context, labelID string) 
(*model.LabelRevisionDoc, error) {
        collection := s.c.Database(DB).Collection(CollectionLabelRevision)
-       ctx, _ = context.WithTimeout(ctx, DefaultTimeout)
+       ctx, _ = context.WithTimeout(ctx, s.timeout)
 
        filter := bson.M{"label_id": labelID}
 
diff --git a/server/resource/v1/common.go b/server/resource/v1/common.go
index f96c11c..db40b4a 100644
--- a/server/resource/v1/common.go
+++ b/server/resource/v1/common.go
@@ -19,13 +19,13 @@ package v1
 
 import (
        "encoding/json"
+       "errors"
        "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"
 )
@@ -80,14 +80,17 @@ func ReadLabelCombinations(req *goRestful.Request) 
([]map[string]string, error)
        if len(labelCombinations) == 0 {
                return []map[string]string{{"default": "default"}}, nil
        }
+
        return labelCombinations, nil
 }
 
 //WriteErrResponse write error message to client
-func WriteErrResponse(context *restful.Context, status int, msg string) {
+func WriteErrResponse(context *restful.Context, status int, msg, contentType 
string) {
        context.WriteHeader(status)
        b, _ := json.MarshalIndent(&ErrorMsg{Msg: msg}, "", " ")
+       context.ReadRestfulResponse().AddHeader(goRestful.HEADER_ContentType, 
contentType)
        context.Write(b)
+
 }
 
 //ErrLog record error
diff --git a/server/resource/v1/kv_resource.go 
b/server/resource/v1/kv_resource.go
index d8b2d50..443c1a5 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"
@@ -39,23 +40,23 @@ func (r *KVResource) Put(context *restful.Context) {
        kv := new(model.KVDoc)
        decoder := json.NewDecoder(context.ReadRequest().Body)
        if err = decoder.Decode(kv); err != nil {
-               WriteErrResponse(context, http.StatusInternalServerError, 
err.Error())
+               WriteErrResponse(context, http.StatusInternalServerError, 
err.Error(), common.ContentTypeText)
                return
        }
        domain := ReadDomain(context)
        if domain == nil {
-               WriteErrResponse(context, http.StatusInternalServerError, 
MsgDomainMustNotBeEmpty)
+               WriteErrResponse(context, http.StatusInternalServerError, 
MsgDomainMustNotBeEmpty, common.ContentTypeText)
        }
        kv.Key = key
        s, err := dao.NewKVService()
        if err != nil {
-               WriteErrResponse(context, http.StatusInternalServerError, 
err.Error())
+               WriteErrResponse(context, http.StatusInternalServerError, 
err.Error(), common.ContentTypeText)
                return
        }
        kv, err = s.CreateOrUpdate(context.Ctx, domain.(string), kv)
        if err != nil {
                ErrLog("put", kv, err)
-               WriteErrResponse(context, http.StatusInternalServerError, 
err.Error())
+               WriteErrResponse(context, http.StatusInternalServerError, 
err.Error(), common.ContentTypeText)
                return
        }
        InfoLog("put", kv)
@@ -69,40 +70,40 @@ func (r *KVResource) GetByKey(context *restful.Context) {
        var err error
        key := context.ReadPathParameter("key")
        if key == "" {
-               WriteErrResponse(context, http.StatusForbidden, "key must not 
be empty")
+               WriteErrResponse(context, http.StatusForbidden, "key must not 
be empty", common.ContentTypeText)
                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)
+                       WriteErrResponse(context, http.StatusBadRequest, 
MsgIllegalLabels, common.ContentTypeText)
                        return
                }
                labels[k] = v[0]
        }
        s, err := dao.NewKVService()
        if err != nil {
-               WriteErrResponse(context, http.StatusInternalServerError, 
err.Error())
+               WriteErrResponse(context, http.StatusInternalServerError, 
err.Error(), common.ContentTypeText)
                return
        }
        domain := ReadDomain(context)
        if domain == nil {
-               WriteErrResponse(context, http.StatusInternalServerError, 
MsgDomainMustNotBeEmpty)
+               WriteErrResponse(context, http.StatusInternalServerError, 
MsgDomainMustNotBeEmpty, common.ContentTypeText)
                return
        }
        d, err := ReadFindDepth(context)
        if err != nil {
-               WriteErrResponse(context, http.StatusBadRequest, 
MsgIllegalDepth)
+               WriteErrResponse(context, http.StatusBadRequest, 
MsgIllegalDepth, common.ContentTypeText)
                return
        }
        kvs, err := s.FindKV(context.Ctx, domain.(string), dao.WithKey(key), 
dao.WithLabels(labels), dao.WithDepth(d))
        if err != nil {
                if err == dao.ErrKeyNotExists {
-                       WriteErrResponse(context, http.StatusNotFound, 
err.Error())
+                       WriteErrResponse(context, http.StatusNotFound, 
err.Error(), common.ContentTypeText)
                        return
                }
-               WriteErrResponse(context, http.StatusInternalServerError, 
err.Error())
+               WriteErrResponse(context, http.StatusInternalServerError, 
err.Error(), common.ContentTypeText)
                return
        }
        err = context.WriteHeaderAndJSON(http.StatusOK, kvs, 
goRestful.MIME_JSON)
@@ -117,34 +118,41 @@ func (r *KVResource) SearchByLabels(context 
*restful.Context) {
        var err error
        labelCombinations, err := 
ReadLabelCombinations(context.ReadRestfulRequest())
        if err != nil {
-               WriteErrResponse(context, http.StatusBadRequest, err.Error())
+               WriteErrResponse(context, http.StatusBadRequest, err.Error(), 
common.ContentTypeText)
                return
        }
        s, err := dao.NewKVService()
        if err != nil {
-               WriteErrResponse(context, http.StatusInternalServerError, 
err.Error())
+               WriteErrResponse(context, http.StatusInternalServerError, 
err.Error(), common.ContentTypeText)
                return
        }
        domain := ReadDomain(context)
        if domain == nil {
-               WriteErrResponse(context, http.StatusInternalServerError, 
MsgDomainMustNotBeEmpty)
+               WriteErrResponse(context, http.StatusInternalServerError, 
MsgDomainMustNotBeEmpty, common.ContentTypeText)
                return
        }
        var kvs []*model.KVResponse
        for _, labels := range labelCombinations {
+               openlogging.Debug("find by combination", 
openlogging.WithTags(openlogging.Tags{
+                       "q": labels,
+               }))
                result, err := s.FindKV(context.Ctx, domain.(string), 
dao.WithLabels(labels))
                if err != nil {
                        if err == dao.ErrKeyNotExists {
                                continue
+                       } else {
+                               openlogging.Error("can not find by labels", 
openlogging.WithTags(openlogging.Tags{
+                                       "err": err.Error(),
+                               }))
+                               WriteErrResponse(context, 
http.StatusInternalServerError, err.Error(), common.ContentTypeText)
+                               return
                        }
-                       WriteErrResponse(context, 
http.StatusInternalServerError, err.Error())
-                       return
                }
                kvs = append(kvs, result...)
 
        }
        if len(kvs) == 0 {
-               WriteErrResponse(context, http.StatusNotFound, "no kv found")
+               WriteErrResponse(context, http.StatusNotFound, "no kv found", 
common.ContentTypeText)
                return
        }
 
@@ -159,17 +167,17 @@ func (r *KVResource) SearchByLabels(context 
*restful.Context) {
 func (r *KVResource) Delete(context *restful.Context) {
        domain := ReadDomain(context)
        if domain == nil {
-               WriteErrResponse(context, http.StatusInternalServerError, 
MsgDomainMustNotBeEmpty)
+               WriteErrResponse(context, http.StatusInternalServerError, 
MsgDomainMustNotBeEmpty, common.ContentTypeText)
        }
        kvID := context.ReadPathParameter("kvID")
        if kvID == "" {
-               WriteErrResponse(context, http.StatusBadRequest, 
ErrKvIDMustNotEmpty)
+               WriteErrResponse(context, http.StatusBadRequest, 
ErrKvIDMustNotEmpty, common.ContentTypeText)
                return
        }
        labelID := context.ReadQueryParameter("labelID")
        s, err := dao.NewKVService()
        if err != nil {
-               WriteErrResponse(context, http.StatusInternalServerError, 
err.Error())
+               WriteErrResponse(context, http.StatusInternalServerError, 
err.Error(), common.ContentTypeText)
                return
        }
        err = s.Delete(kvID, labelID, domain.(string))
@@ -179,7 +187,7 @@ func (r *KVResource) Delete(context *restful.Context) {
                        "labelID": labelID,
                        "error":   err.Error(),
                }))
-               WriteErrResponse(context, http.StatusInternalServerError, 
err.Error())
+               WriteErrResponse(context, http.StatusInternalServerError, 
err.Error(), common.ContentTypeText)
                return
        }
        context.WriteHeader(http.StatusNoContent)
@@ -209,7 +217,7 @@ func (r *KVResource) URLPatterns() []restful.Route {
                        },
                        Consumes: []string{goRestful.MIME_JSON},
                        Produces: []string{goRestful.MIME_JSON},
-                       Read:     &KVBody{},
+                       Read:     KVBody{},
                }, {
                        Method:           http.MethodGet,
                        Path:             "/v1/kv/{key}",
@@ -222,7 +230,7 @@ func (r *KVResource) URLPatterns() []restful.Route {
                                {
                                        Code:    http.StatusOK,
                                        Message: "get key value success",
-                                       Model:   []*model.KVResponse{},
+                                       Model:   []model.KVResponse{},
                                },
                        },
                        Consumes: []string{goRestful.MIME_JSON},
@@ -240,7 +248,7 @@ func (r *KVResource) URLPatterns() []restful.Route {
                                {
                                        Code:    http.StatusOK,
                                        Message: "get key value success",
-                                       Model:   []*model.KVResponse{},
+                                       Model:   []model.KVResponse{},
                                },
                        },
                        Consumes: []string{goRestful.MIME_JSON},
diff --git a/server/resource/v1/kv_resource_test.go 
b/server/resource/v1/kv_resource_test.go
index 8119ef0..445ef6f 100644
--- a/server/resource/v1/kv_resource_test.go
+++ b/server/resource/v1/kv_resource_test.go
@@ -36,8 +36,8 @@ var _ = Describe("v1 kv resource", func() {
        config.Configurations = &config.Config{
                DB: config.DB{},
        }
+       config.Configurations.DB.URI = "mongodb://kie:[email protected]:27017"
        Describe("put kv", func() {
-               config.Configurations.DB.URI = 
"mongodb://kie:[email protected]:27017"
                Context("valid param", func() {
                        kv := &model.KVDoc{
                                Value:  "1s",
diff --git a/swagger/servicecomb-kie.yaml b/swagger/servicecomb-kie.yaml
new file mode 100644
index 0000000..4e7685b
--- /dev/null
+++ b/swagger/servicecomb-kie.yaml
@@ -0,0 +1,157 @@
+swagger: "2.0"
+info:
+  title: ""
+  version: ""
+basePath: /
+paths:
+  /v1/kv:
+    get:
+      summary: search key values by labels combination
+      operationId: SearchByLabels
+      parameters:
+      - name: q
+        in: query
+        description: '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'
+        type: string
+      consumes:
+      - application/json
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: get key value success
+          schema:
+            type: array
+            items:
+              $ref: '#/definitions/KVResponse'
+  /v1/kv/{key}:
+    get:
+      summary: get key values by key and labels
+      operationId: GetByKey
+      parameters:
+      - name: key
+        in: path
+        required: true
+        type: string
+      - name: X-Depth
+        in: header
+        description: integer, default is 1, if you set match policy, you can 
set,depth
+          to decide label number
+        type: string
+      - name: body
+        in: body
+        required: true
+        schema:
+          $ref: '#/definitions/*v1.KVBody'
+      consumes:
+      - application/json
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: get key value success
+          schema:
+            type: array
+            items:
+              $ref: '#/definitions/KVResponse'
+    put:
+      summary: create or update key value
+      operationId: Put
+      parameters:
+      - name: key
+        in: path
+        required: true
+        type: string
+      - name: X-Realm
+        in: header
+        description: set kv to heterogeneous config server, not implement yet
+        type: string
+      - name: body
+        in: body
+        required: true
+        schema:
+          $ref: '#/definitions/v1.KVBody'
+      consumes:
+      - application/json
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: "true"
+  /v1/kv/{kvID}:
+    delete:
+      summary: Delete key by kvID and labelID,If the labelID is nil, query the 
collection
+        kv to get it.It means if only get kvID, it can also delete 
normally.But if
+        you want better performance, you need to pass the labelID
+      operationId: Delete
+      parameters:
+      - name: key
+        in: path
+        required: true
+        type: string
+      responses:
+        "204":
+          description: Delete success
+        "400":
+          description: Failed,check url
+        "500":
+          description: Server error
+definitions:
+  KVDoc:
+    type: object
+    properties:
+      _id:
+        type: array
+        items:
+          type: integer
+          format: byte
+      check:
+        type: string
+      domain:
+        type: string
+      key:
+        type: string
+      label_id:
+        type: string
+      labels:
+        type: object
+        additionalProperties:
+          type: string
+      revision:
+        type: integer
+        format: int32
+      value:
+        type: string
+      value_type:
+        type: string
+  KVResponse:
+    type: object
+    properties:
+      data:
+        type: array
+        items:
+          $ref: '#/definitions/KVDoc'
+      label:
+        $ref: '#/definitions/LabelDocResponse'
+  LabelDocResponse:
+    type: object
+    properties:
+      label_id:
+        type: string
+      labels:
+        type: object
+        additionalProperties:
+          type: string
+  v1.KVBody:
+    type: object
+    properties:
+      labels:
+        type: object
+        additionalProperties:
+          type: string
+      value:
+        type: string
+      valueType:
+        type: string

Reply via email to