forked from TrueCloudLab/frostfs-node
db703a5117
Define a structure for dealing with the geographic location of nodes. Implement VerifyAndUpdate (with the same purpose as NodeValidator interface) that checks LOCODE attribute and fills other attributes of the location. Technically the entity is a wrapper over the NeoFS location database: it maps the node LOCODE to the database record from which the new attributes are generated. Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
85 lines
2 KiB
Go
85 lines
2 KiB
Go
package locode
|
|
|
|
import (
|
|
"github.com/nspcc-dev/neofs-api-go/pkg/netmap"
|
|
"github.com/nspcc-dev/neofs-node/pkg/util/locode"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
var errMissingLocode = errors.New("missing locode attribute")
|
|
|
|
var errMissingRequiredAttr = errors.New("missing required attribute in DB record")
|
|
|
|
// VerifyAndUpdate validates LOCODE attribute of n
|
|
// and adds a group of related attributes.
|
|
//
|
|
// If n does not contain LOCODE attribute or its value does not
|
|
// match the UN/LOCODE format, an error returns.
|
|
//
|
|
// New attributes are formed from the record of DB instance (Prm).
|
|
// If DB entry R was found w/o errors, then new attributes are:
|
|
// * CountryCode: R.CountryCode().String();
|
|
// * Country: R.CountryName();
|
|
// * CityCode: R.LocationCode().String();
|
|
// * City: Record.LocationName();
|
|
// * SubDivCode: R.SubDivCode();
|
|
// * SubDiv: R.SubDivName();
|
|
// * Continent: R.Continent().String().
|
|
//
|
|
// LOCODE attribute remains untouched.
|
|
func (v *Validator) VerifyAndUpdate(n *netmap.NodeInfo) error {
|
|
mAttr := uniqueAttributes(n.Attributes())
|
|
|
|
attrLocode, ok := mAttr[attrKeyLocode]
|
|
if !ok {
|
|
return errMissingLocode
|
|
}
|
|
|
|
lc, err := locode.FromString(attrLocode.Value())
|
|
if err != nil {
|
|
return errors.Wrap(err, "invalid locode value")
|
|
}
|
|
|
|
record, err := v.db.Get(lc)
|
|
if err != nil {
|
|
return errors.Wrap(err, "could not get locode record from DB")
|
|
}
|
|
|
|
for attrKey, attrDesc := range v.mAttr {
|
|
attrVal := attrDesc.converter(record)
|
|
if attrVal == "" {
|
|
if !attrDesc.optional {
|
|
return errMissingRequiredAttr
|
|
}
|
|
|
|
continue
|
|
}
|
|
|
|
a := netmap.NewNodeAttribute()
|
|
a.SetKey(attrKey)
|
|
a.SetValue(attrVal)
|
|
|
|
mAttr[attrKey] = a
|
|
}
|
|
|
|
as := n.Attributes()
|
|
as = as[:0]
|
|
|
|
for _, attr := range mAttr {
|
|
as = append(as, attr)
|
|
}
|
|
|
|
n.SetAttributes(as...)
|
|
|
|
return nil
|
|
}
|
|
|
|
func uniqueAttributes(as []*netmap.NodeAttribute) map[string]*netmap.NodeAttribute {
|
|
mAttr := make(map[string]*netmap.NodeAttribute, len(as))
|
|
|
|
for _, attr := range as {
|
|
mAttr[attr.Key()] = attr
|
|
}
|
|
|
|
return mAttr
|
|
}
|