From f1f24f3c83a32867ba786858e29b59696dbeb13a Mon Sep 17 00:00:00 2001 From: Minoru Osuka Date: Mon, 30 Mar 2020 16:18:11 +0900 Subject: [PATCH 1/3] Migrate to Cobra and Viper --- .gitignore | 18 --- Dockerfile | 16 +- Makefile | 64 ++++---- README.md | 27 +--- cmd/cete/cluster.go | 53 ------ cmd/cete/delete.go | 54 ------- cmd/cete/get.go | 59 ------- cmd/cete/join.go | 75 --------- cmd/cete/leave.go | 55 ------- cmd/cete/main.go | 359 ----------------------------------------- cmd/cete/metrics.go | 47 ------ cmd/cete/node.go | 53 ------ cmd/cete/set.go | 63 -------- cmd/cete/snapshot.go | 43 ----- cmd/cete/start.go | 160 ------------------ cmd/cete/watch.go | 120 -------------- cmd/cluster.go | 92 +++++++++++ cmd/delete.go | 91 +++++++++++ cmd/get.go | 94 +++++++++++ cmd/join.go | 106 ++++++++++++ cmd/leave.go | 91 +++++++++++ cmd/metrics.go | 86 ++++++++++ cmd/node.go | 92 +++++++++++ cmd/root.go | 17 ++ cmd/set.go | 93 +++++++++++ cmd/snapshot.go | 83 ++++++++++ cmd/start.go | 200 +++++++++++++++++++++++ cmd/variables.go | 20 +++ cmd/version.go | 24 +++ cmd/watch.go | 159 ++++++++++++++++++ docker-entrypoint.sh | 16 +- etc/cete.yaml | 15 ++ go.mod | 4 +- go.sum | 53 +++++- log/log.go | 21 +-- main.go | 15 ++ marshaler/util_test.go | 22 +-- 37 files changed, 1372 insertions(+), 1288 deletions(-) delete mode 100644 cmd/cete/cluster.go delete mode 100644 cmd/cete/delete.go delete mode 100644 cmd/cete/get.go delete mode 100644 cmd/cete/join.go delete mode 100644 cmd/cete/leave.go delete mode 100644 cmd/cete/main.go delete mode 100644 cmd/cete/metrics.go delete mode 100644 cmd/cete/node.go delete mode 100644 cmd/cete/set.go delete mode 100644 cmd/cete/snapshot.go delete mode 100644 cmd/cete/start.go delete mode 100644 cmd/cete/watch.go create mode 100644 cmd/cluster.go create mode 100644 cmd/delete.go create mode 100644 cmd/get.go create mode 100644 cmd/join.go create mode 100644 cmd/leave.go create mode 100644 cmd/metrics.go create mode 100644 cmd/node.go create mode 100644 cmd/root.go create mode 100644 cmd/set.go create mode 100644 cmd/snapshot.go create mode 100644 cmd/start.go create mode 100644 cmd/variables.go create mode 100644 cmd/version.go create mode 100644 cmd/watch.go create mode 100644 etc/cete.yaml create mode 100644 main.go diff --git a/.gitignore b/.gitignore index e26302f..ee0c04c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,31 +1,13 @@ -# Copyright (c) 2017 Minoru Osuka -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - .DS_Store -# Eclipse .classpath .project -# Gogland .idea/ -# Blast bin/ dist/ -# TLS *.pem *.csr diff --git a/Dockerfile b/Dockerfile index 338f7eb..98cbbfe 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,17 +1,3 @@ -# Copyright (c) 2020 Minoru Osuka -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - FROM golang:1.14.0-alpine3.11 ARG VERSION @@ -46,4 +32,4 @@ COPY --from=0 /go/src/github.com/mosuka/cete/docker-entrypoint.sh /usr/bin/ EXPOSE 7000 8000 9000 ENTRYPOINT [ "/usr/bin/docker-entrypoint.sh" ] -CMD [ "cete", "--help" ] +CMD [ "cete", "start" ] diff --git a/Makefile b/Makefile index dc39857..fa32ddc 100644 --- a/Makefile +++ b/Makefile @@ -1,17 +1,3 @@ -# Copyright (c) 2020 Minoru Osuka -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - GOOS ?= GOARCH ?= GO111MODULE ?= on @@ -27,7 +13,7 @@ PACKAGES = $(shell $(GO) list ./... | grep -v '/vendor/') PROTOBUFS = $(shell find . -name '*.proto' -print0 | xargs -0 -n1 dirname | sort | uniq | grep -v /vendor/) -TARGET_PACKAGES = $(shell find . -name 'main.go' -print0 | xargs -0 -n1 dirname | sort | uniq | grep -v /vendor/) +TARGET_PACKAGES = $(shell find $(CURDIR) -name 'main.go' -print0 | xargs -0 -n1 dirname | sort | uniq | grep -v /vendor/) GRPC_GATEWAY_PATH = $(shell $(GO) list -m -f "{{.Dir}}" github.com/grpc-ecosystem/grpc-gateway) @@ -55,13 +41,13 @@ GO := GOOS=$(GOOS) GOARCH=$(GOARCH) CGO_ENABLED=$(CGO_ENABLED) CGO_CFLAGS=$(CGO_ .PHONY: protoc protoc: @echo ">> generating proto3 code" - @for proto_dir in $(PROTOBUFS); do echo $$proto_dir; protoc --proto_path=. --proto_path=$$proto_dir --proto_path=${GRPC_GATEWAY_PATH} --proto_path=${GRPC_GATEWAY_PATH}/third_party/googleapis --go_out=plugins=grpc:$(GOPATH)/src $$proto_dir/*.proto || exit 1; done - @for proto_dir in $(PROTOBUFS); do echo $$proto_dir; protoc --proto_path=. --proto_path=$$proto_dir --proto_path=${GRPC_GATEWAY_PATH} --proto_path=${GRPC_GATEWAY_PATH}/third_party/googleapis --grpc-gateway_out=logtostderr=true,allow_delete_body=true:$(GOPATH)/src $$proto_dir/*.proto || exit 1; done + for proto_dir in $(PROTOBUFS); do echo $$proto_dir; protoc --proto_path=. --proto_path=$$proto_dir --proto_path=${GRPC_GATEWAY_PATH} --proto_path=${GRPC_GATEWAY_PATH}/third_party/googleapis --go_out=plugins=grpc:$(GOPATH)/src $$proto_dir/*.proto || exit 1; done + for proto_dir in $(PROTOBUFS); do echo $$proto_dir; protoc --proto_path=. --proto_path=$$proto_dir --proto_path=${GRPC_GATEWAY_PATH} --proto_path=${GRPC_GATEWAY_PATH}/third_party/googleapis --grpc-gateway_out=logtostderr=true,allow_delete_body=true:$(GOPATH)/src $$proto_dir/*.proto || exit 1; done .PHONY: format format: @echo ">> formatting code" - @$(GO) fmt $(PACKAGES) + $(GO) fmt $(PACKAGES) .PHONY: test test: @@ -72,13 +58,20 @@ test: @echo " CGO_CFLAGS = $(CGO_CFLAGS)" @echo " CGO_LDFLAGS = $(CGO_LDFLAGS)" @echo " BUILD_TAGS = $(BUILD_TAGS)" - @$(GO) test -v -tags="$(BUILD_TAGS)" $(PACKAGES) + $(GO) test -v -tags="$(BUILD_TAGS)" $(PACKAGES) .PHONY: coverage coverage: @echo ">> checking coverage of all packages" - $(GO) test -coverprofile=./cover.out -tags="$(BUILD_TAGS)" $(PACKAGES) - $(GO) tool cover -html=cover.out -o cover.html + (GO) test -coverprofile=./cover.out -tags="$(BUILD_TAGS)" $(PACKAGES) + (GO) tool cover -html=cover.out -o cover.html + +.PHONY: clean +clean: + @echo ">> cleaning binaries" + rm -rf ./bin + rm -rf ./data + rm -rf ./dist .PHONY: build build: @@ -90,7 +83,7 @@ build: @echo " CGO_LDFLAGS = $(CGO_LDFLAGS)" @echo " BUILD_TAGS = $(BUILD_TAGS)" @echo " VERSION = $(VERSION)" - @for target_pkg in $(TARGET_PACKAGES); do echo $$target_pkg; $(GO) build -tags="$(BUILD_TAGS)" $(LDFLAGS) -o ./bin/`basename $$target_pkg`$(BIN_EXT) $$target_pkg || exit 1; done + for target_pkg in $(TARGET_PACKAGES); do echo $$target_pkg; $(GO) build -tags="$(BUILD_TAGS)" $(LDFLAGS) -o ./bin/`basename $$target_pkg`$(BIN_EXT) $$target_pkg || exit 1; done .PHONY: install install: @@ -102,7 +95,7 @@ install: @echo " CGO_LDFLAGS = $(CGO_LDFLAGS)" @echo " BUILD_TAGS = $(BUILD_TAGS)" @echo " VERSION = $(VERSION)" - @for target_pkg in $(TARGET_PACKAGES); do echo $$target_pkg; $(GO) install -tags="$(BUILD_TAGS)" $(LDFLAGS) $$target_pkg || exit 1; done + for target_pkg in $(TARGET_PACKAGES); do echo $$target_pkg; $(GO) install -tags="$(BUILD_TAGS)" $(LDFLAGS) $$target_pkg || exit 1; done .PHONY: dist dist: @@ -115,11 +108,11 @@ dist: @echo " BUILD_TAGS = $(BUILD_TAGS)" @echo " VERSION = $(VERSION)" mkdir -p ./dist/$(GOOS)-$(GOARCH)/bin - @for target_pkg in $(TARGET_PACKAGES); do echo $$target_pkg; $(GO) build -tags="$(BUILD_TAGS)" $(LDFLAGS) -o ./dist/$(GOOS)-$(GOARCH)/bin/`basename $$target_pkg`$(BIN_EXT) $$target_pkg || exit 1; done + for target_pkg in $(TARGET_PACKAGES); do echo $$target_pkg; $(GO) build -tags="$(BUILD_TAGS)" $(LDFLAGS) -o ./dist/$(GOOS)-$(GOARCH)/bin/`basename $$target_pkg`$(BIN_EXT) $$target_pkg || exit 1; done (cd ./dist/$(GOOS)-$(GOARCH); tar zcfv ../cete-${VERSION}.$(GOOS)-$(GOARCH).tar.gz .) -.PHONY: git-tag -git-tag: +.PHONY: tag +tag: @echo ">> tagging github" @echo " VERSION = $(VERSION)" ifeq ($(VERSION),$(filter $(VERSION),latest master "")) @@ -129,30 +122,27 @@ else git push origin $(VERSION) endif -.PHONY: docker-build -docker-build: +.PHONY: build-docker +build-docker: @echo ">> building docker container image" @echo " DOCKER_REPOSITORY = $(DOCKER_REPOSITORY)" @echo " VERSION = $(VERSION)" docker build -t $(DOCKER_REPOSITORY)/cete:latest --build-arg VERSION=$(VERSION) . docker tag $(DOCKER_REPOSITORY)/cete:latest $(DOCKER_REPOSITORY)/cete:$(VERSION) -.PHONY: docker-push -docker-push: +.PHONY: push-docker +push-docker: @echo ">> pushing docker container image" @echo " DOCKER_REPOSITORY = $(DOCKER_REPOSITORY)" @echo " VERSION = $(VERSION)" docker push $(DOCKER_REPOSITORY)/cete:latest docker push $(DOCKER_REPOSITORY)/cete:$(VERSION) -.PHONY: clean -clean: - @echo ">> cleaning binaries" - rm -rf ./bin - rm -rf ./data - rm -rf ./dist +.PHONY: clean-docker +clean-docker: + docker rmi -f $(shell docker images --filter "dangling=true" -q --no-trunc) .PHONY: cert cert: @echo ">> generating certification" - openssl req -x509 -nodes -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -subj '/CN=localhost' + openssl req -x509 -nodes -newkey rsa:4096 -keyout ./etc/cete-key.pem -out ./etc/cete-cert.pem -days 365 -subj '/CN=localhost' diff --git a/README.md b/README.md index cda6060..af1b5f6 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,3 @@ - - # Cete Cete is a distributed key value store server written in [Go](https://golang.org) built on top of [BadgerDB](https://blog.dgraph.io/post/badger/). @@ -360,7 +341,7 @@ Cete supports HTTPS access, ensuring that all communication between clients and One way to generate the necessary resources is via [openssl](https://www.openssl.org/). For example: ```bash -$ openssl req -x509 -nodes -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -subj '/CN=localhost' +$ openssl req -x509 -nodes -newkey rsa:4096 -keyout ./etc/cete-key.pem -out ./etc/cete-cert.pem -days 365 -subj '/CN=localhost' Generating a 4096 bit RSA private key ............................++ ........++ @@ -372,9 +353,9 @@ writing new private key to 'key.pem' Starting a node with HTTPS enabled, node-to-node encryption, and with the above configuration file. It is assumed the HTTPS X.509 certificate and key are at the paths server.crt and key.pem respectively. ```bash -$ ./bin/cete start --id=node1 --bind-addr=:7000 --grpc-addr=:9000 --http-addr=:8000 --data-dir=/tmp/cete/node1 --peer-grpc-addr=:9000 --cert-file=./cert.pem --key-file=./key.pem --cert-hostname=localhost -$ ./bin/cete start --id=node2 --bind-addr=:7001 --grpc-addr=:9001 --http-addr=:8001 --data-dir=/tmp/cete/node2 --peer-grpc-addr=:9000 --cert-file=./cert.pem --key-file=./key.pem --cert-hostname=localhost -$ ./bin/cete start --id=node3 --bind-addr=:7002 --grpc-addr=:9002 --http-addr=:8002 --data-dir=/tmp/cete/node3 --peer-grpc-addr=:9000 --cert-file=./cert.pem --key-file=./key.pem --cert-hostname=localhost +$ ./bin/cete start --id=node1 --bind-addr=:7000 --grpc-addr=:9000 --http-addr=:8000 --data-dir=/tmp/cete/node1 --peer-grpc-addr=:9000 --cert-file=./etc/cert.pem --key-file=./etc/key.pem --cert-hostname=localhost +$ ./bin/cete start --id=node2 --bind-addr=:7001 --grpc-addr=:9001 --http-addr=:8001 --data-dir=/tmp/cete/node2 --peer-grpc-addr=:9000 --cert-file=./etc/cert.pem --key-file=./etc/key.pem --cert-hostname=localhost +$ ./bin/cete start --id=node3 --bind-addr=:7002 --grpc-addr=:9002 --http-addr=:8002 --data-dir=/tmp/cete/node3 --peer-grpc-addr=:9000 --cert-file=./etc/cert.pem --key-file=./etc/key.pem --cert-hostname=localhost ``` You can access the cluster by adding a flag, such as the following command: diff --git a/cmd/cete/cluster.go b/cmd/cete/cluster.go deleted file mode 100644 index 6dad6ff..0000000 --- a/cmd/cete/cluster.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2020 Minoru Osuka -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "encoding/json" - "fmt" - "os" - - "github.com/mosuka/cete/client" - "github.com/urfave/cli" -) - -func execCluster(ctx *cli.Context) error { - grpcAddr := ctx.String("grpc-addr") - certFile := ctx.String("cert-file") - certHostname := ctx.String("cert-hostname") - - c, err := client.NewGRPCClientWithContextTLS(grpcAddr, context.Background(), certFile, certHostname) - if err != nil { - return err - } - defer func() { - _ = c.Close() - }() - - resp, err := c.Cluster() - if err != nil { - return err - } - - clusterBytes, err := json.Marshal(resp) - if err != nil { - return err - } - - _, _ = fmt.Fprintln(os.Stdout, fmt.Sprintf("%s", string(clusterBytes))) - - return nil -} diff --git a/cmd/cete/delete.go b/cmd/cete/delete.go deleted file mode 100644 index cf7abf7..0000000 --- a/cmd/cete/delete.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2020 Minoru Osuka -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "errors" - - "github.com/mosuka/cete/client" - "github.com/mosuka/cete/protobuf" - "github.com/urfave/cli" -) - -func execDelete(ctx *cli.Context) error { - grpcAddr := ctx.String("grpc-addr") - certFile := ctx.String("cert-file") - certHostname := ctx.String("cert-hostname") - - key := ctx.Args().Get(0) - if key == "" { - err := errors.New("key argument must be set") - return err - } - - req := &protobuf.DeleteRequest{ - Key: key, - } - - c, err := client.NewGRPCClientWithContextTLS(grpcAddr, context.Background(), certFile, certHostname) - if err != nil { - return err - } - defer func() { - _ = c.Close() - }() - - if err = c.Delete(req); err != nil { - return err - } - - return nil -} diff --git a/cmd/cete/get.go b/cmd/cete/get.go deleted file mode 100644 index 49592cd..0000000 --- a/cmd/cete/get.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2020 Minoru Osuka -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "errors" - "fmt" - "os" - - "github.com/mosuka/cete/client" - "github.com/mosuka/cete/protobuf" - "github.com/urfave/cli" -) - -func execGet(ctx *cli.Context) error { - grpcAddr := ctx.String("grpc-addr") - certFile := ctx.String("cert-file") - certHostname := ctx.String("cert-hostname") - - key := ctx.Args().Get(0) - if key == "" { - err := errors.New("key argument must be set") - return err - } - - req := &protobuf.GetRequest{ - Key: key, - } - - c, err := client.NewGRPCClientWithContextTLS(grpcAddr, context.Background(), certFile, certHostname) - if err != nil { - return err - } - defer func() { - _ = c.Close() - }() - - resp, err := c.Get(req) - if err != nil { - return err - } - - _, _ = fmt.Fprintln(os.Stdout, fmt.Sprintf("%s", string(resp.Value))) - - return nil -} diff --git a/cmd/cete/join.go b/cmd/cete/join.go deleted file mode 100644 index 22d2cd5..0000000 --- a/cmd/cete/join.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) 2020 Minoru Osuka -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "errors" - - "github.com/mosuka/cete/client" - "github.com/mosuka/cete/protobuf" - "github.com/urfave/cli" -) - -func execJoin(ctx *cli.Context) error { - grpcAddr := ctx.String("grpc-addr") - certFile := ctx.String("cert-file") - certHostname := ctx.String("cert-hostname") - - id := ctx.Args().Get(0) - if id == "" { - err := errors.New("id argument must be set") - return err - } - - targetGrpcAddr := ctx.Args().Get(1) - if targetGrpcAddr == "" { - err := errors.New("address argument must be set") - return err - } - - t, err := client.NewGRPCClientWithContextTLS(targetGrpcAddr, context.Background(), certFile, certHostname) - if err != nil { - return err - } - defer func() { - _ = t.Close() - }() - - nodeResp, err := t.Node() - if err != nil { - return err - } - - req := &protobuf.JoinRequest{ - Id: id, - Node: nodeResp.Node, - } - - c, err := client.NewGRPCClientWithContextTLS(grpcAddr, context.Background(), certFile, certHostname) - if err != nil { - return err - } - defer func() { - _ = c.Close() - }() - - err = c.Join(req) - if err != nil { - return err - } - - return nil -} diff --git a/cmd/cete/leave.go b/cmd/cete/leave.go deleted file mode 100644 index 447c5ee..0000000 --- a/cmd/cete/leave.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2020 Minoru Osuka -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "errors" - - "github.com/mosuka/cete/client" - "github.com/mosuka/cete/protobuf" - "github.com/urfave/cli" -) - -func execLeave(ctx *cli.Context) error { - grpcAddr := ctx.String("grpc-addr") - certFile := ctx.String("cert-file") - certHostname := ctx.String("cert-hostname") - - id := ctx.Args().Get(0) - if id == "" { - err := errors.New("id argument must be set") - return err - } - - req := &protobuf.LeaveRequest{ - Id: id, - } - - c, err := client.NewGRPCClientWithContextTLS(grpcAddr, context.Background(), certFile, certHostname) - if err != nil { - return err - } - defer func() { - _ = c.Close() - }() - - err = c.Leave(req) - if err != nil { - return err - } - - return nil -} diff --git a/cmd/cete/main.go b/cmd/cete/main.go deleted file mode 100644 index 24f4de5..0000000 --- a/cmd/cete/main.go +++ /dev/null @@ -1,359 +0,0 @@ -// Copyright (c) 2020 Minoru Osuka -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "fmt" - "os" - "path" - - "github.com/mosuka/cete/version" - "github.com/urfave/cli" -) - -func main() { - app := cli.NewApp() - app.Name = path.Base(os.Args[0]) - app.Usage = "The lightweight distributed key value store" - app.Version = version.Version - app.Authors = []cli.Author{ - { - Name: "mosuka", - Email: "minoru.osuka@gmail.com", - }, - } - app.Commands = []cli.Command{ - { - Name: "start", - Usage: "Start key value store server", - Flags: []cli.Flag{ - cli.StringFlag{ - Name: "id", - Value: "", - Usage: "Node ID", - }, - cli.StringFlag{ - Name: "bind-addr", - Value: ":7000", - Usage: "Raft bind address", - }, - cli.StringFlag{ - Name: "grpc-addr", - Value: ":9000", - Usage: "gRPC Server listen address", - }, - cli.StringFlag{ - Name: "http-addr", - Value: ":8000", - Usage: "HTTP Server listen address", - }, - cli.StringFlag{ - Name: "data-dir", - Value: "./", - Usage: "Data directory", - }, - cli.StringFlag{ - Name: "peer-grpc-addr", - Value: "", - Usage: "Existing gRPC server listen address to join to the cluster", - }, - cli.StringFlag{ - Name: "cert-file", - Value: "", - Usage: "Path to the client server TLS cert file", - }, - cli.StringFlag{ - Name: "key-file", - Value: "", - Usage: "Path to the client server TLS key file", - }, - cli.StringFlag{ - Name: "cert-hostname", - Value: "", - Usage: "Allowed TLS hostname", - }, - cli.StringFlag{ - Name: "log-level", - Value: "INFO", - Usage: "Log level", - }, - cli.StringFlag{ - Name: "log-file", - Value: os.Stderr.Name(), - Usage: "Log file", - }, - cli.IntFlag{ - Name: "log-max-size", - Value: 500, - Usage: "Max size of a log file (megabytes)", - }, - cli.IntFlag{ - Name: "log-max-backups", - Value: 3, - Usage: "Max backup count of log files", - }, - cli.IntFlag{ - Name: "log-max-age", - Value: 30, - Usage: "Max age of a log file (days)", - }, - cli.BoolFlag{ - Name: "log-compress", - Usage: "Compress a log file", - }, - }, - Action: execStart, - }, - { - Name: "join", - Usage: "Join a node to the cluster", - Flags: []cli.Flag{ - cli.StringFlag{ - Name: "grpc-addr, g", - Value: ":9000", - Usage: "gRPC address to connect to", - }, - cli.StringFlag{ - Name: "cert-file", - Value: "", - Usage: "Path to the client server TLS cert file", - }, - cli.StringFlag{ - Name: "cert-hostname", - Value: "", - Usage: "Allowed TLS hostname", - }, - }, - ArgsUsage: "[id] [target-grpc-addr]", - Action: execJoin, - }, - { - Name: "leave", - Usage: "Leave a node from the cluster", - Flags: []cli.Flag{ - cli.StringFlag{ - Name: "grpc-addr, g", - Value: ":9000", - Usage: "address to connect to", - }, - cli.StringFlag{ - Name: "cert-file", - Value: "", - Usage: "Path to the client server TLS cert file", - }, - cli.StringFlag{ - Name: "cert-hostname", - Value: "", - Usage: "Allowed TLS hostname", - }, - }, - ArgsUsage: "[id]", - Action: execLeave, - }, - { - Name: "node", - Usage: "Get node", - Flags: []cli.Flag{ - cli.StringFlag{ - Name: "grpc-addr, g", - Value: ":9000", - Usage: "gRPC address to connect to", - }, - cli.StringFlag{ - Name: "cert-file", - Value: "", - Usage: "Path to the client server TLS cert file", - }, - cli.StringFlag{ - Name: "cert-hostname", - Value: "", - Usage: "Allowed TLS hostname", - }, - }, - Action: execNode, - }, - { - Name: "cluster", - Usage: "Get cluster", - Flags: []cli.Flag{ - cli.StringFlag{ - Name: "grpc-addr, g", - Value: ":9000", - Usage: "gRPC address to connect to", - }, - cli.StringFlag{ - Name: "cert-file", - Value: "", - Usage: "Path to the client server TLS cert file", - }, - cli.StringFlag{ - Name: "cert-hostname", - Value: "", - Usage: "Allowed TLS hostname", - }, - }, - Action: execCluster, - }, - { - Name: "snapshot", - Usage: "Create snapshot manually", - Flags: []cli.Flag{ - cli.StringFlag{ - Name: "grpc-addr, g", - Value: ":9000", - Usage: "address to connect to", - }, - cli.StringFlag{ - Name: "cert-file", - Value: "", - Usage: "Path to the client server TLS cert file", - }, - cli.StringFlag{ - Name: "cert-hostname", - Value: "", - Usage: "Allowed TLS hostname", - }, - }, - Action: execSnapshot, - }, - { - Name: "get", - Usage: "Get a value by key", - Flags: []cli.Flag{ - cli.StringFlag{ - Name: "grpc-addr, g", - Value: ":9000", - Usage: "gRPC address to connect to", - }, - cli.StringFlag{ - Name: "cert-file", - Value: "", - Usage: "Path to the client server TLS cert file", - }, - cli.StringFlag{ - Name: "cert-hostname", - Value: "", - Usage: "Allowed TLS hostname", - }, - }, - ArgsUsage: "[key]", - Action: execGet, - }, - { - Name: "set", - Usage: "Set a value by key", - Flags: []cli.Flag{ - cli.StringFlag{ - Name: "grpc-addr, g", - Value: ":9000", - Usage: "gRPC address to connect to", - }, - cli.StringFlag{ - Name: "cert-file", - Value: "", - Usage: "Path to the client server TLS cert file", - }, - cli.StringFlag{ - Name: "cert-hostname", - Value: "", - Usage: "Allowed TLS hostname", - }, - }, - ArgsUsage: "[key] [value]", - Action: execSet, - }, - { - Name: "delete", - Usage: "Delete a value by key", - Flags: []cli.Flag{ - cli.StringFlag{ - Name: "grpc-addr, g", - Value: ":9000", - Usage: "gRPC address to connect to", - }, - cli.StringFlag{ - Name: "cert-file", - Value: "", - Usage: "Path to the client server TLS cert file", - }, - cli.StringFlag{ - Name: "cert-hostname", - Value: "", - Usage: "Allowed TLS hostname", - }, - }, - ArgsUsage: "[key]", - Action: execDelete, - }, - { - Name: "watch", - Usage: "Watch node", - Flags: []cli.Flag{ - cli.StringFlag{ - Name: "grpc-addr, g", - Value: ":9000", - Usage: "The gRPC address of the node for which to retrieve the node information", - }, - cli.StringFlag{ - Name: "cert-file", - Value: "", - Usage: "Path to the client server TLS cert file", - }, - cli.StringFlag{ - Name: "cert-hostname", - Value: "", - Usage: "Allowed TLS hostname", - }, - }, - Action: execWatch, - }, - { - Name: "metrics", - Usage: "Get node metrics", - Flags: []cli.Flag{ - cli.StringFlag{ - Name: "grpc-addr, g", - Value: ":9000", - Usage: "gRPC address to connect to", - }, - cli.StringFlag{ - Name: "cert-file", - Value: "", - Usage: "Path to the client server TLS cert file", - }, - cli.StringFlag{ - Name: "cert-hostname", - Value: "", - Usage: "Allowed TLS hostname", - }, - }, - Action: execMetrics, - }, - } - - cli.HelpFlag = cli.BoolFlag{ - Name: "help, h", - Usage: "Show this message", - } - cli.VersionFlag = cli.BoolFlag{ - Name: "version, v", - Usage: "Print the version", - } - - err := app.Run(os.Args) - if err != nil { - _, _ = fmt.Fprintln(os.Stderr, err) - } -} diff --git a/cmd/cete/metrics.go b/cmd/cete/metrics.go deleted file mode 100644 index 90539f3..0000000 --- a/cmd/cete/metrics.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2020 Minoru Osuka -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "fmt" - "os" - - "github.com/mosuka/cete/client" - "github.com/urfave/cli" -) - -func execMetrics(ctx *cli.Context) error { - grpcAddr := ctx.String("grpc-addr") - certFile := ctx.String("cert-file") - certHostname := ctx.String("cert-hostname") - - c, err := client.NewGRPCClientWithContextTLS(grpcAddr, context.Background(), certFile, certHostname) - if err != nil { - return err - } - defer func() { - _ = c.Close() - }() - - resp, err := c.Metrics() - if err != nil { - return err - } - - _, _ = fmt.Fprintln(os.Stdout, fmt.Sprintf("%s", string(resp.Metrics))) - - return nil -} diff --git a/cmd/cete/node.go b/cmd/cete/node.go deleted file mode 100644 index 74fb577..0000000 --- a/cmd/cete/node.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2020 Minoru Osuka -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "encoding/json" - "fmt" - "os" - - "github.com/mosuka/cete/client" - "github.com/urfave/cli" -) - -func execNode(ctx *cli.Context) error { - grpcAddr := ctx.String("grpc-addr") - certFile := ctx.String("cert-file") - certHostname := ctx.String("cert-hostname") - - c, err := client.NewGRPCClientWithContextTLS(grpcAddr, context.Background(), certFile, certHostname) - if err != nil { - return err - } - defer func() { - _ = c.Close() - }() - - resp, err := c.Node() - if err != nil { - return err - } - - clusterBytes, err := json.Marshal(resp) - if err != nil { - return err - } - - _, _ = fmt.Fprintln(os.Stdout, fmt.Sprintf("%s", string(clusterBytes))) - - return nil -} diff --git a/cmd/cete/set.go b/cmd/cete/set.go deleted file mode 100644 index b60ebec..0000000 --- a/cmd/cete/set.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) 2020 Minoru Osuka -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "errors" - - "github.com/mosuka/cete/client" - "github.com/mosuka/cete/protobuf" - "github.com/urfave/cli" -) - -func execSet(ctx *cli.Context) error { - grpcAddr := ctx.String("grpc-addr") - certFile := ctx.String("cert-file") - certHostname := ctx.String("cert-hostname") - - key := ctx.Args().Get(0) - if key == "" { - err := errors.New("key argument must be set") - return err - } - - value := ctx.Args().Get(1) - if value == "" { - err := errors.New("value argument must be set") - return err - } - - // create PutRequest - req := &protobuf.SetRequest{ - Key: key, - Value: []byte(value), - } - - c, err := client.NewGRPCClientWithContextTLS(grpcAddr, context.Background(), certFile, certHostname) - if err != nil { - return err - } - defer func() { - _ = c.Close() - }() - - err = c.Set(req) - if err != nil { - return err - } - - return nil -} diff --git a/cmd/cete/snapshot.go b/cmd/cete/snapshot.go deleted file mode 100644 index f85a572..0000000 --- a/cmd/cete/snapshot.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2020 Minoru Osuka -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - - "github.com/mosuka/cete/client" - "github.com/urfave/cli" -) - -func execSnapshot(ctx *cli.Context) error { - grpcAddr := ctx.String("grpc-addr") - certFile := ctx.String("cert-file") - certHostname := ctx.String("cert-hostname") - - c, err := client.NewGRPCClientWithContextTLS(grpcAddr, context.Background(), certFile, certHostname) - if err != nil { - return err - } - defer func() { - _ = c.Close() - }() - - err = c.Snapshot() - if err != nil { - return err - } - - return nil -} diff --git a/cmd/cete/start.go b/cmd/cete/start.go deleted file mode 100644 index a28676f..0000000 --- a/cmd/cete/start.go +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright (c) 2020 Minoru Osuka -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "os" - "os/signal" - "syscall" - "time" - - "github.com/mosuka/cete/client" - "github.com/mosuka/cete/errors" - "github.com/mosuka/cete/log" - "github.com/mosuka/cete/protobuf" - "github.com/mosuka/cete/server" - "github.com/urfave/cli" - "go.uber.org/zap" -) - -func execStart(ctx *cli.Context) error { - nodeId := ctx.String("id") - bindAddr := ctx.String("bind-addr") - grpcAddr := ctx.String("grpc-addr") - httpAddr := ctx.String("http-addr") - dataDir := ctx.String("data-dir") - peerGrpcAddr := ctx.String("peer-grpc-addr") - - certFile := ctx.String("cert-file") - keyFile := ctx.String("key-file") - certHostname := ctx.String("cert-hostname") - - logger := log.NewLogger( - ctx.String("log-level"), - ctx.String("log-file"), - ctx.Int("log-max-size"), - ctx.Int("log-max-backups"), - ctx.Int("log-max-age"), - ctx.Bool("log-compress"), - ) - - bootstrap := peerGrpcAddr == "" || peerGrpcAddr == grpcAddr - - raftServer, err := server.NewRaftServer(nodeId, bindAddr, dataDir, bootstrap, logger) - if err != nil { - logger.Error("failed to create Raft server", - zap.String("id", nodeId), - zap.String("bind_addr", bindAddr), - zap.String("data_dir", dataDir), - zap.Bool("bootstrap", bootstrap), - zap.String("err", err.Error()), - ) - return err - } - - grpcServer, err := server.NewGRPCServer(grpcAddr, raftServer, certFile, keyFile, certHostname, logger) - if err != nil { - logger.Error("failed to create gRPC server", zap.String("grpc_addr", grpcAddr), zap.Error(err)) - return err - } - - grpcGateway, err := server.NewGRPCGateway(httpAddr, grpcAddr, certFile, keyFile, certHostname, logger) - if err != nil { - logger.Error("failed to create gRPC gateway", zap.String("http_addr", httpAddr), zap.String("grpc_addr", grpcAddr), zap.Error(err)) - return err - } - - quitCh := make(chan os.Signal, 1) - signal.Notify(quitCh, os.Kill, os.Interrupt, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) - - if err := raftServer.Start(); err != nil { - logger.Error("failed to start Raft server", zap.Error(err)) - return err - } - - if err := grpcServer.Start(); err != nil { - logger.Error("failed to start gRPC server", zap.Error(err)) - return err - } - - if err := grpcGateway.Start(); err != nil { - logger.Error("failed to start gRPC gateway", zap.Error(err)) - return err - } - - // wait for detect leader if it's bootstrap - if bootstrap { - timeout := 60 * time.Second - if err := raftServer.WaitForDetectLeader(timeout); err != nil { - if err == errors.ErrTimeout { - logger.Error("leader detection timed out", zap.Duration("timeout", timeout), zap.Error(err)) - } else { - logger.Error("failed to detect leader", zap.Error(err)) - } - return err - } - } - - // create gRPC client for joining node - var joinAddr string - if bootstrap { - joinAddr = grpcAddr - } else { - joinAddr = peerGrpcAddr - } - - c, err := client.NewGRPCClientWithContextTLS(joinAddr, context.Background(), certFile, certHostname) - if err != nil { - logger.Error("failed to create gRPC client", zap.String("addr", joinAddr), zap.Error(err)) - return err - } - defer func() { - _ = c.Close() - }() - - // join this node to the existing cluster - joinRequest := &protobuf.JoinRequest{ - Id: nodeId, - Node: &protobuf.Node{ - BindAddr: bindAddr, - Metadata: &protobuf.Metadata{ - GrpcAddr: grpcAddr, - HttpAddr: httpAddr, - }, - }, - } - if err = c.Join(joinRequest); err != nil { - logger.Error("failed to join node to the cluster", zap.Any("req", joinRequest), zap.Error(err)) - return err - } - - // wait for receiving signal - <-quitCh - - if err := grpcGateway.Stop(); err != nil { - logger.Error("failed to stop gRPC gateway", zap.Error(err)) - } - - if err := grpcServer.Stop(); err != nil { - logger.Error("failed to stop gRPC server", zap.Error(err)) - } - - if err := raftServer.Stop(); err != nil { - logger.Error("failed to stop Raft server", zap.Error(err)) - } - - return nil -} diff --git a/cmd/cete/watch.go b/cmd/cete/watch.go deleted file mode 100644 index c0a52f5..0000000 --- a/cmd/cete/watch.go +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (c) 2020 Minoru Osuka -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "fmt" - "io" - "os" - "os/signal" - "syscall" - - "github.com/golang/protobuf/ptypes/empty" - "github.com/mosuka/cete/client" - "github.com/mosuka/cete/marshaler" - "github.com/mosuka/cete/protobuf" - "github.com/urfave/cli" -) - -func execWatch(ctx *cli.Context) error { - grpcAddr := ctx.String("grpc-addr") - certFile := ctx.String("cert-file") - certHostname := ctx.String("cert-hostname") - - c, err := client.NewGRPCClientWithContextTLS(grpcAddr, context.Background(), certFile, certHostname) - if err != nil { - return err - } - defer func() { - _ = c.Close() - }() - - req := &empty.Empty{} - watchClient, err := c.Watch(req) - if err != nil { - return err - } - - go func() { - for { - resp, err := watchClient.Recv() - if err == io.EOF { - break - } - if err != nil { - break - } - - switch resp.Event.Type { - case protobuf.Event_Join: - eventReq := &protobuf.SetMetadataRequest{} - if eventData, err := marshaler.MarshalAny(resp.Event.Data); err != nil { - _, _ = fmt.Fprintln(os.Stderr, fmt.Sprintf("%s, %v", resp.Event.Type.String(), err)) - } else { - if eventData == nil { - _, _ = fmt.Fprintln(os.Stderr, fmt.Sprintf("%s, nil", resp.Event.Type.String())) - } else { - eventReq = eventData.(*protobuf.SetMetadataRequest) - } - } - _, _ = fmt.Fprintln(os.Stdout, fmt.Sprintf("%s, %v", resp.Event.Type.String(), eventReq)) - case protobuf.Event_Leave: - eventReq := &protobuf.DeleteMetadataRequest{} - if eventData, err := marshaler.MarshalAny(resp.Event.Data); err != nil { - _, _ = fmt.Fprintln(os.Stderr, fmt.Sprintf("%s, %v", resp.Event.Type.String(), err)) - } else { - if eventData == nil { - _, _ = fmt.Fprintln(os.Stderr, fmt.Sprintf("%s, nil", resp.Event.Type.String())) - } else { - eventReq = eventData.(*protobuf.DeleteMetadataRequest) - } - } - _, _ = fmt.Fprintln(os.Stdout, fmt.Sprintf("%s, %v", resp.Event.Type.String(), eventReq)) - case protobuf.Event_Set: - putRequest := &protobuf.SetRequest{} - if putRequestInstance, err := marshaler.MarshalAny(resp.Event.Data); err != nil { - _, _ = fmt.Fprintln(os.Stderr, fmt.Sprintf("%s, %v", resp.Event.Type.String(), err)) - } else { - if putRequestInstance == nil { - _, _ = fmt.Fprintln(os.Stderr, fmt.Sprintf("%s, nil", resp.Event.Type.String())) - } else { - putRequest = putRequestInstance.(*protobuf.SetRequest) - } - } - _, _ = fmt.Fprintln(os.Stdout, fmt.Sprintf("%s, %v", resp.Event.Type.String(), putRequest)) - case protobuf.Event_Delete: - deleteRequest := &protobuf.DeleteRequest{} - if deleteRequestInstance, err := marshaler.MarshalAny(resp.Event.Data); err != nil { - _, _ = fmt.Fprintln(os.Stderr, fmt.Sprintf("%s, %v", resp.Event.Type.String(), err)) - } else { - if deleteRequestInstance == nil { - _, _ = fmt.Fprintln(os.Stderr, fmt.Sprintf("%s, nil", resp.Event.Type.String())) - } else { - deleteRequest = deleteRequestInstance.(*protobuf.DeleteRequest) - } - } - _, _ = fmt.Fprintln(os.Stdout, fmt.Sprintf("%s, %v", resp.Event.Type.String(), deleteRequest)) - } - } - }() - - quitCh := make(chan os.Signal, 1) - signal.Notify(quitCh, os.Kill, os.Interrupt, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) - - <-quitCh - - return nil -} diff --git a/cmd/cluster.go b/cmd/cluster.go new file mode 100644 index 0000000..f5b896d --- /dev/null +++ b/cmd/cluster.go @@ -0,0 +1,92 @@ +package cmd + +import ( + "context" + "encoding/json" + "fmt" + "os" + + "github.com/mitchellh/go-homedir" + "github.com/mosuka/cete/client" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var ( + clusterCmd = &cobra.Command{ + Use: "cluster", + Short: "Get the cluster info", + Long: "Get the cluster info", + RunE: func(cmd *cobra.Command, args []string) error { + grpcAddress = viper.GetString("grpc_address") + + certificateFile = viper.GetString("certificate_file") + commonName = viper.GetString("common_name") + + c, err := client.NewGRPCClientWithContextTLS(grpcAddress, context.Background(), certificateFile, commonName) + if err != nil { + return err + } + defer func() { + _ = c.Close() + }() + + resp, err := c.Cluster() + if err != nil { + return err + } + + respBytes, err := json.Marshal(resp) + if err != nil { + return err + } + + fmt.Println(string(respBytes)) + + return nil + }, + } +) + +func init() { + rootCmd.AddCommand(clusterCmd) + + cobra.OnInitialize(func() { + if configFile != "" { + viper.SetConfigFile(configFile) + } else { + home, err := homedir.Dir() + if err != nil { + _, _ = fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + viper.AddConfigPath("/etc") + viper.AddConfigPath(home) + viper.SetConfigName("cete") + + } + + viper.SetEnvPrefix("CETE") + viper.AutomaticEnv() + + if err := viper.ReadInConfig(); err != nil { + switch err.(type) { + case viper.ConfigFileNotFoundError: + // cete.yaml does not found in config search path + default: + _, _ = fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + } + }) + + clusterCmd.PersistentFlags().StringVar(&configFile, "config-file", "", "config file. if omitted, cete.yaml in /etc and home directory will be searched") + clusterCmd.PersistentFlags().StringVar(&grpcAddress, "grpc-address", ":9000", "gRPC server listen address") + clusterCmd.PersistentFlags().StringVar(&certificateFile, "certificate-file", "", "path to the client server TLS certificate file") + clusterCmd.PersistentFlags().StringVar(&commonName, "common-name", "", "certificate common name") + + _ = viper.BindPFlag("grpc_address", clusterCmd.PersistentFlags().Lookup("grpc-address")) + _ = viper.BindPFlag("certificate_file", clusterCmd.PersistentFlags().Lookup("certificate-file")) + _ = viper.BindPFlag("common_name", clusterCmd.PersistentFlags().Lookup("common-name")) +} diff --git a/cmd/delete.go b/cmd/delete.go new file mode 100644 index 0000000..d58b2b0 --- /dev/null +++ b/cmd/delete.go @@ -0,0 +1,91 @@ +package cmd + +import ( + "context" + "fmt" + "os" + + "github.com/mitchellh/go-homedir" + "github.com/mosuka/cete/client" + "github.com/mosuka/cete/protobuf" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var ( + deleteCmd = &cobra.Command{ + Use: "delete KEY", + Args: cobra.ExactArgs(1), + Short: "Delete a key-value", + Long: "Delete a key-value", + RunE: func(cmd *cobra.Command, args []string) error { + grpcAddress = viper.GetString("grpc_address") + + certificateFile = viper.GetString("certificate_file") + commonName = viper.GetString("common_name") + + key := args[0] + + c, err := client.NewGRPCClientWithContextTLS(grpcAddress, context.Background(), certificateFile, commonName) + if err != nil { + return err + } + defer func() { + _ = c.Close() + }() + + req := &protobuf.DeleteRequest{ + Key: key, + } + + if err := c.Delete(req); err != nil { + return err + } + + return nil + }, + } +) + +func init() { + rootCmd.AddCommand(deleteCmd) + + cobra.OnInitialize(func() { + if configFile != "" { + viper.SetConfigFile(configFile) + } else { + home, err := homedir.Dir() + if err != nil { + _, _ = fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + viper.AddConfigPath("/etc") + viper.AddConfigPath(home) + viper.SetConfigName("cete") + + } + + viper.SetEnvPrefix("CETE") + viper.AutomaticEnv() + + if err := viper.ReadInConfig(); err != nil { + switch err.(type) { + case viper.ConfigFileNotFoundError: + // cete.yaml does not found in config search path + default: + _, _ = fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + } + }) + + deleteCmd.PersistentFlags().StringVar(&configFile, "config-file", "", "config file. if omitted, cete.yaml in /etc and home directory will be searched") + deleteCmd.PersistentFlags().StringVar(&grpcAddress, "grpc-address", ":9000", "gRPC server listen address") + deleteCmd.PersistentFlags().StringVar(&certificateFile, "certificate-file", "", "path to the client server TLS certificate file") + deleteCmd.PersistentFlags().StringVar(&commonName, "common-name", "", "certificate common name") + + _ = viper.BindPFlag("grpc_address", deleteCmd.PersistentFlags().Lookup("grpc-address")) + _ = viper.BindPFlag("certificate_file", deleteCmd.PersistentFlags().Lookup("certificate-file")) + _ = viper.BindPFlag("common_name", deleteCmd.PersistentFlags().Lookup("common-name")) +} diff --git a/cmd/get.go b/cmd/get.go new file mode 100644 index 0000000..d92566e --- /dev/null +++ b/cmd/get.go @@ -0,0 +1,94 @@ +package cmd + +import ( + "context" + "fmt" + "os" + + "github.com/mitchellh/go-homedir" + "github.com/mosuka/cete/client" + "github.com/mosuka/cete/protobuf" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var ( + getCmd = &cobra.Command{ + Use: "get KEY", + Args: cobra.ExactArgs(1), + Short: "Get a key-value", + Long: "Get a key-value", + RunE: func(cmd *cobra.Command, args []string) error { + grpcAddress = viper.GetString("grpc_address") + + certificateFile = viper.GetString("certificate_file") + commonName = viper.GetString("common_name") + + key := args[0] + + c, err := client.NewGRPCClientWithContextTLS(grpcAddress, context.Background(), certificateFile, commonName) + if err != nil { + return err + } + defer func() { + _ = c.Close() + }() + + req := &protobuf.GetRequest{ + Key: key, + } + + resp, err := c.Get(req) + if err != nil { + return err + } + + fmt.Println(string(resp.Value)) + + return nil + }, + } +) + +func init() { + rootCmd.AddCommand(getCmd) + + cobra.OnInitialize(func() { + if configFile != "" { + viper.SetConfigFile(configFile) + } else { + home, err := homedir.Dir() + if err != nil { + _, _ = fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + viper.AddConfigPath("/etc") + viper.AddConfigPath(home) + viper.SetConfigName("cete") + + } + + viper.SetEnvPrefix("CETE") + viper.AutomaticEnv() + + if err := viper.ReadInConfig(); err != nil { + switch err.(type) { + case viper.ConfigFileNotFoundError: + // cete.yaml does not found in config search path + default: + _, _ = fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + } + }) + + getCmd.PersistentFlags().StringVar(&configFile, "config-file", "", "config file. if omitted, cete.yaml in /etc and home directory will be searched") + getCmd.PersistentFlags().StringVar(&grpcAddress, "grpc-address", ":9000", "gRPC server listen address") + getCmd.PersistentFlags().StringVar(&certificateFile, "certificate-file", "", "path to the client server TLS certificate file") + getCmd.PersistentFlags().StringVar(&commonName, "common-name", "", "certificate common name") + + _ = viper.BindPFlag("grpc_address", getCmd.PersistentFlags().Lookup("grpc-address")) + _ = viper.BindPFlag("certificate_file", getCmd.PersistentFlags().Lookup("certificate-file")) + _ = viper.BindPFlag("common_name", getCmd.PersistentFlags().Lookup("common-name")) +} diff --git a/cmd/join.go b/cmd/join.go new file mode 100644 index 0000000..d8955da --- /dev/null +++ b/cmd/join.go @@ -0,0 +1,106 @@ +package cmd + +import ( + "context" + "fmt" + "os" + + "github.com/mitchellh/go-homedir" + "github.com/mosuka/cete/client" + "github.com/mosuka/cete/protobuf" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var ( + joinCmd = &cobra.Command{ + Use: "join ID GRPC_ADDRESS", + Args: cobra.ExactArgs(2), + Short: "Join a node to the cluster", + Long: "Join a node to the cluster", + RunE: func(cmd *cobra.Command, args []string) error { + grpcAddress = viper.GetString("grpc_address") + + certificateFile = viper.GetString("certificate_file") + commonName = viper.GetString("common_name") + + id := args[0] + targetGrpcAddress := args[1] + + t, err := client.NewGRPCClientWithContextTLS(targetGrpcAddress, context.Background(), certificateFile, commonName) + if err != nil { + return err + } + defer func() { + _ = t.Close() + }() + + nodeResp, err := t.Node() + if err != nil { + return err + } + + c, err := client.NewGRPCClientWithContextTLS(grpcAddress, context.Background(), certificateFile, commonName) + if err != nil { + return err + } + defer func() { + _ = c.Close() + }() + + req := &protobuf.JoinRequest{ + Id: id, + Node: nodeResp.Node, + } + + if err := c.Join(req); err != nil { + return err + } + + return nil + }, + } +) + +func init() { + rootCmd.AddCommand(joinCmd) + + cobra.OnInitialize(func() { + if configFile != "" { + viper.SetConfigFile(configFile) + } else { + home, err := homedir.Dir() + if err != nil { + _, _ = fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + viper.AddConfigPath("/etc") + viper.AddConfigPath(home) + viper.SetConfigName("cete") + + } + + viper.SetEnvPrefix("CETE") + viper.AutomaticEnv() + + if err := viper.ReadInConfig(); err != nil { + switch err.(type) { + case viper.ConfigFileNotFoundError: + // cete.yaml does not found in config search path + default: + _, _ = fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + } + }) + + joinCmd.PersistentFlags().StringVar(&configFile, "config-file", "", "config file. if omitted, cete.yaml in /etc and home directory will be searched") + joinCmd.PersistentFlags().StringVar(&grpcAddress, "grpc-address", ":9000", "gRPC server listen address") + joinCmd.PersistentFlags().StringVar(&certificateFile, "certificate-file", "", "path to the client server TLS certificate file") + joinCmd.PersistentFlags().StringVar(&commonName, "common-name", "", "certificate common name") + + _ = viper.BindPFlag("grpc_address", joinCmd.PersistentFlags().Lookup("grpc-address")) + _ = viper.BindPFlag("certificate_file", joinCmd.PersistentFlags().Lookup("certificate-file")) + _ = viper.BindPFlag("common_name", joinCmd.PersistentFlags().Lookup("common-name")) +} diff --git a/cmd/leave.go b/cmd/leave.go new file mode 100644 index 0000000..4c2219f --- /dev/null +++ b/cmd/leave.go @@ -0,0 +1,91 @@ +package cmd + +import ( + "context" + "fmt" + "os" + + "github.com/mitchellh/go-homedir" + "github.com/mosuka/cete/client" + "github.com/mosuka/cete/protobuf" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var ( + leaveCmd = &cobra.Command{ + Use: "leave ID", + Args: cobra.ExactArgs(1), + Short: "Leave a node from the cluster", + Long: "Leave a node from the cluster", + RunE: func(cmd *cobra.Command, args []string) error { + grpcAddress = viper.GetString("grpc_address") + + certificateFile = viper.GetString("certificate_file") + commonName = viper.GetString("common_name") + + id := args[0] + + c, err := client.NewGRPCClientWithContextTLS(grpcAddress, context.Background(), certificateFile, commonName) + if err != nil { + return err + } + defer func() { + _ = c.Close() + }() + + req := &protobuf.LeaveRequest{ + Id: id, + } + + if err := c.Leave(req); err != nil { + return err + } + + return nil + }, + } +) + +func init() { + rootCmd.AddCommand(leaveCmd) + + cobra.OnInitialize(func() { + if configFile != "" { + viper.SetConfigFile(configFile) + } else { + home, err := homedir.Dir() + if err != nil { + _, _ = fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + viper.AddConfigPath("/etc") + viper.AddConfigPath(home) + viper.SetConfigName("cete") + + } + + viper.SetEnvPrefix("CETE") + viper.AutomaticEnv() + + if err := viper.ReadInConfig(); err != nil { + switch err.(type) { + case viper.ConfigFileNotFoundError: + // cete.yaml does not found in config search path + default: + _, _ = fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + } + }) + + leaveCmd.PersistentFlags().StringVar(&configFile, "config-file", "", "config file. if omitted, cete.yaml in /etc and home directory will be searched") + leaveCmd.PersistentFlags().StringVar(&grpcAddress, "grpc-address", ":9000", "gRPC server listen address") + leaveCmd.PersistentFlags().StringVar(&certificateFile, "certificate-file", "", "path to the client server TLS certificate file") + leaveCmd.PersistentFlags().StringVar(&commonName, "common-name", "", "certificate common name") + + _ = viper.BindPFlag("grpc_address", leaveCmd.PersistentFlags().Lookup("grpc-address")) + _ = viper.BindPFlag("certificate_file", leaveCmd.PersistentFlags().Lookup("certificate-file")) + _ = viper.BindPFlag("common_name", leaveCmd.PersistentFlags().Lookup("common-name")) +} diff --git a/cmd/metrics.go b/cmd/metrics.go new file mode 100644 index 0000000..c043022 --- /dev/null +++ b/cmd/metrics.go @@ -0,0 +1,86 @@ +package cmd + +import ( + "context" + "fmt" + "os" + + "github.com/mitchellh/go-homedir" + "github.com/mosuka/cete/client" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var ( + metricsCmd = &cobra.Command{ + Use: "metrics", + Short: "Get the node metrics", + Long: "Get the node metrics in Prometheus exposition format", + RunE: func(cmd *cobra.Command, args []string) error { + grpcAddress = viper.GetString("grpc_address") + + certificateFile = viper.GetString("certificate_file") + commonName = viper.GetString("common_name") + + c, err := client.NewGRPCClientWithContextTLS(grpcAddress, context.Background(), certificateFile, commonName) + if err != nil { + return err + } + defer func() { + _ = c.Close() + }() + + resp, err := c.Metrics() + if err != nil { + return err + } + + fmt.Println(string(resp.Metrics)) + + return nil + }, + } +) + +func init() { + rootCmd.AddCommand(metricsCmd) + + cobra.OnInitialize(func() { + if configFile != "" { + viper.SetConfigFile(configFile) + } else { + home, err := homedir.Dir() + if err != nil { + _, _ = fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + viper.AddConfigPath("/etc") + viper.AddConfigPath(home) + viper.SetConfigName("cete") + + } + + viper.SetEnvPrefix("CETE") + viper.AutomaticEnv() + + if err := viper.ReadInConfig(); err != nil { + switch err.(type) { + case viper.ConfigFileNotFoundError: + // cete.yaml does not found in config search path + default: + _, _ = fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + } + }) + + metricsCmd.PersistentFlags().StringVar(&configFile, "config-file", "", "config file. if omitted, cete.yaml in /etc and home directory will be searched") + metricsCmd.PersistentFlags().StringVar(&grpcAddress, "grpc-address", ":9000", "gRPC server listen address") + metricsCmd.PersistentFlags().StringVar(&certificateFile, "certificate-file", "", "path to the client server TLS certificate file") + metricsCmd.PersistentFlags().StringVar(&commonName, "common-name", "", "certificate common name") + + _ = viper.BindPFlag("grpc_address", metricsCmd.PersistentFlags().Lookup("grpc-address")) + _ = viper.BindPFlag("certificate_file", metricsCmd.PersistentFlags().Lookup("certificate-file")) + _ = viper.BindPFlag("common_name", metricsCmd.PersistentFlags().Lookup("common-name")) +} diff --git a/cmd/node.go b/cmd/node.go new file mode 100644 index 0000000..edb954c --- /dev/null +++ b/cmd/node.go @@ -0,0 +1,92 @@ +package cmd + +import ( + "context" + "encoding/json" + "fmt" + "os" + + "github.com/mitchellh/go-homedir" + "github.com/mosuka/cete/client" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var ( + nodeCmd = &cobra.Command{ + Use: "node", + Short: "Get the node info", + Long: "Get the node info", + RunE: func(cmd *cobra.Command, args []string) error { + grpcAddress = viper.GetString("grpc_address") + + certificateFile = viper.GetString("certificate_file") + commonName = viper.GetString("common_name") + + c, err := client.NewGRPCClientWithContextTLS(grpcAddress, context.Background(), certificateFile, commonName) + if err != nil { + return err + } + defer func() { + _ = c.Close() + }() + + resp, err := c.Node() + if err != nil { + return err + } + + respBytes, err := json.Marshal(resp) + if err != nil { + return err + } + + fmt.Println(string(respBytes)) + + return nil + }, + } +) + +func init() { + rootCmd.AddCommand(nodeCmd) + + cobra.OnInitialize(func() { + if configFile != "" { + viper.SetConfigFile(configFile) + } else { + home, err := homedir.Dir() + if err != nil { + _, _ = fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + viper.AddConfigPath("/etc") + viper.AddConfigPath(home) + viper.SetConfigName("cete") + + } + + viper.SetEnvPrefix("CETE") + viper.AutomaticEnv() + + if err := viper.ReadInConfig(); err != nil { + switch err.(type) { + case viper.ConfigFileNotFoundError: + // cete.yaml does not found in config search path + default: + _, _ = fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + } + }) + + nodeCmd.PersistentFlags().StringVar(&configFile, "config-file", "", "config file. if omitted, cete.yaml in /etc and home directory will be searched") + nodeCmd.PersistentFlags().StringVar(&grpcAddress, "grpc-address", ":9000", "gRPC server listen address") + nodeCmd.PersistentFlags().StringVar(&certificateFile, "certificate-file", "", "path to the client server TLS certificate file") + nodeCmd.PersistentFlags().StringVar(&commonName, "common-name", "", "certificate common name") + + _ = viper.BindPFlag("grpc_address", nodeCmd.PersistentFlags().Lookup("grpc-address")) + _ = viper.BindPFlag("certificate_file", nodeCmd.PersistentFlags().Lookup("certificate-file")) + _ = viper.BindPFlag("common_name", nodeCmd.PersistentFlags().Lookup("common-name")) +} diff --git a/cmd/root.go b/cmd/root.go new file mode 100644 index 0000000..038f047 --- /dev/null +++ b/cmd/root.go @@ -0,0 +1,17 @@ +package cmd + +import ( + "github.com/spf13/cobra" +) + +var ( + rootCmd = &cobra.Command{ + Use: "cete", + Short: "The lightweight distributed key value store server", + Long: "The lightweight distributed key value store server", + } +) + +func Execute() error { + return rootCmd.Execute() +} diff --git a/cmd/set.go b/cmd/set.go new file mode 100644 index 0000000..d145f67 --- /dev/null +++ b/cmd/set.go @@ -0,0 +1,93 @@ +package cmd + +import ( + "context" + "fmt" + "os" + + "github.com/mitchellh/go-homedir" + "github.com/mosuka/cete/client" + "github.com/mosuka/cete/protobuf" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var ( + setCmd = &cobra.Command{ + Use: "set KEY VALUE", + Args: cobra.ExactArgs(2), + Short: "Set a key-value", + Long: "Set a key-value", + RunE: func(cmd *cobra.Command, args []string) error { + grpcAddress = viper.GetString("grpc_address") + + certificateFile = viper.GetString("certificate_file") + commonName = viper.GetString("common_name") + + key := args[0] + value := args[1] + + c, err := client.NewGRPCClientWithContextTLS(grpcAddress, context.Background(), certificateFile, commonName) + if err != nil { + return err + } + defer func() { + _ = c.Close() + }() + + req := &protobuf.SetRequest{ + Key: key, + Value: []byte(value), + } + + if err := c.Set(req); err != nil { + return err + } + + return nil + }, + } +) + +func init() { + rootCmd.AddCommand(setCmd) + + cobra.OnInitialize(func() { + if configFile != "" { + viper.SetConfigFile(configFile) + } else { + home, err := homedir.Dir() + if err != nil { + _, _ = fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + viper.AddConfigPath("/etc") + viper.AddConfigPath(home) + viper.SetConfigName("cete") + + } + + viper.SetEnvPrefix("CETE") + viper.AutomaticEnv() + + if err := viper.ReadInConfig(); err != nil { + switch err.(type) { + case viper.ConfigFileNotFoundError: + // cete.yaml does not found in config search path + default: + _, _ = fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + } + }) + + setCmd.PersistentFlags().StringVar(&configFile, "config-file", "", "config file. if omitted, cete.yaml in /etc and home directory will be searched") + setCmd.PersistentFlags().StringVar(&grpcAddress, "grpc-address", ":9000", "gRPC server listen address") + setCmd.PersistentFlags().StringVar(&certificateFile, "certificate-file", "", "path to the client server TLS certificate file") + setCmd.PersistentFlags().StringVar(&commonName, "common-name", "", "certificate common name") + + _ = viper.BindPFlag("grpc_address", setCmd.PersistentFlags().Lookup("grpc-address")) + _ = viper.BindPFlag("certificate_file", setCmd.PersistentFlags().Lookup("certificate-file")) + _ = viper.BindPFlag("common_name", setCmd.PersistentFlags().Lookup("common-name")) +} diff --git a/cmd/snapshot.go b/cmd/snapshot.go new file mode 100644 index 0000000..99d6037 --- /dev/null +++ b/cmd/snapshot.go @@ -0,0 +1,83 @@ +package cmd + +import ( + "context" + "fmt" + "os" + + "github.com/mitchellh/go-homedir" + "github.com/mosuka/cete/client" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var ( + snapshotCmd = &cobra.Command{ + Use: "snapshot", + Short: "Create a snapshot", + Long: "Create a snapshot which is full-volume copy of data stored on the node", + RunE: func(cmd *cobra.Command, args []string) error { + grpcAddress = viper.GetString("grpc_address") + + certificateFile = viper.GetString("certificate_file") + commonName = viper.GetString("common_name") + + c, err := client.NewGRPCClientWithContextTLS(grpcAddress, context.Background(), certificateFile, commonName) + if err != nil { + return err + } + defer func() { + _ = c.Close() + }() + + if err := c.Snapshot(); err != nil { + return err + } + + return nil + }, + } +) + +func init() { + rootCmd.AddCommand(snapshotCmd) + + cobra.OnInitialize(func() { + if configFile != "" { + viper.SetConfigFile(configFile) + } else { + home, err := homedir.Dir() + if err != nil { + _, _ = fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + viper.AddConfigPath("/etc") + viper.AddConfigPath(home) + viper.SetConfigName("cete") + + } + + viper.SetEnvPrefix("CETE") + viper.AutomaticEnv() + + if err := viper.ReadInConfig(); err != nil { + switch err.(type) { + case viper.ConfigFileNotFoundError: + // cete.yaml does not found in config search path + default: + _, _ = fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + } + }) + + snapshotCmd.PersistentFlags().StringVar(&configFile, "config-file", "", "config file. if omitted, cete.yaml in /etc and home directory will be searched") + snapshotCmd.PersistentFlags().StringVar(&grpcAddress, "grpc-address", ":9000", "gRPC server listen address") + snapshotCmd.PersistentFlags().StringVar(&certificateFile, "certificate-file", "", "path to the client server TLS certificate file") + snapshotCmd.PersistentFlags().StringVar(&commonName, "common-name", "", "certificate common name") + + _ = viper.BindPFlag("grpc_address", snapshotCmd.PersistentFlags().Lookup("grpc-address")) + _ = viper.BindPFlag("certificate_file", snapshotCmd.PersistentFlags().Lookup("certificate-file")) + _ = viper.BindPFlag("common_name", snapshotCmd.PersistentFlags().Lookup("common-name")) +} diff --git a/cmd/start.go b/cmd/start.go new file mode 100644 index 0000000..1cb2d9d --- /dev/null +++ b/cmd/start.go @@ -0,0 +1,200 @@ +package cmd + +import ( + "context" + "fmt" + "os" + "os/signal" + "syscall" + "time" + + "github.com/mitchellh/go-homedir" + "github.com/mosuka/cete/client" + "github.com/mosuka/cete/log" + "github.com/mosuka/cete/protobuf" + "github.com/mosuka/cete/server" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var ( + startCmd = &cobra.Command{ + Use: "start", + Short: "Start the key value store server", + Long: "Start the key value store server", + RunE: func(cmd *cobra.Command, args []string) error { + id = viper.GetString("id") + raftAddress = viper.GetString("raft_address") + grpcAddress = viper.GetString("grpc_address") + httpAddress = viper.GetString("http_address") + dataDirectory = viper.GetString("data_directory") + peerGrpcAddress = viper.GetString("peer_grpc_address") + + certificateFile = viper.GetString("certificate_file") + keyFile = viper.GetString("key_file") + commonName = viper.GetString("common_name") + + logLevel = viper.GetString("log_level") + logFile = viper.GetString("log_file") + logMaxSize = viper.GetInt("log_max_size") + logMaxBackups = viper.GetInt("log_max_backups") + logMaxAge = viper.GetInt("log_max_age") + logCompress = viper.GetBool("log_compress") + + logger := log.NewLogger( + logLevel, + logFile, + logMaxSize, + logMaxBackups, + logMaxAge, + logCompress, + ) + + bootstrap := peerGrpcAddress == "" || peerGrpcAddress == grpcAddress + + raftServer, err := server.NewRaftServer(id, raftAddress, dataDirectory, bootstrap, logger) + if err != nil { + return err + } + + grpcServer, err := server.NewGRPCServer(grpcAddress, raftServer, certificateFile, keyFile, commonName, logger) + if err != nil { + return err + } + + grpcGateway, err := server.NewGRPCGateway(httpAddress, grpcAddress, certificateFile, keyFile, commonName, logger) + if err != nil { + return err + } + + quitCh := make(chan os.Signal, 1) + signal.Notify(quitCh, os.Kill, os.Interrupt, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) + + if err := raftServer.Start(); err != nil { + return err + } + + if err := grpcServer.Start(); err != nil { + return err + } + + if err := grpcGateway.Start(); err != nil { + return err + } + + // wait for detect leader if it's bootstrap + if bootstrap { + timeout := 60 * time.Second + if err := raftServer.WaitForDetectLeader(timeout); err != nil { + return err + } + } + + // create gRPC client for joining node + var joinGrpcAddress string + if bootstrap { + joinGrpcAddress = grpcAddress + } else { + joinGrpcAddress = peerGrpcAddress + } + + c, err := client.NewGRPCClientWithContextTLS(joinGrpcAddress, context.Background(), certificateFile, commonName) + if err != nil { + return err + } + defer func() { + _ = c.Close() + }() + + // join this node to the existing cluster + joinRequest := &protobuf.JoinRequest{ + Id: id, + Node: &protobuf.Node{ + BindAddr: raftAddress, + Metadata: &protobuf.Metadata{ + GrpcAddr: grpcAddress, + HttpAddr: httpAddress, + }, + }, + } + if err = c.Join(joinRequest); err != nil { + return err + } + + // wait for receiving signal + <-quitCh + + _ = grpcGateway.Stop() + _ = grpcServer.Stop() + _ = raftServer.Stop() + + return nil + }, + } +) + +func init() { + rootCmd.AddCommand(startCmd) + + cobra.OnInitialize(func() { + if configFile != "" { + viper.SetConfigFile(configFile) + } else { + home, err := homedir.Dir() + if err != nil { + _, _ = fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + viper.AddConfigPath("/etc") + viper.AddConfigPath(home) + viper.SetConfigName("cete") + + } + + viper.SetEnvPrefix("CETE") + viper.AutomaticEnv() + + if err := viper.ReadInConfig(); err != nil { + switch err.(type) { + case viper.ConfigFileNotFoundError: + // cete.yaml does not found in config search path + default: + _, _ = fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + } + }) + + startCmd.PersistentFlags().StringVar(&configFile, "config-file", "", "config file. if omitted, cete.yaml in /etc and home directory will be searched") + startCmd.PersistentFlags().StringVar(&id, "id", "node1", "node ID") + startCmd.PersistentFlags().StringVar(&raftAddress, "raft-address", ":7000", "Raft server listen address") + startCmd.PersistentFlags().StringVar(&grpcAddress, "grpc-address", ":9000", "gRPC server listen address") + startCmd.PersistentFlags().StringVar(&httpAddress, "http-address", ":8000", "HTTP server listen address") + startCmd.PersistentFlags().StringVar(&dataDirectory, "data-directory", "./data", "HTTP server listen address") + startCmd.PersistentFlags().StringVar(&peerGrpcAddress, "peer-grpc-address", "", "listen address of the existing gRPC server in the joining cluster") + startCmd.PersistentFlags().StringVar(&certificateFile, "certificate-file", "", "path to the client server TLS certificate file") + startCmd.PersistentFlags().StringVar(&keyFile, "key-file", "", "path to the client server TLS key file") + startCmd.PersistentFlags().StringVar(&commonName, "common-name", "", "certificate common name") + startCmd.PersistentFlags().StringVar(&logLevel, "log-level", "INFO", "log level") + startCmd.PersistentFlags().StringVar(&logFile, "log-file", os.Stderr.Name(), "log file") + startCmd.PersistentFlags().IntVar(&logMaxSize, "log-max-size", 500, "Max size of a log file (megabytes)") + startCmd.PersistentFlags().IntVar(&logMaxBackups, "log-max-backups", 3, "Max backup count of log files") + startCmd.PersistentFlags().IntVar(&logMaxAge, "log-max-age", 30, "Max age of a log file (days)") + startCmd.PersistentFlags().BoolVar(&logCompress, "log-compress", false, "Compress a log file") + + _ = viper.BindPFlag("id", startCmd.PersistentFlags().Lookup("id")) + _ = viper.BindPFlag("raft_address", startCmd.PersistentFlags().Lookup("raft-address")) + _ = viper.BindPFlag("grpc_address", startCmd.PersistentFlags().Lookup("grpc-address")) + _ = viper.BindPFlag("http_address", startCmd.PersistentFlags().Lookup("http-address")) + _ = viper.BindPFlag("data_directory", startCmd.PersistentFlags().Lookup("data-directory")) + _ = viper.BindPFlag("peer_grpc_address", startCmd.PersistentFlags().Lookup("peer-grpc-address")) + _ = viper.BindPFlag("certificate_file", startCmd.PersistentFlags().Lookup("certificate-file")) + _ = viper.BindPFlag("key_file", startCmd.PersistentFlags().Lookup("key-file")) + _ = viper.BindPFlag("common_name", startCmd.PersistentFlags().Lookup("common-name")) + _ = viper.BindPFlag("log_level", startCmd.PersistentFlags().Lookup("log-level")) + _ = viper.BindPFlag("log_max_size", startCmd.PersistentFlags().Lookup("log-max-size")) + _ = viper.BindPFlag("log_max_backups", startCmd.PersistentFlags().Lookup("log-max-backups")) + _ = viper.BindPFlag("log_max_age", startCmd.PersistentFlags().Lookup("log-max-age")) + _ = viper.BindPFlag("log_compress", startCmd.PersistentFlags().Lookup("log-compress")) +} diff --git a/cmd/variables.go b/cmd/variables.go new file mode 100644 index 0000000..4333e6c --- /dev/null +++ b/cmd/variables.go @@ -0,0 +1,20 @@ +package cmd + +var ( + configFile string + id string + raftAddress string + grpcAddress string + httpAddress string + dataDirectory string + peerGrpcAddress string + certificateFile string + keyFile string + commonName string + logLevel string + logFile string + logMaxSize int + logMaxBackups int + logMaxAge int + logCompress bool +) diff --git a/cmd/version.go b/cmd/version.go new file mode 100644 index 0000000..470f564 --- /dev/null +++ b/cmd/version.go @@ -0,0 +1,24 @@ +package cmd + +import ( + "fmt" + + "github.com/mosuka/cete/version" + "github.com/spf13/cobra" +) + +var ( + versionCmd = &cobra.Command{ + Use: "version", + Short: "Print the version number", + Long: "Print the version number", + RunE: func(cmd *cobra.Command, args []string) error { + fmt.Printf("cete version: %s\n", version.Version) + return nil + }, + } +) + +func init() { + rootCmd.AddCommand(versionCmd) +} diff --git a/cmd/watch.go b/cmd/watch.go new file mode 100644 index 0000000..8fdef4a --- /dev/null +++ b/cmd/watch.go @@ -0,0 +1,159 @@ +package cmd + +import ( + "context" + "fmt" + "io" + "os" + "os/signal" + "syscall" + + "github.com/golang/protobuf/ptypes/empty" + "github.com/mitchellh/go-homedir" + "github.com/mosuka/cete/client" + "github.com/mosuka/cete/marshaler" + "github.com/mosuka/cete/protobuf" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var ( + watchCmd = &cobra.Command{ + Use: "watch", + Short: "Watch a node updates", + Long: "Watch a node updates", + RunE: func(cmd *cobra.Command, args []string) error { + grpcAddress = viper.GetString("grpc_address") + + certificateFile = viper.GetString("certificate_file") + commonName = viper.GetString("common_name") + + c, err := client.NewGRPCClientWithContextTLS(grpcAddress, context.Background(), certificateFile, commonName) + if err != nil { + return err + } + defer func() { + _ = c.Close() + }() + + req := &empty.Empty{} + watchClient, err := c.Watch(req) + if err != nil { + return err + } + + go func() { + for { + resp, err := watchClient.Recv() + if err == io.EOF { + break + } + if err != nil { + break + } + + switch resp.Event.Type { + case protobuf.Event_Join: + eventReq := &protobuf.SetMetadataRequest{} + if eventData, err := marshaler.MarshalAny(resp.Event.Data); err != nil { + _, _ = fmt.Fprintln(os.Stderr, fmt.Sprintf("%s, %v", resp.Event.Type.String(), err)) + } else { + if eventData == nil { + _, _ = fmt.Fprintln(os.Stderr, fmt.Sprintf("%s, nil", resp.Event.Type.String())) + } else { + eventReq = eventData.(*protobuf.SetMetadataRequest) + } + } + fmt.Printf("%s, %v\n", resp.Event.Type.String(), eventReq) + case protobuf.Event_Leave: + eventReq := &protobuf.DeleteMetadataRequest{} + if eventData, err := marshaler.MarshalAny(resp.Event.Data); err != nil { + _, _ = fmt.Fprintln(os.Stderr, fmt.Sprintf("%s, %v", resp.Event.Type.String(), err)) + } else { + if eventData == nil { + _, _ = fmt.Fprintln(os.Stderr, fmt.Sprintf("%s, nil", resp.Event.Type.String())) + } else { + eventReq = eventData.(*protobuf.DeleteMetadataRequest) + } + } + fmt.Printf("%s, %v\n", resp.Event.Type.String(), eventReq) + case protobuf.Event_Set: + putRequest := &protobuf.SetRequest{} + if putRequestInstance, err := marshaler.MarshalAny(resp.Event.Data); err != nil { + _, _ = fmt.Fprintln(os.Stderr, fmt.Sprintf("%s, %v", resp.Event.Type.String(), err)) + } else { + if putRequestInstance == nil { + _, _ = fmt.Fprintln(os.Stderr, fmt.Sprintf("%s, nil", resp.Event.Type.String())) + } else { + putRequest = putRequestInstance.(*protobuf.SetRequest) + } + } + fmt.Printf("%s, %v\n", resp.Event.Type.String(), putRequest) + case protobuf.Event_Delete: + deleteRequest := &protobuf.DeleteRequest{} + if deleteRequestInstance, err := marshaler.MarshalAny(resp.Event.Data); err != nil { + _, _ = fmt.Fprintln(os.Stderr, fmt.Sprintf("%s, %v", resp.Event.Type.String(), err)) + } else { + if deleteRequestInstance == nil { + _, _ = fmt.Fprintln(os.Stderr, fmt.Sprintf("%s, nil", resp.Event.Type.String())) + } else { + deleteRequest = deleteRequestInstance.(*protobuf.DeleteRequest) + } + } + fmt.Printf("%s, %v\n", resp.Event.Type.String(), deleteRequest) + } + } + }() + + quitCh := make(chan os.Signal, 1) + signal.Notify(quitCh, os.Kill, os.Interrupt, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) + + <-quitCh + + return nil + }, + } +) + +func init() { + rootCmd.AddCommand(watchCmd) + + cobra.OnInitialize(func() { + if configFile != "" { + viper.SetConfigFile(configFile) + } else { + home, err := homedir.Dir() + if err != nil { + _, _ = fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + viper.AddConfigPath("/etc") + viper.AddConfigPath(home) + viper.SetConfigName("cete") + + } + + viper.SetEnvPrefix("CETE") + viper.AutomaticEnv() + + if err := viper.ReadInConfig(); err != nil { + switch err.(type) { + case viper.ConfigFileNotFoundError: + // cete.yaml does not found in config search path + default: + _, _ = fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + } + }) + + watchCmd.PersistentFlags().StringVar(&configFile, "config-file", "", "config file. if omitted, cete.yaml in /etc and home directory will be searched") + watchCmd.PersistentFlags().StringVar(&grpcAddress, "grpc-address", ":9000", "gRPC server listen address") + watchCmd.PersistentFlags().StringVar(&certificateFile, "certificate-file", "", "path to the client server TLS certificate file") + watchCmd.PersistentFlags().StringVar(&commonName, "common-name", "", "certificate common name") + + _ = viper.BindPFlag("grpc_address", watchCmd.PersistentFlags().Lookup("grpc-address")) + _ = viper.BindPFlag("certificate_file", watchCmd.PersistentFlags().Lookup("certificate-file")) + _ = viper.BindPFlag("common_name", watchCmd.PersistentFlags().Lookup("common-name")) +} diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index bc58fbd..18b36f9 100755 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -1,19 +1,5 @@ #!/bin/sh -# Copyright (c) 2020 Minoru Osuka -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -#set -e +set -e exec "$@" diff --git a/etc/cete.yaml b/etc/cete.yaml new file mode 100644 index 0000000..1ef7d2d --- /dev/null +++ b/etc/cete.yaml @@ -0,0 +1,15 @@ +id: "node1" +raft_address: ":7000" +grpc_address: ":9000" +http_address: ":8000" +data_directory: "/tmp/cete/node1/data" +peer_grpc_address: "" +#certificate_file: "./etc/cete-cert.pem" +#key_file: "./etc/cete-key.pem" +#common_name: "localhost" +log_level: "INFO" +#log_file: "/tmp/cete/node1/cete.log" +#log_max_size: 500 +#log_max_backups: 3 +#log_max_age: 30 +#log_compress: false diff --git a/go.mod b/go.mod index b65dead..c7f67f1 100644 --- a/go.mod +++ b/go.mod @@ -11,10 +11,12 @@ require ( github.com/grpc-ecosystem/grpc-gateway v1.14.3 github.com/hashicorp/raft v1.1.2 github.com/mash/go-accesslog v1.1.0 + github.com/mitchellh/go-homedir v1.1.0 github.com/natefinch/lumberjack v2.0.0+incompatible github.com/prometheus/client_golang v1.5.1 github.com/prometheus/common v0.9.1 - github.com/urfave/cli v1.22.3 + github.com/spf13/cobra v0.0.7 + github.com/spf13/viper v1.4.0 go.uber.org/zap v1.14.1 google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c google.golang.org/grpc v1.28.0 diff --git a/go.sum b/go.sum index faf3d73..151ee60 100644 --- a/go.sum +++ b/go.sum @@ -33,13 +33,16 @@ github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6D github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -48,15 +51,18 @@ github.com/dgraph-io/badger/v2 v2.0.0 h1:Cr05o2TUd2IcLbEY0aGd8mbjm1YyQpy+dswo3Bc github.com/dgraph-io/badger/v2 v2.0.0/go.mod h1:YoRSIp1LmAJ7zH7tZwRvjNMUYLxB4wl3ebYkaIruZ04= github.com/dgraph-io/ristretto v0.0.0-20191025175511-c1f00be0418e h1:aeUNgwup7PnDOBAD1BOKAqzb/W/NksOj6r3dwKKuqfg= github.com/dgraph-io/ristretto v0.0.0-20191025175511-c1f00be0418e/go.mod h1:edzKIzGvqUCMzhTVWbiTSe75zD9Xxq0GtSBtFmaUTZs= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20191112170834-c2139c5d712b h1:SeiGBzKrEtuDddnBABHkp4kq9sBGE9nuYmk6FPTg0zg= github.com/dgryski/go-farm v0.0.0-20191112170834-c2139c5d712b/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -69,6 +75,7 @@ github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -79,16 +86,20 @@ github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.2.0 h1:0IKlLyQ3Hs9nDaiK5cSHAGmcQEIC8l2Ts1u6x5Dfrqg= github.com/grpc-ecosystem/go-grpc-middleware v1.2.0/go.mod h1:mJzapYve32yjrKlk9GbyCZHuPgZsrbyIbyKhSzOpg6s= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.14.3 h1:OCJlWkOUoTnl0neNGlf4fUm3TmbEtguw7vR+nGtnDjY= github.com/grpc-ecosystem/grpc-gateway v1.14.3/go.mod h1:6CwZWGDSPRJidgKAtJVvND6soZe6fT7iteq8wDPdhb0= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= @@ -103,13 +114,16 @@ github.com/hashicorp/go-uuid v1.0.0 h1:RS8zrF7PhGwyNPOtxSClXXj9HA8feRnJzgnI1RJCS github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/raft v1.1.1/go.mod h1:vPAJM8Asw6u8LxC3eJCUZmRP/E4QmUGE1R7g7k8sG/8= github.com/hashicorp/raft v1.1.2 h1:oxEL5DDeurYxLd3UbcY/hccgSPhLLpiBZ1YxtWEq59c= github.com/hashicorp/raft v1.1.2/go.mod h1:vPAJM8Asw6u8LxC3eJCUZmRP/E4QmUGE1R7g7k8sG/8= github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea h1:xykPFhrBAS2J0VBzVa5e80b5ZtYuNQtgXjN40qBZlD4= github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea/go.mod h1:pNv7Wc3ycL6F5oOWn+tPGo2gWD4a5X+yp/ntwdKLjRk= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= @@ -122,12 +136,15 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mash/go-accesslog v1.1.0 h1:y22583qP3s+SePBs6mv8ZTz5D1UffPrSg+WFEW2Rf/c= github.com/mash/go-accesslog v1.1.0/go.mod h1:DAbGQzio0KX16krP/3uouoTPxGbzcPjFAb948zazOgg= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -136,9 +153,11 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM= github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= @@ -148,6 +167,7 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.2 h1:awm861/B8OKDd2I/6o1dy3ra4BamzKhYOiGItCeZ740= github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.5.1 h1:bdHYieyGlH+6OLEk2YQha8THib30KP0/yD0YH9m6xcA= github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= @@ -157,17 +177,22 @@ github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1: github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275 h1:PnBWHBf+6L0jOqq0gIVUe6Yk0/QMZ640k6NvkxcBf+8= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a h1:9a8MnZMP0X2nLJdBg+pBmGgkJlSaKC2KaQmTCk1XDtE= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= @@ -178,15 +203,26 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5I github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v0.0.7 h1:FfTH+vuMXOas8jmfb5/M7dzEYx7LpcLb7a0LPe34uOU= +github.com/spf13/cobra v0.0.7/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -194,11 +230,13 @@ github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/urfave/cli v1.22.3 h1:FpNT6zq26xNpHZy08emi755QwzLPs6Pukqjlc7RfOMU= -github.com/urfave/cli v1.22.3/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -226,9 +264,11 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc h1:a3CU5tJYVj92DY2LaA1kUkrsqD5/3mLDhx2NcNqyW+0= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -243,6 +283,7 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522 h1:Ve1ORMCxvRmSXBwJK+t3Oy+V2vRW2OetUQBq4rJIkZE= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -256,6 +297,7 @@ golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 h1:ywK/j/KkyTHcdyYSZNXGjMwgm golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -277,6 +319,7 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c h1:hrpEMCZ2O7DR5gC1n2AJGVhrwiEjOi35+jxtIuZpTMo= google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= @@ -292,6 +335,8 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/log/log.go b/log/log.go index 8b3d4ff..faf1179 100644 --- a/log/log.go +++ b/log/log.go @@ -1,17 +1,3 @@ -// Copyright (c) 2020 Minoru Osuka -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - package log import ( @@ -44,9 +30,12 @@ func NewLogger(logLevel string, logFilename string, logMaxSize int, logMaxBackup } var ws zapcore.WriteSyncer - if logFilename == "" { + switch logFilename { + case "", os.Stderr.Name(): ws = zapcore.AddSync(os.Stderr) - } else { + case os.Stdout.Name(): + ws = zapcore.AddSync(os.Stdout) + default: ws = zapcore.AddSync( &lumberjack.Logger{ Filename: logFilename, diff --git a/main.go b/main.go new file mode 100644 index 0000000..1b5efd4 --- /dev/null +++ b/main.go @@ -0,0 +1,15 @@ +package main + +import ( + "os" + + "github.com/mosuka/cete/cmd" +) + +func main() { + if err := cmd.Execute(); err != nil { + os.Exit(1) + } + + os.Exit(0) +} diff --git a/marshaler/util_test.go b/marshaler/util_test.go index 8361f36..a2d23cc 100644 --- a/marshaler/util_test.go +++ b/marshaler/util_test.go @@ -1,17 +1,3 @@ -// Copyright (c) 2020 Minoru Osuka -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - package marshaler import ( @@ -60,13 +46,13 @@ func TestMarshalAny(t *testing.T) { t.Errorf("%v", err) } - expectedType = "kvs.Node" + expectedType = "protobuf.Node" actualType = nodeAny.TypeUrl if expectedType != actualType { t.Errorf("expected content to see %s, saw %s", expectedType, actualType) } - expectedValue = []byte(`{"bind_addr":":7000","state":"Leader","metadata":{"grpc_addr":":9000","http_addr":":8000",}}`) + expectedValue = []byte(`{"bind_addr":":7000","metadata":{"grpc_addr":":9000","http_addr":":8000"},"state":"Leader"}`) actualValue = nodeAny.Value if !bytes.Equal(expectedValue, actualValue) { t.Errorf("expected content to see %v, saw %v", expectedValue, actualValue) @@ -99,7 +85,7 @@ func TestUnmarshalAny(t *testing.T) { // raft.Node dataAny = &any.Any{ TypeUrl: "protobuf.Node", - Value: []byte(`{"bind_addr":":7000","state":"Leader","metadata":{"grpc_addr":":9000","http_addr":":8000",}}`), + Value: []byte(`{"bind_addr":":7000","metadata":{"grpc_addr":":9000","http_addr":":8000"},"state":"Leader"}`), } data, err = MarshalAny(dataAny) @@ -108,7 +94,7 @@ func TestUnmarshalAny(t *testing.T) { } node := data.(*protobuf.Node) - if node.BindAddr != ":6060" { + if node.BindAddr != ":7000" { t.Errorf("expected content to see %v, saw %v", ":6060", node.BindAddr) } if node.Metadata.GrpcAddr != ":9000" { From bc61abc58dd00d435c6b7eaf0f2fe6c02e5002e9 Mon Sep 17 00:00:00 2001 From: Minoru Osuka Date: Mon, 30 Mar 2020 16:21:12 +0900 Subject: [PATCH 2/3] Update Makefile --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index fa32ddc..0bdfd55 100644 --- a/Makefile +++ b/Makefile @@ -63,8 +63,8 @@ test: .PHONY: coverage coverage: @echo ">> checking coverage of all packages" - (GO) test -coverprofile=./cover.out -tags="$(BUILD_TAGS)" $(PACKAGES) - (GO) tool cover -html=cover.out -o cover.html + $(GO) test -coverprofile=./cover.out -tags="$(BUILD_TAGS)" $(PACKAGES) + $(GO) tool cover -html=cover.out -o cover.html .PHONY: clean clean: From 4503982ab2d64fdac233f433c4d9a7d541222be9 Mon Sep 17 00:00:00 2001 From: Minoru Osuka Date: Mon, 30 Mar 2020 17:11:34 +0900 Subject: [PATCH 3/3] Update README.md --- README.md | 27 ++++++++++++++++++++++++--- cmd/start.go | 10 +++++----- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index af1b5f6..61dfa1b 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,27 @@ $ make GOOS=linux dist $ make GOOS=darwin dist ``` +## Configure Cete + +| CLI Flag | Environment variable | Configuration File | Description | +| --- | --- | --- | --- | +| --config-file | - | - | config file. if omitted, cete.yaml in /etc and home directory will be searched | +| --id | CETE_ID | id | node ID | +| --raft-address | CETE_RAFT_ADDRESS | raft_address | Raft server listen address | +| --grpc-address | CETE_GRPC_ADDRESS | grpc_address | gRPC server listen address | +| --http-address | CETE_HTTP_ADDRESS | http_address | HTTP server listen address | +| --data-directory | CETE_DATA_DIRECTORY | data_directory | data directory which store the key-value store data and Raft logs | +| --peer-grpc-address | CETE_PEER_GRPC_ADDRESS | peer_grpc_address | listen address of the existing gRPC server in the joining cluster | +| --certificate-file | CETE_CERTIFICATE_FILE | certificate_file | path to the client server TLS certificate file | +| --key-file | CETE_KEY_FILE | key_file | path to the client server TLS key file | +| --common-name | CETE_COMMON_NAME | common_name | certificate common name | +| --log-level | CETE_LOG_LEVEL | log_level | log level | +| --log-file | CETE_LOG_FILE | log_file | log file | +| --log-max-size | CETE_LOG_MAX_SIZE | log_max_size | max size of a log file in megabytes | +| --log-max-backups | CETE_LOG_MAX_BACKUPS | log_max_backups | max backup count of log files | +| --log-max-age | CETE_LOG_MAX_AGE | log_max_age | max age of a log file in days | +| --log-compress | CETE_LOG_COMPRESS | log_compress | compress a log file | + ## Starting Cete node @@ -103,7 +124,7 @@ The result of the above command is: } ``` -### Putting a key-value +## Putting a key-value To put a key-value, execute the following command: @@ -118,7 +139,7 @@ $ curl -X PUT 'http://127.0.0.1:8000/v1/data/1' --data-binary value1 $ curl -X PUT 'http://127.0.0.1:8000/v1/data/2' -H "Content-Type: image/jpeg" --data-binary @/path/to/photo.jpg ``` -### Getting a key-value +## Getting a key-value To get a key-value, execute the following command: @@ -138,7 +159,7 @@ You can see the result. The result of the above command is: value1 ``` -### Deleting a value by key via CLI +## Deleting a key-value Deleting a value by key, execute the following command: diff --git a/cmd/start.go b/cmd/start.go index 1cb2d9d..be40dae 100644 --- a/cmd/start.go +++ b/cmd/start.go @@ -171,17 +171,17 @@ func init() { startCmd.PersistentFlags().StringVar(&raftAddress, "raft-address", ":7000", "Raft server listen address") startCmd.PersistentFlags().StringVar(&grpcAddress, "grpc-address", ":9000", "gRPC server listen address") startCmd.PersistentFlags().StringVar(&httpAddress, "http-address", ":8000", "HTTP server listen address") - startCmd.PersistentFlags().StringVar(&dataDirectory, "data-directory", "./data", "HTTP server listen address") + startCmd.PersistentFlags().StringVar(&dataDirectory, "data-directory", "./data", "data directory which store the key-value store data and Raft logs") startCmd.PersistentFlags().StringVar(&peerGrpcAddress, "peer-grpc-address", "", "listen address of the existing gRPC server in the joining cluster") startCmd.PersistentFlags().StringVar(&certificateFile, "certificate-file", "", "path to the client server TLS certificate file") startCmd.PersistentFlags().StringVar(&keyFile, "key-file", "", "path to the client server TLS key file") startCmd.PersistentFlags().StringVar(&commonName, "common-name", "", "certificate common name") startCmd.PersistentFlags().StringVar(&logLevel, "log-level", "INFO", "log level") startCmd.PersistentFlags().StringVar(&logFile, "log-file", os.Stderr.Name(), "log file") - startCmd.PersistentFlags().IntVar(&logMaxSize, "log-max-size", 500, "Max size of a log file (megabytes)") - startCmd.PersistentFlags().IntVar(&logMaxBackups, "log-max-backups", 3, "Max backup count of log files") - startCmd.PersistentFlags().IntVar(&logMaxAge, "log-max-age", 30, "Max age of a log file (days)") - startCmd.PersistentFlags().BoolVar(&logCompress, "log-compress", false, "Compress a log file") + startCmd.PersistentFlags().IntVar(&logMaxSize, "log-max-size", 500, "max size of a log file in megabytes") + startCmd.PersistentFlags().IntVar(&logMaxBackups, "log-max-backups", 3, "max backup count of log files") + startCmd.PersistentFlags().IntVar(&logMaxAge, "log-max-age", 30, "max age of a log file in days") + startCmd.PersistentFlags().BoolVar(&logCompress, "log-compress", false, "compress a log file") _ = viper.BindPFlag("id", startCmd.PersistentFlags().Lookup("id")) _ = viper.BindPFlag("raft_address", startCmd.PersistentFlags().Lookup("raft-address"))