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:18 UTC
[servicecomb-kie] 07/29: add rest api for put and find, (#3)
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"},
+ },
+ }
+}