377 lines
9.6 KiB
Go
377 lines
9.6 KiB
Go
package audit
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/TrueCloudLab/frostfs-api-go/v2/audit"
|
|
"github.com/TrueCloudLab/frostfs-api-go/v2/refs"
|
|
cid "github.com/TrueCloudLab/frostfs-sdk-go/container/id"
|
|
oid "github.com/TrueCloudLab/frostfs-sdk-go/object/id"
|
|
"github.com/TrueCloudLab/frostfs-sdk-go/version"
|
|
)
|
|
|
|
// Result represents report on the results of the data audit in FrostFS system.
|
|
//
|
|
// Result is mutually binary-compatible with github.com/TrueCloudLab/frostfs-api-go/v2/audit.DataAuditResult
|
|
// message. See Marshal / Unmarshal methods.
|
|
//
|
|
// Instances can be created using built-in var declaration.
|
|
type Result struct {
|
|
versionEncoded bool
|
|
|
|
v2 audit.DataAuditResult
|
|
}
|
|
|
|
// Marshal encodes Result into a canonical FrostFS binary format (Protocol Buffers
|
|
// with direct field order).
|
|
//
|
|
// Writes version.Current() protocol version into the resulting message if Result
|
|
// hasn't been already decoded from such a message using Unmarshal.
|
|
//
|
|
// See also Unmarshal.
|
|
func (r *Result) Marshal() []byte {
|
|
if !r.versionEncoded {
|
|
var verV2 refs.Version
|
|
version.Current().WriteToV2(&verV2)
|
|
r.v2.SetVersion(&verV2)
|
|
r.versionEncoded = true
|
|
}
|
|
|
|
return r.v2.StableMarshal(nil)
|
|
}
|
|
|
|
var errCIDNotSet = errors.New("container ID is not set")
|
|
|
|
// Unmarshal decodes Result from its canonical FrostFS binary format (Protocol Buffers
|
|
// with direct field order). Returns an error describing a format violation.
|
|
//
|
|
// See also Marshal.
|
|
func (r *Result) Unmarshal(data []byte) error {
|
|
err := r.v2.Unmarshal(data)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
r.versionEncoded = true
|
|
|
|
// format checks
|
|
|
|
var cID cid.ID
|
|
|
|
cidV2 := r.v2.GetContainerID()
|
|
if cidV2 == nil {
|
|
return errCIDNotSet
|
|
}
|
|
|
|
err = cID.ReadFromV2(*cidV2)
|
|
if err != nil {
|
|
return fmt.Errorf("could not convert V2 container ID: %w", err)
|
|
}
|
|
|
|
var (
|
|
oID oid.ID
|
|
oidV2 refs.ObjectID
|
|
)
|
|
|
|
for _, oidV2 = range r.v2.GetPassSG() {
|
|
err = oID.ReadFromV2(oidV2)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid passed storage group ID: %w", err)
|
|
}
|
|
}
|
|
|
|
for _, oidV2 = range r.v2.GetFailSG() {
|
|
err = oID.ReadFromV2(oidV2)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid failed storage group ID: %w", err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Epoch returns FrostFS epoch when the data associated with the Result was audited.
|
|
//
|
|
// Zero Result has zero epoch.
|
|
//
|
|
// See also ForEpoch.
|
|
func (r Result) Epoch() uint64 {
|
|
return r.v2.GetAuditEpoch()
|
|
}
|
|
|
|
// ForEpoch specifies FrostFS epoch when the data associated with the Result was audited.
|
|
//
|
|
// See also Epoch.
|
|
func (r *Result) ForEpoch(epoch uint64) {
|
|
r.v2.SetAuditEpoch(epoch)
|
|
}
|
|
|
|
// Container returns identifier of the container with which the data audit Result
|
|
// is associated and a bool that indicates container ID field presence in the Result.
|
|
//
|
|
// Zero Result does not have container ID.
|
|
//
|
|
// See also ForContainer.
|
|
func (r Result) Container() (cid.ID, bool) {
|
|
var cID cid.ID
|
|
|
|
cidV2 := r.v2.GetContainerID()
|
|
if cidV2 != nil {
|
|
_ = cID.ReadFromV2(*cidV2)
|
|
return cID, true
|
|
}
|
|
|
|
return cID, false
|
|
}
|
|
|
|
// ForContainer sets identifier of the container with which the data audit Result
|
|
// is associated.
|
|
//
|
|
// See also Container.
|
|
func (r *Result) ForContainer(cnr cid.ID) {
|
|
var cidV2 refs.ContainerID
|
|
cnr.WriteToV2(&cidV2)
|
|
|
|
r.v2.SetContainerID(&cidV2)
|
|
}
|
|
|
|
// AuditorKey returns public key of the auditing FrostFS Inner Ring node in
|
|
// a FrostFS binary key format.
|
|
//
|
|
// Zero Result has nil key. Return value MUST NOT be mutated: to do this,
|
|
// first make a copy.
|
|
//
|
|
// See also SetAuditorPublicKey.
|
|
func (r Result) AuditorKey() []byte {
|
|
return r.v2.GetPublicKey()
|
|
}
|
|
|
|
// SetAuditorKey specifies public key of the auditing FrostFS Inner Ring node in
|
|
// a FrostFS binary key format.
|
|
//
|
|
// Argument MUST NOT be mutated at least until the end of using the Result.
|
|
//
|
|
// See also AuditorKey.
|
|
func (r *Result) SetAuditorKey(key []byte) {
|
|
r.v2.SetPublicKey(key)
|
|
}
|
|
|
|
// Completed returns completion state of the data audit associated with the Result.
|
|
//
|
|
// Zero Result corresponds to incomplete data audit.
|
|
//
|
|
// See also Complete.
|
|
func (r Result) Completed() bool {
|
|
return r.v2.GetComplete()
|
|
}
|
|
|
|
// Complete marks the data audit associated with the Result as completed.
|
|
//
|
|
// See also Completed.
|
|
func (r *Result) Complete() {
|
|
r.v2.SetComplete(true)
|
|
}
|
|
|
|
// RequestsPoR returns number of requests made by Proof-of-Retrievability
|
|
// audit check to get all headers of the objects inside storage groups.
|
|
//
|
|
// Zero Result has zero requests.
|
|
//
|
|
// See also SetRequestsPoR.
|
|
func (r Result) RequestsPoR() uint32 {
|
|
return r.v2.GetRequests()
|
|
}
|
|
|
|
// SetRequestsPoR sets number of requests made by Proof-of-Retrievability
|
|
// audit check to get all headers of the objects inside storage groups.
|
|
//
|
|
// See also RequestsPoR.
|
|
func (r *Result) SetRequestsPoR(v uint32) {
|
|
r.v2.SetRequests(v)
|
|
}
|
|
|
|
// RetriesPoR returns number of retries made by Proof-of-Retrievability
|
|
// audit check to get all headers of the objects inside storage groups.
|
|
//
|
|
// Zero Result has zero retries.
|
|
//
|
|
// See also SetRetriesPoR.
|
|
func (r Result) RetriesPoR() uint32 {
|
|
return r.v2.GetRetries()
|
|
}
|
|
|
|
// SetRetriesPoR sets number of retries made by Proof-of-Retrievability
|
|
// audit check to get all headers of the objects inside storage groups.
|
|
//
|
|
// See also RetriesPoR.
|
|
func (r *Result) SetRetriesPoR(v uint32) {
|
|
r.v2.SetRetries(v)
|
|
}
|
|
|
|
// IteratePassedStorageGroups iterates over all storage groups that passed
|
|
// Proof-of-Retrievability audit check and passes them into f. Breaks on f's
|
|
// false return, f MUST NOT be nil.
|
|
//
|
|
// Zero Result has no passed storage groups and doesn't call f.
|
|
//
|
|
// See also SubmitPassedStorageGroup.
|
|
func (r Result) IteratePassedStorageGroups(f func(oid.ID) bool) {
|
|
r2 := r.v2.GetPassSG()
|
|
|
|
var id oid.ID
|
|
|
|
for i := range r2 {
|
|
_ = id.ReadFromV2(r2[i])
|
|
|
|
if !f(id) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// SubmitPassedStorageGroup marks storage group as passed Proof-of-Retrievability
|
|
// audit check.
|
|
//
|
|
// See also IteratePassedStorageGroups.
|
|
func (r *Result) SubmitPassedStorageGroup(sg oid.ID) {
|
|
var idV2 refs.ObjectID
|
|
sg.WriteToV2(&idV2)
|
|
|
|
r.v2.SetPassSG(append(r.v2.GetPassSG(), idV2))
|
|
}
|
|
|
|
// IterateFailedStorageGroups is similar to IteratePassedStorageGroups but for failed groups.
|
|
//
|
|
// See also SubmitFailedStorageGroup.
|
|
func (r Result) IterateFailedStorageGroups(f func(oid.ID) bool) {
|
|
v := r.v2.GetFailSG()
|
|
var id oid.ID
|
|
|
|
for i := range v {
|
|
_ = id.ReadFromV2(v[i])
|
|
if !f(id) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// SubmitFailedStorageGroup is similar to SubmitPassedStorageGroup but for failed groups.
|
|
//
|
|
// See also IterateFailedStorageGroups.
|
|
func (r *Result) SubmitFailedStorageGroup(sg oid.ID) {
|
|
var idV2 refs.ObjectID
|
|
sg.WriteToV2(&idV2)
|
|
|
|
r.v2.SetFailSG(append(r.v2.GetFailSG(), idV2))
|
|
}
|
|
|
|
// Hits returns number of sampled objects under audit placed
|
|
// in an optimal way according to the container's placement policy
|
|
// when checking Proof-of-Placement.
|
|
//
|
|
// Zero result has zero hits.
|
|
//
|
|
// See also SetHits.
|
|
func (r Result) Hits() uint32 {
|
|
return r.v2.GetHit()
|
|
}
|
|
|
|
// SetHits sets number of sampled objects under audit placed
|
|
// in an optimal way according to the containers placement policy
|
|
// when checking Proof-of-Placement.
|
|
//
|
|
// See also Hits.
|
|
func (r *Result) SetHits(hit uint32) {
|
|
r.v2.SetHit(hit)
|
|
}
|
|
|
|
// Misses returns number of sampled objects under audit placed
|
|
// in suboptimal way according to the container's placement policy,
|
|
// but still at a satisfactory level when checking Proof-of-Placement.
|
|
//
|
|
// Zero Result has zero misses.
|
|
//
|
|
// See also SetMisses.
|
|
func (r Result) Misses() uint32 {
|
|
return r.v2.GetMiss()
|
|
}
|
|
|
|
// SetMisses sets number of sampled objects under audit placed
|
|
// in suboptimal way according to the container's placement policy,
|
|
// but still at a satisfactory level when checking Proof-of-Placement.
|
|
//
|
|
// See also Misses.
|
|
func (r *Result) SetMisses(miss uint32) {
|
|
r.v2.SetMiss(miss)
|
|
}
|
|
|
|
// Failures returns number of sampled objects under audit stored
|
|
// in a way not confirming placement policy or not found at all
|
|
// when checking Proof-of-Placement.
|
|
//
|
|
// Zero result has zero failures.
|
|
//
|
|
// See also SetFailures.
|
|
func (r Result) Failures() uint32 {
|
|
return r.v2.GetFail()
|
|
}
|
|
|
|
// SetFailures sets number of sampled objects under audit stored
|
|
// in a way not confirming placement policy or not found at all
|
|
// when checking Proof-of-Placement.
|
|
//
|
|
// See also Failures.
|
|
func (r *Result) SetFailures(fail uint32) {
|
|
r.v2.SetFail(fail)
|
|
}
|
|
|
|
// IteratePassedStorageNodes iterates over all storage nodes that passed at least one
|
|
// Proof-of-Data-Possession audit check and passes their public keys into f. Breaks on
|
|
// f's false return.
|
|
//
|
|
// f MUST NOT be nil and MUST NOT mutate parameter passed into it at least until
|
|
// the end of using the Result.
|
|
//
|
|
// Zero Result has no passed storage nodes and doesn't call f.
|
|
//
|
|
// See also SubmitPassedStorageNode.
|
|
func (r Result) IteratePassedStorageNodes(f func([]byte) bool) {
|
|
v := r.v2.GetPassNodes()
|
|
|
|
for i := range v {
|
|
if !f(v[i]) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// SubmitPassedStorageNodes marks storage node list as passed Proof-of-Data-Possession
|
|
// audit check. The list contains public keys.
|
|
//
|
|
// Argument and its elements MUST NOT be mutated at least until the end of using the Result.
|
|
//
|
|
// See also IteratePassedStorageNodes.
|
|
func (r *Result) SubmitPassedStorageNodes(list [][]byte) {
|
|
r.v2.SetPassNodes(list)
|
|
}
|
|
|
|
// IterateFailedStorageNodes is similar to IteratePassedStorageNodes but for failed nodes.
|
|
//
|
|
// See also SubmitPassedStorageNodes.
|
|
func (r Result) IterateFailedStorageNodes(f func([]byte) bool) {
|
|
v := r.v2.GetFailNodes()
|
|
|
|
for i := range v {
|
|
if !f(v[i]) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// SubmitFailedStorageNodes is similar to SubmitPassedStorageNodes but for failed nodes.
|
|
//
|
|
// See also IterateFailedStorageNodes.
|
|
func (r *Result) SubmitFailedStorageNodes(list [][]byte) {
|
|
r.v2.SetFailNodes(list)
|
|
}
|