forked from TrueCloudLab/frostfs-api-go
[#233] Implement data audit result type with basic methods
Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
parent
3039aa20c7
commit
9986a4ecd1
9 changed files with 959 additions and 0 deletions
258
pkg/audit/result.go
Normal file
258
pkg/audit/result.go
Normal file
|
@ -0,0 +1,258 @@
|
||||||
|
package audit
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/pkg/container"
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/pkg/object"
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/v2/audit"
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Result represents v2-compatible data audit result.
|
||||||
|
type Result audit.DataAuditResult
|
||||||
|
|
||||||
|
// NewFromV2 wraps v2 DataAuditResult message to Result.
|
||||||
|
func NewResultFromV2(aV2 *audit.DataAuditResult) *Result {
|
||||||
|
return (*Result)(aV2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates and initializes blank Result.
|
||||||
|
func NewResult() *Result {
|
||||||
|
return NewResultFromV2(new(audit.DataAuditResult))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToV2 converts Result to v2 DataAuditResult message.
|
||||||
|
func (r *Result) ToV2() *audit.DataAuditResult {
|
||||||
|
return (*audit.DataAuditResult)(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal marshals Result into a protobuf binary form.
|
||||||
|
//
|
||||||
|
// Buffer is allocated when the argument is empty.
|
||||||
|
// Otherwise, the first buffer is used.
|
||||||
|
func (r *Result) Marshal(b ...[]byte) ([]byte, error) {
|
||||||
|
var buf []byte
|
||||||
|
if len(b) > 0 {
|
||||||
|
buf = b[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
return (*audit.DataAuditResult)(r).
|
||||||
|
StableMarshal(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal unmarshals protobuf binary representation of Result.
|
||||||
|
func (r *Result) Unmarshal(data []byte) error {
|
||||||
|
return (*audit.DataAuditResult)(r).
|
||||||
|
Unmarshal(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON encodes Result to protobuf JSON format.
|
||||||
|
func (r *Result) MarshalJSON() ([]byte, error) {
|
||||||
|
return (*audit.DataAuditResult)(r).
|
||||||
|
MarshalJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON decodes Result from protobuf JSON format.
|
||||||
|
func (r *Result) UnmarshalJSON(data []byte) error {
|
||||||
|
return (*audit.DataAuditResult)(r).
|
||||||
|
UnmarshalJSON(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuditEpoch returns epoch number when the Data Audit was conducted.
|
||||||
|
func (r *Result) AuditEpoch() uint64 {
|
||||||
|
return (*audit.DataAuditResult)(r).
|
||||||
|
GetAuditEpoch()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAuditEpoch sets epoch number when the Data Audit was conducted.
|
||||||
|
func (r *Result) SetAuditEpoch(epoch uint64) {
|
||||||
|
(*audit.DataAuditResult)(r).
|
||||||
|
SetAuditEpoch(epoch)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContainerID returns container under audit.
|
||||||
|
func (r *Result) ContainerID() *container.ID {
|
||||||
|
return container.NewIDFromV2(
|
||||||
|
(*audit.DataAuditResult)(r).
|
||||||
|
GetContainerID(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetContainerID sets container under audit.
|
||||||
|
func (r *Result) SetContainerID(id *container.ID) {
|
||||||
|
(*audit.DataAuditResult)(r).
|
||||||
|
SetContainerID(id.ToV2())
|
||||||
|
}
|
||||||
|
|
||||||
|
// PublicKey returns public key of the auditing InnerRing node in a binary format.
|
||||||
|
func (r *Result) PublicKey() []byte {
|
||||||
|
return (*audit.DataAuditResult)(r).
|
||||||
|
GetPublicKey()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPublicKey sets public key of the auditing InnerRing node in a binary format.
|
||||||
|
func (r *Result) SetPublicKey(key []byte) {
|
||||||
|
(*audit.DataAuditResult)(r).
|
||||||
|
SetPublicKey(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PassSG returns list of Storage Groups that passed audit PoR stage.
|
||||||
|
func (r *Result) PassSG() []*object.ID {
|
||||||
|
mV2 := (*audit.DataAuditResult)(r).
|
||||||
|
GetPassSG()
|
||||||
|
|
||||||
|
if mV2 == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
m := make([]*object.ID, len(mV2))
|
||||||
|
|
||||||
|
for i := range mV2 {
|
||||||
|
m[i] = object.NewIDFromV2(mV2[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPassSG sets list of Storage Groups that passed audit PoR stage.
|
||||||
|
func (r *Result) SetPassSG(list []*object.ID) {
|
||||||
|
mV2 := (*audit.DataAuditResult)(r).
|
||||||
|
GetPassSG()
|
||||||
|
|
||||||
|
if list == nil {
|
||||||
|
mV2 = nil
|
||||||
|
} else {
|
||||||
|
ln := len(list)
|
||||||
|
|
||||||
|
if cap(mV2) >= ln {
|
||||||
|
mV2 = mV2[:0]
|
||||||
|
} else {
|
||||||
|
mV2 = make([]*refs.ObjectID, 0, ln)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < ln; i++ {
|
||||||
|
mV2 = append(mV2, list[i].ToV2())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(*audit.DataAuditResult)(r).
|
||||||
|
SetPassSG(mV2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FailSG returns list of Storage Groups that failed audit PoR stage.
|
||||||
|
func (r *Result) FailSG() []*object.ID {
|
||||||
|
mV2 := (*audit.DataAuditResult)(r).
|
||||||
|
GetFailSG()
|
||||||
|
|
||||||
|
if mV2 == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
m := make([]*object.ID, len(mV2))
|
||||||
|
|
||||||
|
for i := range mV2 {
|
||||||
|
m[i] = object.NewIDFromV2(mV2[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFailSG sets list of Storage Groups that failed audit PoR stage.
|
||||||
|
func (r *Result) SetFailSG(list []*object.ID) {
|
||||||
|
mV2 := (*audit.DataAuditResult)(r).
|
||||||
|
GetFailSG()
|
||||||
|
|
||||||
|
if list == nil {
|
||||||
|
mV2 = nil
|
||||||
|
} else {
|
||||||
|
ln := len(list)
|
||||||
|
|
||||||
|
if cap(mV2) >= ln {
|
||||||
|
mV2 = mV2[:0]
|
||||||
|
} else {
|
||||||
|
mV2 = make([]*refs.ObjectID, 0, ln)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < ln; i++ {
|
||||||
|
mV2 = append(mV2, list[i].ToV2())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(*audit.DataAuditResult)(r).
|
||||||
|
SetFailSG(mV2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hit returns number of sampled objects under audit placed
|
||||||
|
// in an optimal way according to the containers placement policy
|
||||||
|
// when checking PoP.
|
||||||
|
func (r *Result) Hit() uint32 {
|
||||||
|
return (*audit.DataAuditResult)(r).
|
||||||
|
GetHit()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetHit sets number of sampled objects under audit placed
|
||||||
|
// in an optimal way according to the containers placement policy
|
||||||
|
// when checking PoP.
|
||||||
|
func (r *Result) SetHit(hit uint32) {
|
||||||
|
(*audit.DataAuditResult)(r).
|
||||||
|
SetHit(hit)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Miss returns number of sampled objects under audit placed
|
||||||
|
// in suboptimal way according to the containers placement policy,
|
||||||
|
// but still at a satisfactory level when checking PoP.
|
||||||
|
func (r *Result) Miss() uint32 {
|
||||||
|
return (*audit.DataAuditResult)(r).
|
||||||
|
GetMiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMiss sets number of sampled objects under audit placed
|
||||||
|
// in suboptimal way according to the containers placement policy,
|
||||||
|
// but still at a satisfactory level when checking PoP.
|
||||||
|
func (r *Result) SetMiss(miss uint32) {
|
||||||
|
(*audit.DataAuditResult)(r).
|
||||||
|
SetMiss(miss)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fail returns number of sampled objects under audit stored
|
||||||
|
// in a way not confirming placement policy or not found at all
|
||||||
|
// when checking PoP.
|
||||||
|
func (r *Result) Fail() uint32 {
|
||||||
|
return (*audit.DataAuditResult)(r).
|
||||||
|
GetFail()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFail sets number of sampled objects under audit stored
|
||||||
|
// in a way not confirming placement policy or not found at all
|
||||||
|
// when checking PoP.
|
||||||
|
func (r *Result) SetFail(fail uint32) {
|
||||||
|
(*audit.DataAuditResult)(r).
|
||||||
|
SetFail(fail)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PassNodes returns list of storage node public keys that
|
||||||
|
// passed at least one PDP.
|
||||||
|
func (r *Result) PassNodes() [][]byte {
|
||||||
|
return (*audit.DataAuditResult)(r).
|
||||||
|
GetPassNodes()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPassNodes sets list of storage node public keys that
|
||||||
|
// passed at least one PDP.
|
||||||
|
func (r *Result) SetPassNodes(list [][]byte) {
|
||||||
|
(*audit.DataAuditResult)(r).
|
||||||
|
SetPassNodes(list)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FailNodes returns list of storage node public keys that
|
||||||
|
// failed at least one PDP.
|
||||||
|
func (r *Result) FailNodes() [][]byte {
|
||||||
|
return (*audit.DataAuditResult)(r).
|
||||||
|
GetFailNodes()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFailNodes sets list of storage node public keys that
|
||||||
|
// failed at least one PDP.
|
||||||
|
func (r *Result) SetFailNodes(list [][]byte) {
|
||||||
|
(*audit.DataAuditResult)(r).
|
||||||
|
SetFailNodes(list)
|
||||||
|
}
|
109
pkg/audit/result_test.go
Normal file
109
pkg/audit/result_test.go
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
package audit_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/sha256"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/pkg/audit"
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/pkg/container"
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/pkg/object"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func testSHA256() (cs [sha256.Size]byte) {
|
||||||
|
_, _ = rand.Read(cs[:])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func testCID() *container.ID {
|
||||||
|
cid := container.NewID()
|
||||||
|
cid.SetSHA256(testSHA256())
|
||||||
|
|
||||||
|
return cid
|
||||||
|
}
|
||||||
|
|
||||||
|
func testOID() *object.ID {
|
||||||
|
id := object.NewID()
|
||||||
|
id.SetSHA256(testSHA256())
|
||||||
|
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResult(t *testing.T) {
|
||||||
|
r := audit.NewResult()
|
||||||
|
|
||||||
|
epoch := uint64(13)
|
||||||
|
r.SetAuditEpoch(epoch)
|
||||||
|
require.Equal(t, epoch, r.AuditEpoch())
|
||||||
|
|
||||||
|
cid := testCID()
|
||||||
|
r.SetContainerID(cid)
|
||||||
|
require.Equal(t, cid, r.ContainerID())
|
||||||
|
|
||||||
|
key := []byte{1, 2, 3}
|
||||||
|
r.SetPublicKey(key)
|
||||||
|
require.Equal(t, key, r.PublicKey())
|
||||||
|
|
||||||
|
passSG := []*object.ID{testOID(), testOID()}
|
||||||
|
r.SetPassSG(passSG)
|
||||||
|
require.Equal(t, passSG, r.PassSG())
|
||||||
|
|
||||||
|
failSG := []*object.ID{testOID(), testOID()}
|
||||||
|
r.SetFailSG(failSG)
|
||||||
|
require.Equal(t, failSG, r.FailSG())
|
||||||
|
|
||||||
|
hit := uint32(1)
|
||||||
|
r.SetHit(hit)
|
||||||
|
require.Equal(t, hit, r.Hit())
|
||||||
|
|
||||||
|
miss := uint32(2)
|
||||||
|
r.SetMiss(miss)
|
||||||
|
require.Equal(t, miss, r.Miss())
|
||||||
|
|
||||||
|
fail := uint32(3)
|
||||||
|
r.SetFail(fail)
|
||||||
|
require.Equal(t, fail, r.Fail())
|
||||||
|
|
||||||
|
passNodes := [][]byte{{1}, {2}}
|
||||||
|
r.SetPassNodes(passNodes)
|
||||||
|
require.Equal(t, passNodes, r.PassNodes())
|
||||||
|
|
||||||
|
failNodes := [][]byte{{3}, {4}}
|
||||||
|
r.SetFailNodes(failNodes)
|
||||||
|
require.Equal(t, failNodes, r.FailNodes())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStorageGroupEncoding(t *testing.T) {
|
||||||
|
r := audit.NewResult()
|
||||||
|
r.SetAuditEpoch(13)
|
||||||
|
r.SetContainerID(testCID())
|
||||||
|
r.SetPublicKey([]byte{1, 2, 3})
|
||||||
|
r.SetPassSG([]*object.ID{testOID(), testOID()})
|
||||||
|
r.SetFailSG([]*object.ID{testOID(), testOID()})
|
||||||
|
r.SetHit(1)
|
||||||
|
r.SetMiss(2)
|
||||||
|
r.SetFail(3)
|
||||||
|
r.SetPassNodes([][]byte{{1}, {2}})
|
||||||
|
r.SetFailNodes([][]byte{{3}, {4}})
|
||||||
|
|
||||||
|
t.Run("binary", func(t *testing.T) {
|
||||||
|
data, err := r.Marshal()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
r2 := audit.NewResult()
|
||||||
|
require.NoError(t, r2.Unmarshal(data))
|
||||||
|
|
||||||
|
require.Equal(t, r, r2)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("json", func(t *testing.T) {
|
||||||
|
data, err := r.MarshalJSON()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
r2 := audit.NewResult()
|
||||||
|
require.NoError(t, r2.UnmarshalJSON(data))
|
||||||
|
|
||||||
|
require.Equal(t, r, r2)
|
||||||
|
})
|
||||||
|
}
|
76
v2/audit/convert.go
Normal file
76
v2/audit/convert.go
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
package audit
|
||||||
|
|
||||||
|
import (
|
||||||
|
audit "github.com/nspcc-dev/neofs-api-go/v2/audit/grpc"
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DataAuditResultToGRPCMessage converts unified DataAuditResult structure
|
||||||
|
// into gRPC DataAuditResult message.
|
||||||
|
func DataAuditResultToGRPCMessage(a *DataAuditResult) *audit.DataAuditResult {
|
||||||
|
if a == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
m := new(audit.DataAuditResult)
|
||||||
|
|
||||||
|
m.SetAuditEpoch(a.GetAuditEpoch())
|
||||||
|
|
||||||
|
m.SetContainerId(
|
||||||
|
refs.ContainerIDToGRPCMessage(a.GetContainerID()),
|
||||||
|
)
|
||||||
|
|
||||||
|
m.SetPublicKey(a.GetPublicKey())
|
||||||
|
|
||||||
|
m.SetPassSg(
|
||||||
|
refs.ObjectIDListToGRPCMessage(a.GetPassSG()),
|
||||||
|
)
|
||||||
|
|
||||||
|
m.SetFailSg(
|
||||||
|
refs.ObjectIDListToGRPCMessage(a.GetFailSG()),
|
||||||
|
)
|
||||||
|
|
||||||
|
m.SetHit(a.GetHit())
|
||||||
|
m.SetMiss(a.GetMiss())
|
||||||
|
m.SetFail(a.GetFail())
|
||||||
|
|
||||||
|
m.SetPassNodes(a.GetPassNodes())
|
||||||
|
m.SetFailNodes(a.GetFailNodes())
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
// DataAuditResultFromGRPCMessage converts gRPC message DataAuditResult
|
||||||
|
// into unified DataAuditResult structure.
|
||||||
|
func DataAuditResultFromGRPCMessage(m *audit.DataAuditResult) *DataAuditResult {
|
||||||
|
if m == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
a := new(DataAuditResult)
|
||||||
|
|
||||||
|
a.SetAuditEpoch(m.GetAuditEpoch())
|
||||||
|
|
||||||
|
a.SetContainerID(
|
||||||
|
refs.ContainerIDFromGRPCMessage(m.GetContainerId()),
|
||||||
|
)
|
||||||
|
|
||||||
|
a.SetPublicKey(m.GetPublicKey())
|
||||||
|
|
||||||
|
a.SetPassSG(
|
||||||
|
refs.ObjectIDListFromGRPCMessage(m.GetPassSg()),
|
||||||
|
)
|
||||||
|
|
||||||
|
a.SetFailSG(
|
||||||
|
refs.ObjectIDListFromGRPCMessage(m.GetFailSg()),
|
||||||
|
)
|
||||||
|
|
||||||
|
a.SetHit(m.GetHit())
|
||||||
|
a.SetMiss(m.GetMiss())
|
||||||
|
a.SetFail(m.GetFail())
|
||||||
|
|
||||||
|
a.SetPassNodes(m.GetPassNodes())
|
||||||
|
a.SetFailNodes(m.GetFailNodes())
|
||||||
|
|
||||||
|
return a
|
||||||
|
}
|
75
v2/audit/grpc/types.go
Normal file
75
v2/audit/grpc/types.go
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
package audit
|
||||||
|
|
||||||
|
import (
|
||||||
|
refs "github.com/nspcc-dev/neofs-api-go/v2/refs/grpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SetAuditEpoch is an AuditEpoch field setter.
|
||||||
|
func (x *DataAuditResult) SetAuditEpoch(v uint64) {
|
||||||
|
if x != nil {
|
||||||
|
x.AuditEpoch = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetContainerId is a ContainerId field setter.
|
||||||
|
func (x *DataAuditResult) SetContainerId(v *refs.ContainerID) {
|
||||||
|
if x != nil {
|
||||||
|
x.ContainerId = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPublicKey is a PublicKey field setter.
|
||||||
|
func (x *DataAuditResult) SetPublicKey(v []byte) {
|
||||||
|
if x != nil {
|
||||||
|
x.PublicKey = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPassSg is a PassSg field setter.
|
||||||
|
func (x *DataAuditResult) SetPassSg(v []*refs.ObjectID) {
|
||||||
|
if x != nil {
|
||||||
|
x.PassSg = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFailSg is a FailSg field setter.
|
||||||
|
func (x *DataAuditResult) SetFailSg(v []*refs.ObjectID) {
|
||||||
|
if x != nil {
|
||||||
|
x.FailSg = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetHit is a Hit field setter.
|
||||||
|
func (x *DataAuditResult) SetHit(v uint32) {
|
||||||
|
if x != nil {
|
||||||
|
x.Hit = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMiss is a Miss field setter.
|
||||||
|
func (x *DataAuditResult) SetMiss(v uint32) {
|
||||||
|
if x != nil {
|
||||||
|
x.Miss = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFail is a Fail field setter.
|
||||||
|
func (x *DataAuditResult) SetFail(v uint32) {
|
||||||
|
if x != nil {
|
||||||
|
x.Fail = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPassNodes is a PassNodes field setter.
|
||||||
|
func (x *DataAuditResult) SetPassNodes(v [][]byte) {
|
||||||
|
if x != nil {
|
||||||
|
x.PassNodes = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFailNodes is a FailNodes field setter.
|
||||||
|
func (x *DataAuditResult) SetFailNodes(v [][]byte) {
|
||||||
|
if x != nil {
|
||||||
|
x.FailNodes = v
|
||||||
|
}
|
||||||
|
}
|
26
v2/audit/json.go
Normal file
26
v2/audit/json.go
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
package audit
|
||||||
|
|
||||||
|
import (
|
||||||
|
audit "github.com/nspcc-dev/neofs-api-go/v2/audit/grpc"
|
||||||
|
"google.golang.org/protobuf/encoding/protojson"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (a *DataAuditResult) MarshalJSON() ([]byte, error) {
|
||||||
|
return protojson.MarshalOptions{
|
||||||
|
EmitUnpopulated: true,
|
||||||
|
}.Marshal(
|
||||||
|
DataAuditResultToGRPCMessage(a),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *DataAuditResult) UnmarshalJSON(data []byte) error {
|
||||||
|
msg := new(audit.DataAuditResult)
|
||||||
|
|
||||||
|
if err := protojson.Unmarshal(data, msg); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*a = *DataAuditResultFromGRPCMessage(msg)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
20
v2/audit/json_test.go
Normal file
20
v2/audit/json_test.go
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
package audit_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/v2/audit"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDataAuditResultJSON(t *testing.T) {
|
||||||
|
a := generateDataAuditResult()
|
||||||
|
|
||||||
|
data, err := a.MarshalJSON()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
a2 := new(audit.DataAuditResult)
|
||||||
|
require.NoError(t, a2.UnmarshalJSON(data))
|
||||||
|
|
||||||
|
require.Equal(t, a, a2)
|
||||||
|
}
|
143
v2/audit/marshal.go
Normal file
143
v2/audit/marshal.go
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
package audit
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/util/proto"
|
||||||
|
audit "github.com/nspcc-dev/neofs-api-go/v2/audit/grpc"
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
||||||
|
goproto "google.golang.org/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
_ = iota
|
||||||
|
auditEpochFNum
|
||||||
|
cidFNum
|
||||||
|
pubKeyFNum
|
||||||
|
passSGFNum
|
||||||
|
failSGFNum
|
||||||
|
hitFNum
|
||||||
|
missFNum
|
||||||
|
failFNum
|
||||||
|
passNodesFNum
|
||||||
|
failNodesFNum
|
||||||
|
)
|
||||||
|
|
||||||
|
// StableMarshal marshals unified DataAuditResult structure into a protobuf
|
||||||
|
// binary format without field order shuffle.
|
||||||
|
func (a *DataAuditResult) StableMarshal(buf []byte) ([]byte, error) {
|
||||||
|
if a == nil {
|
||||||
|
return []byte{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if buf == nil {
|
||||||
|
buf = make([]byte, a.StableSize())
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
offset, n int
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
n, err = proto.Fixed64Marshal(auditEpochFNum, buf[offset:], a.auditEpoch)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += n
|
||||||
|
|
||||||
|
n, err = proto.NestedStructureMarshal(cidFNum, buf[offset:], a.cid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += n
|
||||||
|
|
||||||
|
n, err = proto.BytesMarshal(pubKeyFNum, buf[offset:], a.pubKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += n
|
||||||
|
|
||||||
|
n, err = refs.ObjectIDNestedListMarshal(passSGFNum, buf[offset:], a.passSG)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += n
|
||||||
|
|
||||||
|
n, err = refs.ObjectIDNestedListMarshal(failSGFNum, buf[offset:], a.failSG)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += n
|
||||||
|
|
||||||
|
n, err = proto.UInt32Marshal(hitFNum, buf[offset:], a.hit)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += n
|
||||||
|
|
||||||
|
n, err = proto.UInt32Marshal(missFNum, buf[offset:], a.miss)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += n
|
||||||
|
|
||||||
|
n, err = proto.UInt32Marshal(failFNum, buf[offset:], a.fail)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += n
|
||||||
|
|
||||||
|
n, err = proto.RepeatedBytesMarshal(passNodesFNum, buf[offset:], a.passNodes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += n
|
||||||
|
|
||||||
|
n, err = proto.RepeatedBytesMarshal(failNodesFNum, buf[offset:], a.failNodes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// StableSize returns byte length of DataAuditResult structure
|
||||||
|
// marshaled by StableMarshal function.
|
||||||
|
func (a *DataAuditResult) StableSize() (size int) {
|
||||||
|
if a == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
size += proto.Fixed64Size(auditEpochFNum, a.auditEpoch)
|
||||||
|
size += proto.NestedStructureSize(cidFNum, a.cid)
|
||||||
|
size += proto.BytesSize(pubKeyFNum, a.pubKey)
|
||||||
|
size += refs.ObjectIDNestedListSize(passSGFNum, a.passSG)
|
||||||
|
size += refs.ObjectIDNestedListSize(failSGFNum, a.failSG)
|
||||||
|
size += proto.UInt32Size(hitFNum, a.hit)
|
||||||
|
size += proto.UInt32Size(missFNum, a.miss)
|
||||||
|
size += proto.UInt32Size(failFNum, a.fail)
|
||||||
|
size += proto.RepeatedBytesSize(passNodesFNum, a.passNodes)
|
||||||
|
size += proto.RepeatedBytesSize(failNodesFNum, a.failNodes)
|
||||||
|
|
||||||
|
return size
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal unmarshals DataAuditResult structure from its protobuf
|
||||||
|
// binary representation.
|
||||||
|
func (a *DataAuditResult) Unmarshal(data []byte) error {
|
||||||
|
m := new(audit.DataAuditResult)
|
||||||
|
if err := goproto.Unmarshal(data, m); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*a = *DataAuditResultFromGRPCMessage(m)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
55
v2/audit/marshal_test.go
Normal file
55
v2/audit/marshal_test.go
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
package audit_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/v2/audit"
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDataAuditResult_StableMarshal(t *testing.T) {
|
||||||
|
from := generateDataAuditResult()
|
||||||
|
|
||||||
|
t.Run("non empty", func(t *testing.T) {
|
||||||
|
wire, err := from.StableMarshal(nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
to := new(audit.DataAuditResult)
|
||||||
|
require.NoError(t, to.Unmarshal(wire))
|
||||||
|
|
||||||
|
require.Equal(t, from, to)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateDataAuditResult() *audit.DataAuditResult {
|
||||||
|
a := new(audit.DataAuditResult)
|
||||||
|
|
||||||
|
oid1 := new(refs.ObjectID)
|
||||||
|
oid1.SetValue([]byte("Object ID 1"))
|
||||||
|
|
||||||
|
oid2 := new(refs.ObjectID)
|
||||||
|
oid2.SetValue([]byte("Object ID 2"))
|
||||||
|
|
||||||
|
cid := new(refs.ContainerID)
|
||||||
|
cid.SetValue([]byte("Container ID"))
|
||||||
|
|
||||||
|
a.SetAuditEpoch(13)
|
||||||
|
a.SetContainerID(cid)
|
||||||
|
a.SetPublicKey([]byte("Public key"))
|
||||||
|
a.SetPassSG([]*refs.ObjectID{oid1, oid2})
|
||||||
|
a.SetFailSG([]*refs.ObjectID{oid2, oid1})
|
||||||
|
a.SetHit(1)
|
||||||
|
a.SetMiss(2)
|
||||||
|
a.SetFail(3)
|
||||||
|
a.SetPassNodes([][]byte{
|
||||||
|
{1, 2},
|
||||||
|
{3, 4},
|
||||||
|
})
|
||||||
|
a.SetFailNodes([][]byte{
|
||||||
|
{5, 6},
|
||||||
|
{7, 8},
|
||||||
|
})
|
||||||
|
|
||||||
|
return a
|
||||||
|
}
|
197
v2/audit/types.go
Normal file
197
v2/audit/types.go
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
package audit
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DataAuditResult is a unified structure of
|
||||||
|
// DataAuditResult message from proto definition.
|
||||||
|
type DataAuditResult struct {
|
||||||
|
auditEpoch uint64
|
||||||
|
|
||||||
|
hit, miss, fail uint32
|
||||||
|
|
||||||
|
cid *refs.ContainerID
|
||||||
|
|
||||||
|
pubKey []byte
|
||||||
|
|
||||||
|
passSG, failSG []*refs.ObjectID
|
||||||
|
|
||||||
|
failNodes, passNodes [][]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAuditEpoch returns epoch number when the Data Audit was conducted.
|
||||||
|
func (a *DataAuditResult) GetAuditEpoch() uint64 {
|
||||||
|
if a != nil {
|
||||||
|
return a.auditEpoch
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAuditEpoch sets epoch number when the Data Audit was conducted.
|
||||||
|
func (a *DataAuditResult) SetAuditEpoch(v uint64) {
|
||||||
|
if a != nil {
|
||||||
|
a.auditEpoch = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetContainerID returns container under audit.
|
||||||
|
func (a *DataAuditResult) GetContainerID() *refs.ContainerID {
|
||||||
|
if a != nil {
|
||||||
|
return a.cid
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetContainerID sets container under audit.
|
||||||
|
func (a *DataAuditResult) SetContainerID(v *refs.ContainerID) {
|
||||||
|
if a != nil {
|
||||||
|
a.cid = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPublicKey returns public key of the auditing InnerRing node in a binary format.
|
||||||
|
func (a *DataAuditResult) GetPublicKey() []byte {
|
||||||
|
if a != nil {
|
||||||
|
return a.pubKey
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPublicKey sets public key of the auditing InnerRing node in a binary format.
|
||||||
|
func (a *DataAuditResult) SetPublicKey(v []byte) {
|
||||||
|
if a != nil {
|
||||||
|
a.pubKey = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPassSG returns list of Storage Groups that passed audit PoR stage.
|
||||||
|
func (a *DataAuditResult) GetPassSG() []*refs.ObjectID {
|
||||||
|
if a != nil {
|
||||||
|
return a.passSG
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPassSG sets list of Storage Groups that passed audit PoR stage.
|
||||||
|
func (a *DataAuditResult) SetPassSG(v []*refs.ObjectID) {
|
||||||
|
if a != nil {
|
||||||
|
a.passSG = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFailSG returns list of Storage Groups that failed audit PoR stage.
|
||||||
|
func (a *DataAuditResult) GetFailSG() []*refs.ObjectID {
|
||||||
|
if a != nil {
|
||||||
|
return a.failSG
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFailSG sets list of Storage Groups that failed audit PoR stage.
|
||||||
|
func (a *DataAuditResult) SetFailSG(v []*refs.ObjectID) {
|
||||||
|
if a != nil {
|
||||||
|
a.failSG = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHit returns number of sampled objects under audit placed
|
||||||
|
// in an optimal way according to the containers placement policy
|
||||||
|
// when checking PoP.
|
||||||
|
func (a *DataAuditResult) GetHit() uint32 {
|
||||||
|
if a != nil {
|
||||||
|
return a.hit
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetHit sets number of sampled objects under audit placed
|
||||||
|
// in an optimal way according to the containers placement policy
|
||||||
|
// when checking PoP.
|
||||||
|
func (a *DataAuditResult) SetHit(v uint32) {
|
||||||
|
if a != nil {
|
||||||
|
a.hit = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMiss returns number of sampled objects under audit placed
|
||||||
|
// in suboptimal way according to the containers placement policy,
|
||||||
|
// but still at a satisfactory level when checking PoP.
|
||||||
|
func (a *DataAuditResult) GetMiss() uint32 {
|
||||||
|
if a != nil {
|
||||||
|
return a.miss
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMiss sets number of sampled objects under audit placed
|
||||||
|
// in suboptimal way according to the containers placement policy,
|
||||||
|
// but still at a satisfactory level when checking PoP.
|
||||||
|
func (a *DataAuditResult) SetMiss(v uint32) {
|
||||||
|
if a != nil {
|
||||||
|
a.miss = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFail returns number of sampled objects under audit stored
|
||||||
|
// in a way not confirming placement policy or not found at all
|
||||||
|
// when checking PoP.
|
||||||
|
func (a *DataAuditResult) GetFail() uint32 {
|
||||||
|
if a != nil {
|
||||||
|
return a.fail
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFail sets number of sampled objects under audit stored
|
||||||
|
// in a way not confirming placement policy or not found at all
|
||||||
|
// when checking PoP.
|
||||||
|
func (a *DataAuditResult) SetFail(v uint32) {
|
||||||
|
if a != nil {
|
||||||
|
a.fail = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPassNodes returns list of storage node public keys that
|
||||||
|
// passed at least one PDP.
|
||||||
|
func (a *DataAuditResult) GetPassNodes() [][]byte {
|
||||||
|
if a != nil {
|
||||||
|
return a.passNodes
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPassNodes sets list of storage node public keys that
|
||||||
|
// passed at least one PDP.
|
||||||
|
func (a *DataAuditResult) SetPassNodes(v [][]byte) {
|
||||||
|
if a != nil {
|
||||||
|
a.passNodes = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFailNodes returns list of storage node public keys that
|
||||||
|
// failed at least one PDP.
|
||||||
|
func (a *DataAuditResult) GetFailNodes() [][]byte {
|
||||||
|
if a != nil {
|
||||||
|
return a.failNodes
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFailNodes sets list of storage node public keys that
|
||||||
|
// failed at least one PDP.
|
||||||
|
func (a *DataAuditResult) SetFailNodes(v [][]byte) {
|
||||||
|
if a != nil {
|
||||||
|
a.failNodes = v
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue