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 <[email protected]> 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", },
