frostfs-node/pkg/policy/json.go
Evgenii Stratonikov 84b4ff0755 [#27] Support JSON format for placement policy
Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
2020-10-02 11:25:35 +03:00

221 lines
4.7 KiB
Go

package policy
import (
"encoding/json"
"fmt"
"strings"
"github.com/nspcc-dev/neofs-api-go/v2/netmap"
)
type (
filter struct {
Name string `json:"name,omitempty"`
Key string `json:"key,omitempty"`
Op string `json:"op,omitempty"`
Value string `json:"value,omitempty"`
Filters []filter `json:"filters,omitempty"`
}
replica struct {
Count uint32 `json:"count"`
Selector string `json:"selector,omitempty"`
}
selector struct {
Count uint32 `json:"count"`
Attribute string `json:"attribute"`
Filter string `json:"filter,omitempty"`
Name string `json:"name,omitempty"`
Clause string `json:"clause,omitempty"`
}
placement struct {
Replicas []replica `json:"replicas"`
CBF uint32 `json:"container_backup_factor,omitempty"`
Selectors []selector `json:"selectors,omitempty"`
Filters []filter `json:"filters,omitempty"`
}
)
// ToJSON converts placement policy to JSON.
func ToJSON(np *netmap.PlacementPolicy) ([]byte, error) {
p := new(placement)
p.CBF = np.GetContainerBackupFactor()
p.Filters = make([]filter, len(np.GetFilters()))
for i, f := range np.GetFilters() {
p.Filters[i].fromNetmap(f)
}
p.Selectors = make([]selector, len(np.GetSelectors()))
for i, s := range np.GetSelectors() {
p.Selectors[i].fromNetmap(s)
}
p.Replicas = make([]replica, len(np.GetReplicas()))
for i, r := range np.GetReplicas() {
p.Replicas[i].fromNetmap(r)
}
return json.Marshal(p)
}
// ToJSON creates placement policy from JSON.
func FromJSON(data []byte) (*netmap.PlacementPolicy, error) {
p := new(placement)
if err := json.Unmarshal(data, p); err != nil {
return nil, err
}
rs := make([]*netmap.Replica, len(p.Replicas))
for i := range p.Replicas {
rs[i] = p.Replicas[i].toNetmap()
}
var fs []*netmap.Filter
if len(p.Filters) != 0 {
fs = make([]*netmap.Filter, len(p.Filters))
for i := range p.Filters {
f, err := p.Filters[i].toNetmap()
if err != nil {
return nil, err
}
fs[i] = f
}
}
var ss []*netmap.Selector
if len(p.Selectors) != 0 {
ss = make([]*netmap.Selector, len(p.Selectors))
for i := range p.Selectors {
s, err := p.Selectors[i].toNetmap()
if err != nil {
return nil, err
}
ss[i] = s
}
}
pp := new(netmap.PlacementPolicy)
pp.SetReplicas(rs)
pp.SetContainerBackupFactor(p.CBF)
pp.SetFilters(fs)
pp.SetSelectors(ss)
return pp, nil
}
func (r *replica) toNetmap() *netmap.Replica {
nr := new(netmap.Replica)
nr.SetCount(r.Count)
nr.SetSelector(r.Selector)
return nr
}
func (r *replica) fromNetmap(nr *netmap.Replica) {
r.Count = nr.GetCount()
r.Selector = nr.GetSelector()
}
func (f *filter) toNetmap() (*netmap.Filter, error) {
var op netmap.Operation
switch strings.ToUpper(f.Op) {
case "EQ":
op = netmap.EQ
case "NE":
op = netmap.NE
case "GT":
op = netmap.GT
case "GE":
op = netmap.GE
case "LT":
op = netmap.LT
case "LE":
op = netmap.LE
case "AND":
op = netmap.AND
case "OR":
op = netmap.OR
case "":
op = netmap.UnspecifiedOperation
default:
return nil, fmt.Errorf("%w: '%s'", ErrUnknownOp, f.Op)
}
var fs []*netmap.Filter
if len(f.Filters) != 0 {
fs = make([]*netmap.Filter, len(f.Filters))
for i := range f.Filters {
var err error
fs[i], err = f.Filters[i].toNetmap()
if err != nil {
return nil, err
}
}
}
nf := new(netmap.Filter)
nf.SetFilters(fs)
nf.SetOp(op)
nf.SetName(f.Name)
nf.SetValue(f.Value)
nf.SetKey(f.Key)
return nf, nil
}
func (f *filter) fromNetmap(nf *netmap.Filter) {
f.Name = nf.GetName()
f.Key = nf.GetKey()
f.Value = nf.GetValue()
switch nf.GetOp() {
case netmap.EQ:
f.Op = "EQ"
case netmap.NE:
f.Op = "NE"
case netmap.GT:
f.Op = "GT"
case netmap.GE:
f.Op = "GE"
case netmap.LT:
f.Op = "LT"
case netmap.LE:
f.Op = "LE"
case netmap.AND:
f.Op = "AND"
case netmap.OR:
f.Op = "OR"
}
if nf.GetFilters() != nil {
f.Filters = make([]filter, len(nf.GetFilters()))
for i, sf := range nf.GetFilters() {
f.Filters[i].fromNetmap(sf)
}
}
}
func (s *selector) toNetmap() (*netmap.Selector, error) {
var c netmap.Clause
switch strings.ToUpper(s.Clause) {
case "SAME":
c = netmap.Same
case "DISTINCT":
c = netmap.Distinct
case "":
default:
return nil, fmt.Errorf("%w: '%s'", ErrUnknownClause, s.Clause)
}
ns := new(netmap.Selector)
ns.SetName(s.Name)
ns.SetAttribute(s.Attribute)
ns.SetCount(s.Count)
ns.SetClause(c)
ns.SetFilter(s.Filter)
return ns, nil
}
func (s *selector) fromNetmap(ns *netmap.Selector) {
s.Name = ns.GetName()
s.Filter = ns.GetFilter()
s.Count = ns.GetCount()
s.Attribute = ns.GetAttribute()
switch ns.GetClause() {
case netmap.Same:
s.Clause = "same"
case netmap.Distinct:
s.Clause = "distinct"
}
s.Name = ns.GetName()
}