Merge branch 'release/0.3.2'
This commit is contained in:
commit
7f304476e1
7 changed files with 214 additions and 1 deletions
12
CHANGELOG.md
12
CHANGELOG.md
|
@ -1,6 +1,17 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
This is the changelog for NeoFS Proto
|
This is the changelog for NeoFS Proto
|
||||||
|
|
||||||
|
## [0.3.2] - 2020-02-10
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- gRPC method DumpVars to State service
|
||||||
|
- add method `EncodeVariables` to encode debug variables to JSON (slice of bytes)
|
||||||
|
- increase test coverage for state package
|
||||||
|
|
||||||
|
### Updated
|
||||||
|
- state proto file
|
||||||
|
- documentation for state service and messages
|
||||||
|
|
||||||
## [0.3.1] - 2020-02-07
|
## [0.3.1] - 2020-02-07
|
||||||
### Fixed
|
### Fixed
|
||||||
- bug with `tz.Concat`
|
- bug with `tz.Concat`
|
||||||
|
@ -177,3 +188,4 @@ Initial public release
|
||||||
[0.2.14]: https://github.com/nspcc-dev/neofs-api/compare/v0.2.13...v0.2.14
|
[0.2.14]: https://github.com/nspcc-dev/neofs-api/compare/v0.2.13...v0.2.14
|
||||||
[0.3.0]: https://github.com/nspcc-dev/neofs-api/compare/v0.2.14...v0.3.0
|
[0.3.0]: https://github.com/nspcc-dev/neofs-api/compare/v0.2.14...v0.3.0
|
||||||
[0.3.1]: https://github.com/nspcc-dev/neofs-api/compare/v0.3.0...v0.3.1
|
[0.3.1]: https://github.com/nspcc-dev/neofs-api/compare/v0.3.0...v0.3.1
|
||||||
|
[0.3.2]: https://github.com/nspcc-dev/neofs-api/compare/v0.3.1...v0.3.2
|
||||||
|
|
6
Makefile
6
Makefile
|
@ -14,7 +14,6 @@ deps:
|
||||||
@go mod vendor
|
@go mod vendor
|
||||||
|
|
||||||
@echo "${B}${G}=> Cleanup old files ${R}"
|
@echo "${B}${G}=> Cleanup old files ${R}"
|
||||||
@find . -type f -name '*.pb.go' -not -path './vendor/*' -exec rm {} \;
|
|
||||||
@find . -type f -name '*.proto' -not -path './vendor/*' -not -name '*_test.proto' -exec rm {} \;
|
@find . -type f -name '*.proto' -not -path './vendor/*' -not -name '*_test.proto' -exec rm {} \;
|
||||||
|
|
||||||
@echo "${B}${G}=> NeoFS Proto files ${R}"
|
@echo "${B}${G}=> NeoFS Proto files ${R}"
|
||||||
|
@ -49,6 +48,9 @@ docgen: deps
|
||||||
|
|
||||||
# Regenerate proto files:
|
# Regenerate proto files:
|
||||||
protoc: deps
|
protoc: deps
|
||||||
|
@echo "${B}${G}=> Cleanup old files ${R}"
|
||||||
|
@find . -type f -name '*.pb.go' -not -path './vendor/*' -exec rm {} \;
|
||||||
|
|
||||||
@echo "${B}${G}=> Install specific version for gogo-proto ${R}"
|
@echo "${B}${G}=> Install specific version for gogo-proto ${R}"
|
||||||
@go list -f '{{.Path}}/...@{{.Version}}' -m github.com/gogo/protobuf | xargs go get -v
|
@go list -f '{{.Path}}/...@{{.Version}}' -m github.com/gogo/protobuf | xargs go get -v
|
||||||
@echo "${B}${G}=> Install specific version for protobuf lib ${R}"
|
@echo "${B}${G}=> Install specific version for protobuf lib ${R}"
|
||||||
|
@ -60,3 +62,5 @@ protoc: deps
|
||||||
--proto_path=.:./vendor:/usr/local/include \
|
--proto_path=.:./vendor:/usr/local/include \
|
||||||
--gofast_out=plugins=grpc,paths=source_relative:. $$f; \
|
--gofast_out=plugins=grpc,paths=source_relative:. $$f; \
|
||||||
done
|
done
|
||||||
|
|
||||||
|
update: docgen protoc
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
- Messages
|
- Messages
|
||||||
- [DumpRequest](#state.DumpRequest)
|
- [DumpRequest](#state.DumpRequest)
|
||||||
- [DumpResponse](#state.DumpResponse)
|
- [DumpResponse](#state.DumpResponse)
|
||||||
|
- [DumpVarsRequest](#state.DumpVarsRequest)
|
||||||
|
- [DumpVarsResponse](#state.DumpVarsResponse)
|
||||||
- [HealthRequest](#state.HealthRequest)
|
- [HealthRequest](#state.HealthRequest)
|
||||||
- [HealthResponse](#state.HealthResponse)
|
- [HealthResponse](#state.HealthResponse)
|
||||||
- [MetricsRequest](#state.MetricsRequest)
|
- [MetricsRequest](#state.MetricsRequest)
|
||||||
|
@ -39,6 +41,7 @@ rpc Netmap(NetmapRequest) returns (.bootstrap.SpreadMap);
|
||||||
rpc Metrics(MetricsRequest) returns (MetricsResponse);
|
rpc Metrics(MetricsRequest) returns (MetricsResponse);
|
||||||
rpc HealthCheck(HealthRequest) returns (HealthResponse);
|
rpc HealthCheck(HealthRequest) returns (HealthResponse);
|
||||||
rpc DumpConfig(DumpRequest) returns (DumpResponse);
|
rpc DumpConfig(DumpRequest) returns (DumpResponse);
|
||||||
|
rpc DumpVars(DumpVarsRequest) returns (DumpVarsResponse);
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -73,6 +76,15 @@ The request should be signed.
|
||||||
| Name | Input | Output |
|
| Name | Input | Output |
|
||||||
| ---- | ----- | ------ |
|
| ---- | ----- | ------ |
|
||||||
| DumpConfig | [DumpRequest](#state.DumpRequest) | [DumpResponse](#state.DumpResponse) |
|
| DumpConfig | [DumpRequest](#state.DumpRequest) | [DumpResponse](#state.DumpResponse) |
|
||||||
|
#### Method DumpVars
|
||||||
|
|
||||||
|
DumpVars returns debug variables for the current node.
|
||||||
|
To permit access, used server config options.
|
||||||
|
The request should be signed.
|
||||||
|
|
||||||
|
| Name | Input | Output |
|
||||||
|
| ---- | ----- | ------ |
|
||||||
|
| DumpVars | [DumpVarsRequest](#state.DumpVarsRequest) | [DumpVarsResponse](#state.DumpVarsResponse) |
|
||||||
<!-- end services -->
|
<!-- end services -->
|
||||||
|
|
||||||
|
|
||||||
|
@ -100,6 +112,30 @@ Config stored in JSON encoded into slice of bytes.
|
||||||
| Config | [bytes](#bytes) | | |
|
| Config | [bytes](#bytes) | | |
|
||||||
|
|
||||||
|
|
||||||
|
<a name="state.DumpVarsRequest"></a>
|
||||||
|
|
||||||
|
### Message DumpVarsRequest
|
||||||
|
DumpVarsRequest message to fetch current server debug variables.
|
||||||
|
|
||||||
|
|
||||||
|
| Field | Type | Label | Description |
|
||||||
|
| ----- | ---- | ----- | ----------- |
|
||||||
|
| Meta | [service.RequestMetaHeader](#service.RequestMetaHeader) | | RequestMetaHeader contains information about request meta headers (should be embedded into message) |
|
||||||
|
| Verify | [service.RequestVerificationHeader](#service.RequestVerificationHeader) | | RequestVerificationHeader is a set of signatures of every NeoFS Node that processed request (should be embedded into message) |
|
||||||
|
|
||||||
|
|
||||||
|
<a name="state.DumpVarsResponse"></a>
|
||||||
|
|
||||||
|
### Message DumpVarsResponse
|
||||||
|
DumpVarsResponse message contains current server debug variables.
|
||||||
|
Variables stored in JSON encoded into slice of bytes.
|
||||||
|
|
||||||
|
|
||||||
|
| Field | Type | Label | Description |
|
||||||
|
| ----- | ---- | ----- | ----------- |
|
||||||
|
| Variables | [bytes](#bytes) | | |
|
||||||
|
|
||||||
|
|
||||||
<a name="state.HealthRequest"></a>
|
<a name="state.HealthRequest"></a>
|
||||||
|
|
||||||
### Message HealthRequest
|
### Message HealthRequest
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
package state
|
package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"expvar"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
@ -61,3 +64,25 @@ func EncodeConfig(v *viper.Viper) (*DumpResponse, error) {
|
||||||
|
|
||||||
return &DumpResponse{Config: data}, nil
|
return &DumpResponse{Config: data}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EncodeVariables encodes debug variables into DumpVarsResponse message.
|
||||||
|
// Variables encoded into JSON and stored as slice of bytes.
|
||||||
|
func EncodeVariables() *DumpVarsResponse {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
buf.WriteString("{\n")
|
||||||
|
first := true
|
||||||
|
|
||||||
|
expvar.Do(func(kv expvar.KeyValue) {
|
||||||
|
if !first {
|
||||||
|
buf.WriteString(",\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
first = false
|
||||||
|
|
||||||
|
_, _ = fmt.Fprintf(buf, "%q: %s", kv.Key, kv.Value)
|
||||||
|
})
|
||||||
|
|
||||||
|
buf.WriteString("\n}\n")
|
||||||
|
|
||||||
|
return &DumpVarsResponse{Variables: buf.Bytes()}
|
||||||
|
}
|
||||||
|
|
Binary file not shown.
|
@ -23,6 +23,10 @@ service Status {
|
||||||
// To permit access, used server config options.
|
// To permit access, used server config options.
|
||||||
// The request should be signed.
|
// The request should be signed.
|
||||||
rpc DumpConfig(DumpRequest) returns (DumpResponse);
|
rpc DumpConfig(DumpRequest) returns (DumpResponse);
|
||||||
|
// DumpVars returns debug variables for the current node.
|
||||||
|
// To permit access, used server config options.
|
||||||
|
// The request should be signed.
|
||||||
|
rpc DumpVars(DumpVarsRequest) returns (DumpVarsResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NetmapRequest message to request current node netmap
|
// NetmapRequest message to request current node netmap
|
||||||
|
@ -77,3 +81,17 @@ message DumpRequest {
|
||||||
message DumpResponse {
|
message DumpResponse {
|
||||||
bytes Config = 1;
|
bytes Config = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DumpVarsRequest message to fetch current server debug variables.
|
||||||
|
message DumpVarsRequest {
|
||||||
|
// RequestMetaHeader contains information about request meta headers (should be embedded into message)
|
||||||
|
service.RequestMetaHeader Meta = 98 [(gogoproto.embed) = true, (gogoproto.nullable) = false];
|
||||||
|
// RequestVerificationHeader is a set of signatures of every NeoFS Node that processed request (should be embedded into message)
|
||||||
|
service.RequestVerificationHeader Verify = 99 [(gogoproto.embed) = true, (gogoproto.nullable) = false];
|
||||||
|
}
|
||||||
|
|
||||||
|
// DumpVarsResponse message contains current server debug variables.
|
||||||
|
// Variables stored in JSON encoded into slice of bytes.
|
||||||
|
message DumpVarsResponse {
|
||||||
|
bytes Variables = 1;
|
||||||
|
}
|
||||||
|
|
118
state/service_test.go
Normal file
118
state/service_test.go
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
package state
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"expvar"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
type testCollector struct {
|
||||||
|
testA *prometheus.Desc
|
||||||
|
testB *prometheus.Desc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testCollector) Describe(ch chan<- *prometheus.Desc) {
|
||||||
|
ch <- c.testA
|
||||||
|
ch <- c.testB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testCollector) Collect(ch chan<- prometheus.Metric) {
|
||||||
|
ch <- prometheus.MustNewConstMetric(c.testA, prometheus.GaugeValue, 1, "label_1")
|
||||||
|
ch <- prometheus.MustNewConstMetric(c.testB, prometheus.GaugeValue, 2, "label_2")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEncodeVariables(t *testing.T) {
|
||||||
|
dump := make(map[string]interface{})
|
||||||
|
|
||||||
|
expvar.NewString("test1").Set("test1")
|
||||||
|
expvar.NewString("test2").Set("test2")
|
||||||
|
|
||||||
|
res := EncodeVariables()
|
||||||
|
|
||||||
|
require.NoError(t, json.Unmarshal(res.Variables, &dump))
|
||||||
|
require.NotEmpty(t, dump)
|
||||||
|
|
||||||
|
// dump should contains keys `test1` and `test2`
|
||||||
|
require.Contains(t, dump, "test1")
|
||||||
|
require.Equal(t, "test1", dump["test1"])
|
||||||
|
|
||||||
|
require.Contains(t, dump, "test2")
|
||||||
|
require.Equal(t, "test2", dump["test2"])
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEncodeConfig(t *testing.T) {
|
||||||
|
v := viper.New()
|
||||||
|
v.Set("test1", "test1")
|
||||||
|
v.Set("test2", "test2")
|
||||||
|
|
||||||
|
res, err := EncodeConfig(v)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
dump := make(map[string]interface{})
|
||||||
|
require.NoError(t, json.Unmarshal(res.Config, &dump))
|
||||||
|
|
||||||
|
require.NotEmpty(t, dump)
|
||||||
|
|
||||||
|
require.Contains(t, dump, "test1")
|
||||||
|
require.Equal(t, dump["test1"], "test1")
|
||||||
|
|
||||||
|
require.Contains(t, dump, "test2")
|
||||||
|
require.Equal(t, dump["test2"], "test2")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEncodeAndDecodeMetrics(t *testing.T) {
|
||||||
|
registry := prometheus.NewRegistry()
|
||||||
|
|
||||||
|
collector := &testCollector{
|
||||||
|
testA: prometheus.NewDesc("test1", "test1", []string{"test1"}, prometheus.Labels{"label_1": "test1"}),
|
||||||
|
testB: prometheus.NewDesc("test2", "test2", []string{"test2"}, prometheus.Labels{"label_2": "test2"}),
|
||||||
|
}
|
||||||
|
|
||||||
|
require.NoError(t, registry.Register(collector))
|
||||||
|
|
||||||
|
gather, err := registry.Gather()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
res, err := EncodeMetrics(registry)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
metrics, err := DecodeMetrics(res)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Len(t, metrics, len(gather))
|
||||||
|
|
||||||
|
{ // Check that JSON encoded metrics are equal:
|
||||||
|
expect := new(bytes.Buffer)
|
||||||
|
actual := new(bytes.Buffer)
|
||||||
|
|
||||||
|
require.NoError(t, json.NewEncoder(expect).Encode(gather))
|
||||||
|
require.NoError(t, json.NewEncoder(actual).Encode(metrics))
|
||||||
|
|
||||||
|
require.Equal(t, expect.Bytes(), actual.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // Deep comparison of metrics:
|
||||||
|
for i := range metrics {
|
||||||
|
require.Equal(t, gather[i].Help, metrics[i].Help)
|
||||||
|
require.Equal(t, gather[i].Name, metrics[i].Name)
|
||||||
|
require.Equal(t, gather[i].Type, metrics[i].Type)
|
||||||
|
|
||||||
|
require.Len(t, metrics[i].Metric, len(gather[i].Metric))
|
||||||
|
|
||||||
|
for j := range metrics[i].Metric {
|
||||||
|
require.Equal(t, gather[i].Metric[j].Gauge, metrics[i].Metric[j].Gauge)
|
||||||
|
require.Len(t, metrics[i].Metric[j].Label, len(gather[i].Metric[j].Label))
|
||||||
|
|
||||||
|
for k := range metrics[i].Metric[j].Label {
|
||||||
|
require.Equal(t, gather[i].Metric[j].Label[k].Name, metrics[i].Metric[j].Label[k].Name)
|
||||||
|
require.Equal(t, gather[i].Metric[j].Label[k].Value, metrics[i].Metric[j].Label[k].Value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue