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:21 UTC

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

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",
 				},