From e9e248faccf031f188a641455574dbd147a1c90c Mon Sep 17 00:00:00 2001 From: Pavel Karpy Date: Wed, 15 Nov 2023 16:32:34 +0300 Subject: [PATCH 1/8] ir/locode: Fix `Validator`'s comment Signed-off-by: Pavel Karpy --- .../processors/netmap/nodevalidation/locode/validator.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/pkg/innerring/processors/netmap/nodevalidation/locode/validator.go b/pkg/innerring/processors/netmap/nodevalidation/locode/validator.go index 573d8af5b4..9723da1db0 100644 --- a/pkg/innerring/processors/netmap/nodevalidation/locode/validator.go +++ b/pkg/innerring/processors/netmap/nodevalidation/locode/validator.go @@ -17,8 +17,6 @@ type Validator struct { // New creates a new instance of the Validator. // -// Panics if at least one value of the parameters is invalid. -// // The created Validator does not require additional // initialization and is completely ready for work. func New() *Validator { From 7f1177ef8fb41201a9fbdcacc184da47eb247ca3 Mon Sep 17 00:00:00 2001 From: Pavel Karpy Date: Wed, 15 Nov 2023 16:38:20 +0300 Subject: [PATCH 2/8] ir/locode: Do not export internal method `Get` won't be used outside ever, and it should not be a method in fact. Signed-off-by: Pavel Karpy --- pkg/innerring/processors/netmap/nodevalidation/locode/calls.go | 2 +- .../processors/netmap/nodevalidation/locode/validator.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/innerring/processors/netmap/nodevalidation/locode/calls.go b/pkg/innerring/processors/netmap/nodevalidation/locode/calls.go index d806f959e2..fea3845a1d 100644 --- a/pkg/innerring/processors/netmap/nodevalidation/locode/calls.go +++ b/pkg/innerring/processors/netmap/nodevalidation/locode/calls.go @@ -20,7 +20,7 @@ func (v *Validator) VerifyAndUpdate(n *netmap.NodeInfo) error { if n.LOCODE() == "" { return nil } - key, record, err := v.Get(n.LOCODE()) + key, record, err := getRecord(n.LOCODE()) if err != nil { return fmt.Errorf("could not get locode record from DB: %w", err) } diff --git a/pkg/innerring/processors/netmap/nodevalidation/locode/validator.go b/pkg/innerring/processors/netmap/nodevalidation/locode/validator.go index 9723da1db0..c88efcbabc 100644 --- a/pkg/innerring/processors/netmap/nodevalidation/locode/validator.go +++ b/pkg/innerring/processors/netmap/nodevalidation/locode/validator.go @@ -23,7 +23,7 @@ func New() *Validator { return &Validator{} } -func (v *Validator) Get(lc string) (*locodedb.Key, locodedb.Record, error) { +func getRecord(lc string) (*locodedb.Key, locodedb.Record, error) { country, location := lc[:2], lc[2:] if lc[2] == ' ' { location = lc[3:] From abc37861a8acf2429f8907516cb2af7ab5975a7a Mon Sep 17 00:00:00 2001 From: Pavel Karpy Date: Wed, 15 Nov 2023 18:03:13 +0300 Subject: [PATCH 3/8] node: Expand UN/LOCODE provided by a user Use the new LOCODE db that as a GO package. Allow attributes implicit overriding. Signed-off-by: Pavel Karpy --- cmd/neofs-node/attributes.go | 52 ++++++++++++++++++++++++++++++++++++ cmd/neofs-node/config.go | 24 ++++------------- cmd/neofs-node/netmap.go | 17 ++++-------- 3 files changed, 62 insertions(+), 31 deletions(-) diff --git a/cmd/neofs-node/attributes.go b/cmd/neofs-node/attributes.go index cf1b052447..1424f3685a 100644 --- a/cmd/neofs-node/attributes.go +++ b/cmd/neofs-node/attributes.go @@ -1,8 +1,12 @@ package main import ( + "fmt" + + "github.com/nspcc-dev/locode-db/pkg/locodedb" nodeconfig "github.com/nspcc-dev/neofs-node/cmd/neofs-node/config/node" "github.com/nspcc-dev/neofs-node/pkg/util/attributes" + "github.com/nspcc-dev/neofs-sdk-go/netmap" ) func parseAttributes(c *cfg) { @@ -11,4 +15,52 @@ func parseAttributes(c *cfg) { } fatalOnErr(attributes.ReadNodeAttributes(&c.cfgNodeInfo.localInfo, nodeconfig.Attributes(c.appCfg))) + + // expand UN/LOCODE attribute if any found; keep user's attributes + // if any conflicts appear + + locAttr := c.cfgNodeInfo.localInfo.LOCODE() + if locAttr == "" { + return + } + + key, record, err := getRecord(locAttr) + if err != nil { + fatalOnErr(fmt.Errorf("could not get locode record from DB: %w", err)) + } + + n := &c.cfgNodeInfo.localInfo + + setLocodeAttr(n, "CountryCode", key.CountryCode().String()) + setLocodeAttr(n, "Country", record.Country) + setLocodeAttr(n, "Location", record.Location) + setLocodeAttr(n, "Continent", record.Cont.String()) + if subDivCode := record.SubDivCode; subDivCode != "" { + setLocodeAttr(n, "SubDivCode", subDivCode) + } + if subDivName := record.SubDivName; subDivName != "" { + setLocodeAttr(n, "SubDiv", subDivName) + } +} + +func getRecord(lc string) (*locodedb.Key, locodedb.Record, error) { + country, location := lc[:2], lc[2:] + if lc[2] == ' ' { + location = lc[3:] + } + key, err := locodedb.NewKey(country, location) + if err != nil { + return nil, locodedb.Record{}, err + } + rec, err := locodedb.Get(lc) + return key, rec, err +} + +func setLocodeAttr(ni *netmap.NodeInfo, key, value string) { + valHave := ni.Attribute(key) + if valHave != "" { + return + } + + ni.SetAttribute(key, value) } diff --git a/cmd/neofs-node/config.go b/cmd/neofs-node/config.go index a0fc486445..8462961d7c 100644 --- a/cmd/neofs-node/config.go +++ b/cmd/neofs-node/config.go @@ -422,7 +422,7 @@ type cfgNetmap struct { } type cfgNodeInfo struct { - // values from config + // values from config; NOT MODIFY AFTER APP INITIALIZATION localInfo netmap.NodeInfo } @@ -822,21 +822,15 @@ func initObjectPool(cfg *config.Config) (pool cfgObjectRoutines) { func (c *cfg) LocalNodeInfo() (*netmapV2.NodeInfo, error) { var res netmapV2.NodeInfo - - ni, ok := c.cfgNetmap.state.getNodeInfo() - if ok { - ni.WriteToV2(&res) - } else { - c.cfgNodeInfo.localInfo.WriteToV2(&res) - } + c.cfgNodeInfo.localInfo.WriteToV2(&res) return &res, nil } -// handleLocalNodeInfo rewrites local node info from the NeoFS network map. +// handleLocalNodeInfoFromNetwork rewrites cached node info from the NeoFS network map. // Called with nil when storage node is outside the NeoFS network map // (before entering the network and after leaving it). -func (c *cfg) handleLocalNodeInfo(ni *netmap.NodeInfo) { +func (c *cfg) handleLocalNodeInfoFromNetwork(ni *netmap.NodeInfo) { c.cfgNetmap.state.setNodeInfo(ni) c.localNodeInNetmap.Store(ni != nil) } @@ -845,15 +839,7 @@ func (c *cfg) handleLocalNodeInfo(ni *netmap.NodeInfo) { // with the binary-encoded information from the current node's configuration. // The state is set using the provided setter which MUST NOT be nil. func (c *cfg) bootstrapWithState(stateSetter func(*netmap.NodeInfo)) error { - var ni netmap.NodeInfo - if niAtomic := c.cfgNetmap.state.nodeInfo.Load(); niAtomic != nil { - // node has already been bootstrapped successfully - ni = niAtomic.(netmap.NodeInfo) - } else { - // unknown network state - ni = c.cfgNodeInfo.localInfo - } - + ni := c.cfgNodeInfo.localInfo stateSetter(&ni) prm := nmClient.AddPeerPrm{} diff --git a/cmd/neofs-node/netmap.go b/cmd/neofs-node/netmap.go index 9807be7d58..57dbf9bfdb 100644 --- a/cmd/neofs-node/netmap.go +++ b/cmd/neofs-node/netmap.go @@ -117,19 +117,12 @@ func nodeKeyFromNetmap(c *cfg) []byte { } func (c *cfg) iterateNetworkAddresses(f func(string) bool) { - ni, ok := c.cfgNetmap.state.getNodeInfo() - if ok { - ni.IterateNetworkEndpoints(f) - } + ni := c.cfgNodeInfo.localInfo + ni.IterateNetworkEndpoints(f) } func (c *cfg) addressNum() int { - ni, ok := c.cfgNetmap.state.getNodeInfo() - if ok { - return ni.NumberOfNetworkEndpoints() - } - - return 0 + return c.cfgNodeInfo.localInfo.NumberOfNetworkEndpoints() } func initNetmapService(c *cfg) { @@ -201,7 +194,7 @@ func initNetmapService(c *cfg) { return } - c.handleLocalNodeInfo(ni) + c.handleLocalNodeInfoFromNetwork(ni) }) addNewEpochAsyncNotificationHandler(c, func(ev event.Event) { @@ -285,7 +278,7 @@ func getNetworkState(c *cfg) (uint64, *netmapSDK.NodeInfo, error) { func updateLocalState(c *cfg, epoch uint64, ni *netmapSDK.NodeInfo) { c.cfgNetmap.state.setCurrentEpoch(epoch) c.cfgNetmap.startEpoch = epoch - c.handleLocalNodeInfo(ni) + c.handleLocalNodeInfoFromNetwork(ni) } func (c *cfg) netmapLocalNodeState(epoch uint64) (*netmapSDK.NodeInfo, error) { From fb13ef9853d3fd9437aef4f7a625b42b14850ce5 Mon Sep 17 00:00:00 2001 From: Pavel Karpy Date: Wed, 15 Nov 2023 18:11:52 +0300 Subject: [PATCH 4/8] ir: Check UN/LOCODE attributes, not attach them Closes #2612. Signed-off-by: Pavel Karpy --- CHANGELOG.md | 1 + .../netmap/nodevalidation/locode/calls.go | 38 ++++++++--- .../nodevalidation/locode/calls_test.go | 63 ++++++++++++++++--- 3 files changed, 84 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 07569b88fb..c8ddb2a223 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ Changelog for NeoFS Node - New optimized SDK version is integrated (#2622) - IR uses internal LOCODE DB from Go package (#2610) - Contract group for the committee is no longer registered/used in the Sidechain auto-deployment (#2642) +- IR does not change SNs' attributes, SNs expand UN/LOCODE attributes do it themselves (#2612) - The priority of metrics service is increased (#2428) - The priority of running control service is maximized (#2585) diff --git a/pkg/innerring/processors/netmap/nodevalidation/locode/calls.go b/pkg/innerring/processors/netmap/nodevalidation/locode/calls.go index fea3845a1d..93fdb815a9 100644 --- a/pkg/innerring/processors/netmap/nodevalidation/locode/calls.go +++ b/pkg/innerring/processors/netmap/nodevalidation/locode/calls.go @@ -25,16 +25,38 @@ func (v *Validator) VerifyAndUpdate(n *netmap.NodeInfo) error { return fmt.Errorf("could not get locode record from DB: %w", err) } - n.SetCountryCode(key.CountryCode().String()) - n.SetCountryName(record.Country) - n.SetLocationName(record.Location) - n.SetContinentName(record.Cont.String()) - if subDivCode := record.SubDivCode; subDivCode != "" { - n.SetSubdivisionCode(subDivCode) + err = checkAttribute(n, "CountryCode", key.CountryCode().String()) + if err != nil { + return err + } + err = checkAttribute(n, "Country", record.Country) + if err != nil { + return err + } + err = checkAttribute(n, "Location", record.Location) + if err != nil { + return err + } + err = checkAttribute(n, "Continent", record.Cont.String()) + if err != nil { + return err } + err = checkAttribute(n, "SubDivCode", record.SubDivCode) + if err != nil { + return err + } + err = checkAttribute(n, "SubDiv", record.SubDivName) + if err != nil { + return err + } + + return nil +} - if subDivName := record.SubDivName; subDivName != "" { - n.SetSubdivisionName(subDivName) +func checkAttribute(n *netmap.NodeInfo, key, expectedVal string) error { + val := n.Attribute(key) + if val != expectedVal { + return fmt.Errorf("wrong '%q' attribute value: want '%q', got '%q'", key, expectedVal, val) } return nil diff --git a/pkg/innerring/processors/netmap/nodevalidation/locode/calls_test.go b/pkg/innerring/processors/netmap/nodevalidation/locode/calls_test.go index e2b12e1570..3f76a97fc8 100644 --- a/pkg/innerring/processors/netmap/nodevalidation/locode/calls_test.go +++ b/pkg/innerring/processors/netmap/nodevalidation/locode/calls_test.go @@ -70,18 +70,61 @@ func TestValidator_VerifyAndUpdate(t *testing.T) { // test record with valid but require.Error(t, err) }) - n := nodeInfoWithSomeAttrs() + t.Run("correct code", func(t *testing.T) { + n := nodeInfoWithSomeAttrs() + addLocodeAttr(n, [2]string{k.CountryCode().String(), k.LocationCode().String()}) - addLocodeAttr(n, [2]string{k.CountryCode().String(), k.LocationCode().String()}) + n.SetAttribute("CountryCode", k.CountryCode().String()) + n.SetAttribute("Country", r.Country) + n.SetAttribute("Location", r.Location) + n.SetAttribute("SubDivCode", r.SubDivCode) + n.SetAttribute("SubDiv", r.SubDivName) + n.SetAttribute("Continent", r.Cont.String()) - err := validator.VerifyAndUpdate(n) - require.NoError(t, err) + require.NoError(t, validator.VerifyAndUpdate(n)) + }) + + t.Run("invalid SN expansion", func(t *testing.T) { + + t.Run("invalid Country", func(t *testing.T) { + n := nodeInfoWithSomeAttrs() + addLocodeAttr(n, [2]string{"RU", "SPB"}) + n.SetAttribute("CountryCode", r.Country+"bad") + + require.Error(t, validator.VerifyAndUpdate(n)) + }) - require.Equal(t, k.CountryCode().String(), n.Attribute("CountryCode")) - require.Equal(t, r.Country, n.Attribute("Country")) - require.Equal(t, r.Location, n.Attribute("Location")) - require.Equal(t, r.SubDivCode, n.Attribute("SubDivCode")) - require.Equal(t, r.SubDivName, n.Attribute("SubDiv")) - require.Equal(t, r.Cont.String(), n.Attribute("Continent")) + t.Run("invalid Location", func(t *testing.T) { + n := nodeInfoWithSomeAttrs() + addLocodeAttr(n, [2]string{"RU", "SPB"}) + n.SetAttribute("Location", r.Location+"bad") + + require.Error(t, validator.VerifyAndUpdate(n)) + }) + + t.Run("invalid SubDivCode", func(t *testing.T) { + n := nodeInfoWithSomeAttrs() + addLocodeAttr(n, [2]string{"RU", "SPB"}) + n.SetAttribute("SubDivCode", r.SubDivCode+"bad") + + require.Error(t, validator.VerifyAndUpdate(n)) + }) + + t.Run("invalid SubDivName", func(t *testing.T) { + n := nodeInfoWithSomeAttrs() + addLocodeAttr(n, [2]string{"RU", "SPB"}) + n.SetAttribute("SubDivName", r.SubDivName+"bad") + + require.Error(t, validator.VerifyAndUpdate(n)) + }) + + t.Run("invalid Continent", func(t *testing.T) { + n := nodeInfoWithSomeAttrs() + addLocodeAttr(n, [2]string{"RU", "SPB"}) + n.SetAttribute("Continent", r.Cont.String()+"bad") + + require.Error(t, validator.VerifyAndUpdate(n)) + }) + }) }) } From 962abd097edebd20285ee9cf33d0374ccbc869e6 Mon Sep 17 00:00:00 2001 From: Pavel Karpy Date: Wed, 15 Nov 2023 18:13:33 +0300 Subject: [PATCH 5/8] ir: Fix `NodeValidator` interface It does not update node infos anymore. Signed-off-by: Pavel Karpy --- .../nodevalidation/availability/validator.go | 4 +- .../netmap/nodevalidation/locode/calls.go | 8 ++-- .../nodevalidation/locode/calls_test.go | 40 +++++++++---------- .../privatedomains/validator.go | 2 +- .../privatedomains/validator_test.go | 18 ++++----- .../netmap/nodevalidation/state/validator.go | 6 +-- .../nodevalidation/state/validator_test.go | 2 +- .../netmap/nodevalidation/structure/calls.go | 6 +-- .../netmap/nodevalidation/validator.go | 6 +-- .../processors/netmap/process_peers.go | 4 +- pkg/innerring/processors/netmap/processor.go | 9 +---- 11 files changed, 49 insertions(+), 56 deletions(-) diff --git a/pkg/innerring/processors/netmap/nodevalidation/availability/validator.go b/pkg/innerring/processors/netmap/nodevalidation/availability/validator.go index 209dac7b5b..b67c272d5f 100644 --- a/pkg/innerring/processors/netmap/nodevalidation/availability/validator.go +++ b/pkg/innerring/processors/netmap/nodevalidation/availability/validator.go @@ -19,7 +19,7 @@ import ( // the Validator is immediately ready to work through API. type Validator struct{} -func (v Validator) VerifyAndUpdate(nodeInfo *netmap.NodeInfo) error { +func (v Validator) Verify(nodeInfo netmap.NodeInfo) error { var results []*client.ResEndpointInfo var err error @@ -53,7 +53,7 @@ func (v Validator) VerifyAndUpdate(nodeInfo *netmap.NodeInfo) error { } for _, res := range results { - err = compareNodeInfos(*nodeInfo, res.NodeInfo()) + err = compareNodeInfos(nodeInfo, res.NodeInfo()) if err != nil { return fmt.Errorf("`EndpointInfo` RPC call result differs: %w", err) } diff --git a/pkg/innerring/processors/netmap/nodevalidation/locode/calls.go b/pkg/innerring/processors/netmap/nodevalidation/locode/calls.go index 93fdb815a9..db694082fb 100644 --- a/pkg/innerring/processors/netmap/nodevalidation/locode/calls.go +++ b/pkg/innerring/processors/netmap/nodevalidation/locode/calls.go @@ -6,7 +6,7 @@ import ( "github.com/nspcc-dev/neofs-sdk-go/netmap" ) -// VerifyAndUpdate validates UN-LOCODE attribute of n +// Verify validates UN-LOCODE attribute of n // and adds a group of related attributes. // // If n contains at least one of the LOCODE-derived attributes, @@ -14,9 +14,7 @@ import ( // // If n contains UN-LOCODE attribute and its value does not // match the UN/LOCODE format, an error is returned. -// -// UN-LOCODE attribute remains untouched. -func (v *Validator) VerifyAndUpdate(n *netmap.NodeInfo) error { +func (v *Validator) Verify(n netmap.NodeInfo) error { if n.LOCODE() == "" { return nil } @@ -53,7 +51,7 @@ func (v *Validator) VerifyAndUpdate(n *netmap.NodeInfo) error { return nil } -func checkAttribute(n *netmap.NodeInfo, key, expectedVal string) error { +func checkAttribute(n netmap.NodeInfo, key, expectedVal string) error { val := n.Attribute(key) if val != expectedVal { return fmt.Errorf("wrong '%q' attribute value: want '%q', got '%q'", key, expectedVal, val) diff --git a/pkg/innerring/processors/netmap/nodevalidation/locode/calls_test.go b/pkg/innerring/processors/netmap/nodevalidation/locode/calls_test.go index 3f76a97fc8..9de8d26cb5 100644 --- a/pkg/innerring/processors/netmap/nodevalidation/locode/calls_test.go +++ b/pkg/innerring/processors/netmap/nodevalidation/locode/calls_test.go @@ -18,16 +18,16 @@ func addLocodeAttr(n *netmap.NodeInfo, lc [2]string) { n.SetLOCODE(fmt.Sprintf("%s %s", lc[0], lc[1])) } -func nodeInfoWithSomeAttrs() *netmap.NodeInfo { +func nodeInfoWithSomeAttrs() netmap.NodeInfo { var n netmap.NodeInfo n.SetAttribute("key1", "val1") n.SetAttribute("key2", "val2") - return &n + return n } -func TestValidator_VerifyAndUpdate(t *testing.T) { // test record with valid but random values +func TestValidator_Verify(t *testing.T) { // test record with valid but random values r := locodedb.Record{ SubDivCode: "MSK", } @@ -48,31 +48,31 @@ func TestValidator_VerifyAndUpdate(t *testing.T) { // test record with valid but t.Run("w/o locode", func(t *testing.T) { n := nodeInfoWithSomeAttrs() - err := validator.VerifyAndUpdate(n) + err := validator.Verify(n) require.NoError(t, err) }) t.Run("w/ locode", func(t *testing.T) { t.Run("invalid locode", func(t *testing.T) { n := nodeInfoWithSomeAttrs() - addLocodeAttrValue(n, "WRONG LOCODE") + addLocodeAttrValue(&n, "WRONG LOCODE") - err := validator.VerifyAndUpdate(n) + err := validator.Verify(n) require.Error(t, err) }) t.Run("missing DB record", func(t *testing.T) { n := nodeInfoWithSomeAttrs() - addLocodeAttr(n, [2]string{"RU", "SPB"}) //RU,SSR -Saint Petersburg + addLocodeAttr(&n, [2]string{"RU", "SPB"}) // RU,SSR -Saint Petersburg - err := validator.VerifyAndUpdate(n) + err := validator.Verify(n) require.Error(t, err) }) t.Run("correct code", func(t *testing.T) { n := nodeInfoWithSomeAttrs() - addLocodeAttr(n, [2]string{k.CountryCode().String(), k.LocationCode().String()}) + addLocodeAttr(&n, [2]string{k.CountryCode().String(), k.LocationCode().String()}) n.SetAttribute("CountryCode", k.CountryCode().String()) n.SetAttribute("Country", r.Country) @@ -81,49 +81,49 @@ func TestValidator_VerifyAndUpdate(t *testing.T) { // test record with valid but n.SetAttribute("SubDiv", r.SubDivName) n.SetAttribute("Continent", r.Cont.String()) - require.NoError(t, validator.VerifyAndUpdate(n)) + require.NoError(t, validator.Verify(n)) }) t.Run("invalid SN expansion", func(t *testing.T) { t.Run("invalid Country", func(t *testing.T) { n := nodeInfoWithSomeAttrs() - addLocodeAttr(n, [2]string{"RU", "SPB"}) + addLocodeAttr(&n, [2]string{"RU", "SPB"}) n.SetAttribute("CountryCode", r.Country+"bad") - require.Error(t, validator.VerifyAndUpdate(n)) + require.Error(t, validator.Verify(n)) }) t.Run("invalid Location", func(t *testing.T) { n := nodeInfoWithSomeAttrs() - addLocodeAttr(n, [2]string{"RU", "SPB"}) + addLocodeAttr(&n, [2]string{"RU", "SPB"}) n.SetAttribute("Location", r.Location+"bad") - require.Error(t, validator.VerifyAndUpdate(n)) + require.Error(t, validator.Verify(n)) }) t.Run("invalid SubDivCode", func(t *testing.T) { n := nodeInfoWithSomeAttrs() - addLocodeAttr(n, [2]string{"RU", "SPB"}) + addLocodeAttr(&n, [2]string{"RU", "SPB"}) n.SetAttribute("SubDivCode", r.SubDivCode+"bad") - require.Error(t, validator.VerifyAndUpdate(n)) + require.Error(t, validator.Verify(n)) }) t.Run("invalid SubDivName", func(t *testing.T) { n := nodeInfoWithSomeAttrs() - addLocodeAttr(n, [2]string{"RU", "SPB"}) + addLocodeAttr(&n, [2]string{"RU", "SPB"}) n.SetAttribute("SubDivName", r.SubDivName+"bad") - require.Error(t, validator.VerifyAndUpdate(n)) + require.Error(t, validator.Verify(n)) }) t.Run("invalid Continent", func(t *testing.T) { n := nodeInfoWithSomeAttrs() - addLocodeAttr(n, [2]string{"RU", "SPB"}) + addLocodeAttr(&n, [2]string{"RU", "SPB"}) n.SetAttribute("Continent", r.Cont.String()+"bad") - require.Error(t, validator.VerifyAndUpdate(n)) + require.Error(t, validator.Verify(n)) }) }) }) diff --git a/pkg/innerring/processors/netmap/nodevalidation/privatedomains/validator.go b/pkg/innerring/processors/netmap/nodevalidation/privatedomains/validator.go index 2e6ef92693..26ed20e97c 100644 --- a/pkg/innerring/processors/netmap/nodevalidation/privatedomains/validator.go +++ b/pkg/innerring/processors/netmap/nodevalidation/privatedomains/validator.go @@ -62,7 +62,7 @@ var ( // access denial or the check cannot be done at the moment. // // VerifyAndUpdate does not mutate the argument. -func (x *Validator) VerifyAndUpdate(info *netmap.NodeInfo) error { +func (x *Validator) Verify(info netmap.NodeInfo) error { verifiedNodesDomain := info.VerifiedNodesDomain() if verifiedNodesDomain == "" { return nil diff --git a/pkg/innerring/processors/netmap/nodevalidation/privatedomains/validator_test.go b/pkg/innerring/processors/netmap/nodevalidation/privatedomains/validator_test.go index a3d70b2204..d72a144dc3 100644 --- a/pkg/innerring/processors/netmap/nodevalidation/privatedomains/validator_test.go +++ b/pkg/innerring/processors/netmap/nodevalidation/privatedomains/validator_test.go @@ -91,7 +91,7 @@ func TestValidator_VerifyAndUpdate(t *testing.T) { v := New(newTestNNS()) - err := v.VerifyAndUpdate(&node) + err := v.Verify(node) require.NoError(t, err) }) @@ -102,11 +102,11 @@ func TestValidator_VerifyAndUpdate(t *testing.T) { v := New(newTestNNS()) node.SetPublicKey(nil) - err := v.VerifyAndUpdate(&node) + err := v.Verify(node) require.ErrorIs(t, err, errMissingNodeBinaryKey) node.SetPublicKey([]byte{}) - err = v.VerifyAndUpdate(&node) + err = v.Verify(node) require.ErrorIs(t, err, errMissingNodeBinaryKey) }) @@ -114,14 +114,14 @@ func TestValidator_VerifyAndUpdate(t *testing.T) { anyErr := errors.New("any error") v := New(newTestNNSWithStaticErr(anyErr)) - err := v.VerifyAndUpdate(&node) + err := v.Verify(node) require.ErrorIs(t, err, anyErr) }) t.Run("missing domain", func(t *testing.T) { v := New(newTestNNS()) - err := v.VerifyAndUpdate(&node) + err := v.Verify(node) require.Error(t, err) require.NotErrorIs(t, err, errAccessDenied) }) @@ -132,19 +132,19 @@ func TestValidator_VerifyAndUpdate(t *testing.T) { nns.registerDomain(verifiedDomain) - err := v.VerifyAndUpdate(&node) + err := v.Verify(node) require.ErrorIs(t, err, errAccessDenied) nns.addDomainRecord(verifiedDomain, anyOtherNeoAddress) - err = v.VerifyAndUpdate(&node) + err = v.Verify(node) require.ErrorIs(t, err, errAccessDenied) nns.addDomainRecord(verifiedDomain, nodeNeoAddress) - err = v.VerifyAndUpdate(&node) + err = v.Verify(node) require.NoError(t, err) nns.removeDomainRecord(verifiedDomain, nodeNeoAddress) - err = v.VerifyAndUpdate(&node) + err = v.Verify(node) require.ErrorIs(t, err, errAccessDenied) }) } diff --git a/pkg/innerring/processors/netmap/nodevalidation/state/validator.go b/pkg/innerring/processors/netmap/nodevalidation/state/validator.go index 5638fc5c85..2cbb4b1cf5 100644 --- a/pkg/innerring/processors/netmap/nodevalidation/state/validator.go +++ b/pkg/innerring/processors/netmap/nodevalidation/state/validator.go @@ -44,18 +44,18 @@ func (x *NetMapCandidateValidator) SetNetworkSettings(netSettings NetworkSetting x.netSettings = netSettings } -// VerifyAndUpdate checks state of the network map candidate described by +// Verify checks state of the network map candidate described by // netmap.NodeInfo parameter. Returns no error if status is correct, otherwise // returns an error describing a violation of the rules: // // status MUST be either ONLINE or MAINTENANCE; // if status is MAINTENANCE, then it SHOULD be allowed by the network. // -// VerifyAndUpdate does not mutate the parameter in a binary format. +// Verify does not mutate the parameter in a binary format. // MUST NOT be called before SetNetworkSettings. // // See also netmap.NodeInfo.IsOnline/SetOnline and other similar methods. -func (x *NetMapCandidateValidator) VerifyAndUpdate(node *netmap.NodeInfo) error { +func (x *NetMapCandidateValidator) Verify(node netmap.NodeInfo) error { if node.IsOnline() { return nil } diff --git a/pkg/innerring/processors/netmap/nodevalidation/state/validator_test.go b/pkg/innerring/processors/netmap/nodevalidation/state/validator_test.go index e1acf96a85..ec5bbd6275 100644 --- a/pkg/innerring/processors/netmap/nodevalidation/state/validator_test.go +++ b/pkg/innerring/processors/netmap/nodevalidation/state/validator_test.go @@ -81,7 +81,7 @@ func TestValidator_VerifyAndUpdate(t *testing.T) { testCase.validatorPreparer(&v) } - err := v.VerifyAndUpdate(&node) + err := v.Verify(node) if testCase.valid { require.NoError(t, err, testCase.name) diff --git a/pkg/innerring/processors/netmap/nodevalidation/structure/calls.go b/pkg/innerring/processors/netmap/nodevalidation/structure/calls.go index 0ee22cf615..2f146d78e9 100644 --- a/pkg/innerring/processors/netmap/nodevalidation/structure/calls.go +++ b/pkg/innerring/processors/netmap/nodevalidation/structure/calls.go @@ -7,9 +7,9 @@ import ( "github.com/nspcc-dev/neofs-sdk-go/netmap" ) -// VerifyAndUpdate calls network.VerifyAddress. -func (v *Validator) VerifyAndUpdate(n *netmap.NodeInfo) error { - err := network.VerifyMultiAddress(*n) +// Verify calls network.VerifyAddress. +func (v *Validator) Verify(n netmap.NodeInfo) error { + err := network.VerifyMultiAddress(n) if err != nil { return fmt.Errorf("could not verify multiaddress: %w", err) } diff --git a/pkg/innerring/processors/netmap/nodevalidation/validator.go b/pkg/innerring/processors/netmap/nodevalidation/validator.go index fdb88b927b..ad2c960400 100644 --- a/pkg/innerring/processors/netmap/nodevalidation/validator.go +++ b/pkg/innerring/processors/netmap/nodevalidation/validator.go @@ -23,12 +23,12 @@ func New(validators ...netmap.NodeValidator) *CompositeValidator { return &CompositeValidator{validators} } -// VerifyAndUpdate passes apinetmap.NodeInfo to wrapped validators. +// Verify passes apinetmap.NodeInfo to wrapped validators. // // If error appears, returns it immediately. -func (c *CompositeValidator) VerifyAndUpdate(ni *apinetmap.NodeInfo) error { +func (c *CompositeValidator) Verify(ni apinetmap.NodeInfo) error { for _, v := range c.validators { - if err := v.VerifyAndUpdate(ni); err != nil { + if err := v.Verify(ni); err != nil { return err } } diff --git a/pkg/innerring/processors/netmap/process_peers.go b/pkg/innerring/processors/netmap/process_peers.go index af86476803..2d809711c4 100644 --- a/pkg/innerring/processors/netmap/process_peers.go +++ b/pkg/innerring/processors/netmap/process_peers.go @@ -37,8 +37,8 @@ func (np *Processor) processAddPeer(ev netmapEvent.AddPeer) { return } - // validate and update node info - err = np.nodeValidator.VerifyAndUpdate(&nodeInfo) + // validate node info + err = np.nodeValidator.Verify(nodeInfo) if err != nil { np.log.Warn("could not verify and update information about network map candidate", zap.String("public_key", hex.EncodeToString(nodeInfo.PublicKey())), diff --git a/pkg/innerring/processors/netmap/processor.go b/pkg/innerring/processors/netmap/processor.go index af5e149d9c..85e6356fbe 100644 --- a/pkg/innerring/processors/netmap/processor.go +++ b/pkg/innerring/processors/netmap/processor.go @@ -38,15 +38,10 @@ type ( // of information about the node and its finalization for adding // to the network map. NodeValidator interface { - // Must verify and optionally update NodeInfo structure. + // Verify must verify NodeInfo structure. // // Must return an error if NodeInfo input is invalid. - // Must return an error if it is not possible to correctly - // change the structure for sending to the network map. - // - // If no error occurs, the parameter must point to the - // ready-made NodeInfo structure. - VerifyAndUpdate(*netmap.NodeInfo) error + Verify(netmap.NodeInfo) error } // Processor of events produced by network map contract From d0d38e70b4ab30ccab0fda598adf6d89d9b48f10 Mon Sep 17 00:00:00 2001 From: Pavel Karpy Date: Mon, 20 Nov 2023 18:34:26 +0300 Subject: [PATCH 6/8] node, ir: Do not do useless conversion with locodes String format is checked on the locode lib side (if no err was returned, attribute value should be OK). Key creation does nothing except some type conversions and checks that have already been performed. LOCODE format is fixed and its bound constants are opened. Signed-off-by: Pavel Karpy --- cmd/neofs-node/attributes.go | 17 +++++------------ .../netmap/nodevalidation/locode/calls.go | 8 +++++--- .../netmap/nodevalidation/locode/validator.go | 12 ++---------- 3 files changed, 12 insertions(+), 25 deletions(-) diff --git a/cmd/neofs-node/attributes.go b/cmd/neofs-node/attributes.go index 1424f3685a..c385e5b9ce 100644 --- a/cmd/neofs-node/attributes.go +++ b/cmd/neofs-node/attributes.go @@ -24,14 +24,15 @@ func parseAttributes(c *cfg) { return } - key, record, err := getRecord(locAttr) + record, err := getRecord(locAttr) if err != nil { fatalOnErr(fmt.Errorf("could not get locode record from DB: %w", err)) } + countryCode := locAttr[:locodedb.CountryCodeLen] n := &c.cfgNodeInfo.localInfo - setLocodeAttr(n, "CountryCode", key.CountryCode().String()) + setLocodeAttr(n, "CountryCode", countryCode) setLocodeAttr(n, "Country", record.Country) setLocodeAttr(n, "Location", record.Location) setLocodeAttr(n, "Continent", record.Cont.String()) @@ -43,17 +44,9 @@ func parseAttributes(c *cfg) { } } -func getRecord(lc string) (*locodedb.Key, locodedb.Record, error) { - country, location := lc[:2], lc[2:] - if lc[2] == ' ' { - location = lc[3:] - } - key, err := locodedb.NewKey(country, location) - if err != nil { - return nil, locodedb.Record{}, err - } +func getRecord(lc string) (locodedb.Record, error) { rec, err := locodedb.Get(lc) - return key, rec, err + return rec, err } func setLocodeAttr(ni *netmap.NodeInfo, key, value string) { diff --git a/pkg/innerring/processors/netmap/nodevalidation/locode/calls.go b/pkg/innerring/processors/netmap/nodevalidation/locode/calls.go index db694082fb..f3fc6d9340 100644 --- a/pkg/innerring/processors/netmap/nodevalidation/locode/calls.go +++ b/pkg/innerring/processors/netmap/nodevalidation/locode/calls.go @@ -3,6 +3,7 @@ package locode import ( "fmt" + "github.com/nspcc-dev/locode-db/pkg/locodedb" "github.com/nspcc-dev/neofs-sdk-go/netmap" ) @@ -15,15 +16,16 @@ import ( // If n contains UN-LOCODE attribute and its value does not // match the UN/LOCODE format, an error is returned. func (v *Validator) Verify(n netmap.NodeInfo) error { - if n.LOCODE() == "" { + lAttr := n.LOCODE() + if lAttr == "" { return nil } - key, record, err := getRecord(n.LOCODE()) + record, err := getRecord(lAttr) if err != nil { return fmt.Errorf("could not get locode record from DB: %w", err) } - err = checkAttribute(n, "CountryCode", key.CountryCode().String()) + err = checkAttribute(n, "CountryCode", lAttr[:locodedb.CountryCodeLen]) if err != nil { return err } diff --git a/pkg/innerring/processors/netmap/nodevalidation/locode/validator.go b/pkg/innerring/processors/netmap/nodevalidation/locode/validator.go index c88efcbabc..06c446fe4c 100644 --- a/pkg/innerring/processors/netmap/nodevalidation/locode/validator.go +++ b/pkg/innerring/processors/netmap/nodevalidation/locode/validator.go @@ -23,15 +23,7 @@ func New() *Validator { return &Validator{} } -func getRecord(lc string) (*locodedb.Key, locodedb.Record, error) { - country, location := lc[:2], lc[2:] - if lc[2] == ' ' { - location = lc[3:] - } - key, err := locodedb.NewKey(country, location) - if err != nil { - return nil, locodedb.Record{}, err - } +func getRecord(lc string) (locodedb.Record, error) { rec, err := locodedb.Get(lc) - return key, rec, err + return rec, err } From 532f42303428f349453fea157a2190fa0f3f9362 Mon Sep 17 00:00:00 2001 From: Pavel Karpy Date: Tue, 21 Nov 2023 19:33:01 +0300 Subject: [PATCH 7/8] go.mod: Update to the latest SDK Also, use locode getters instead of the hardcoded ones. Signed-off-by: Pavel Karpy --- cmd/neofs-node/attributes.go | 34 ++++++++-------- go.mod | 2 +- go.sum | 4 +- .../netmap/nodevalidation/locode/calls.go | 39 +++++++------------ 4 files changed, 33 insertions(+), 46 deletions(-) diff --git a/cmd/neofs-node/attributes.go b/cmd/neofs-node/attributes.go index c385e5b9ce..9dec8ae79b 100644 --- a/cmd/neofs-node/attributes.go +++ b/cmd/neofs-node/attributes.go @@ -6,7 +6,6 @@ import ( "github.com/nspcc-dev/locode-db/pkg/locodedb" nodeconfig "github.com/nspcc-dev/neofs-node/cmd/neofs-node/config/node" "github.com/nspcc-dev/neofs-node/pkg/util/attributes" - "github.com/nspcc-dev/neofs-sdk-go/netmap" ) func parseAttributes(c *cfg) { @@ -32,15 +31,23 @@ func parseAttributes(c *cfg) { countryCode := locAttr[:locodedb.CountryCodeLen] n := &c.cfgNodeInfo.localInfo - setLocodeAttr(n, "CountryCode", countryCode) - setLocodeAttr(n, "Country", record.Country) - setLocodeAttr(n, "Location", record.Location) - setLocodeAttr(n, "Continent", record.Cont.String()) - if subDivCode := record.SubDivCode; subDivCode != "" { - setLocodeAttr(n, "SubDivCode", subDivCode) + if countryCode != "" && n.CountryCode() == "" { + n.SetCountryCode(countryCode) } - if subDivName := record.SubDivName; subDivName != "" { - setLocodeAttr(n, "SubDiv", subDivName) + if record.Country != "" && n.CountryName() == "" { + n.SetCountryName(record.Country) + } + if record.Location != "" && n.LocationName() == "" { + n.SetLocationName(record.Location) + } + if record.Cont.String() != "" && n.ContinentName() == "" { + n.SetContinentName(record.Cont.String()) + } + if record.SubDivCode != "" && n.SubdivisionCode() == "" { + n.SetSubdivisionCode(record.SubDivCode) + } + if record.SubDivName != "" && n.SubdivisionName() == "" { + n.SetSubdivisionName(record.SubDivName) } } @@ -48,12 +55,3 @@ func getRecord(lc string) (locodedb.Record, error) { rec, err := locodedb.Get(lc) return rec, err } - -func setLocodeAttr(ni *netmap.NodeInfo, key, value string) { - valHave := ni.Attribute(key) - if valHave != "" { - return - } - - ni.SetAttribute(key, value) -} diff --git a/go.mod b/go.mod index 50e0c73645..e8be9cb4b0 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/nspcc-dev/neo-go v0.103.1 github.com/nspcc-dev/neofs-api-go/v2 v2.14.0 github.com/nspcc-dev/neofs-contract v0.18.0 - github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.11.0.20231113180740-3b24af0410c0 + github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.11.0.20231121125354-d72d76ccb0ba github.com/nspcc-dev/tzhash v1.7.1 github.com/olekukonko/tablewriter v0.0.5 github.com/panjf2000/ants/v2 v2.8.2 diff --git a/go.sum b/go.sum index c486555bd2..29bc2902ee 100644 --- a/go.sum +++ b/go.sum @@ -257,8 +257,8 @@ github.com/nspcc-dev/neofs-contract v0.18.0 h1:9g50b16s0mQFFskG93yRSWh4KL7yYOW+x github.com/nspcc-dev/neofs-contract v0.18.0/go.mod h1:UQr1rUjg0eibLwJd6vfsJJEUBnmRysCg8XQd1HYiS2w= github.com/nspcc-dev/neofs-crypto v0.4.0 h1:5LlrUAM5O0k1+sH/sktBtrgfWtq1pgpDs09fZo+KYi4= github.com/nspcc-dev/neofs-crypto v0.4.0/go.mod h1:6XJ8kbXgOfevbI2WMruOtI+qUJXNwSGM/E9eClXxPHs= -github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.11.0.20231113180740-3b24af0410c0 h1:y24pnVwDLaBAyh8fFcptAvtVfVDay/5jONgtO+cWZfI= -github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.11.0.20231113180740-3b24af0410c0/go.mod h1:6ok9MU40TP0xAVfzisIg4KP+qhP670hra0mKpIGlWT8= +github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.11.0.20231121125354-d72d76ccb0ba h1:dQDBBqmT2rlJGgkeeF3UurB3VgG7buMHDHcz5UQ3bro= +github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.11.0.20231121125354-d72d76ccb0ba/go.mod h1:2PKUuH7kQaAmQ/USBgmiD/k08ssnSvayor6JAFhrC1c= github.com/nspcc-dev/rfc6979 v0.2.0 h1:3e1WNxrN60/6N0DW7+UYisLeZJyfqZTNOjeV/toYvOE= github.com/nspcc-dev/rfc6979 v0.2.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso= github.com/nspcc-dev/tzhash v1.7.1 h1:6zmexLqdTF/ssbUAh7XJS7RxgKWaw28kdNpE/4UFdEU= diff --git a/pkg/innerring/processors/netmap/nodevalidation/locode/calls.go b/pkg/innerring/processors/netmap/nodevalidation/locode/calls.go index f3fc6d9340..fc945bad05 100644 --- a/pkg/innerring/processors/netmap/nodevalidation/locode/calls.go +++ b/pkg/innerring/processors/netmap/nodevalidation/locode/calls.go @@ -25,39 +25,28 @@ func (v *Validator) Verify(n netmap.NodeInfo) error { return fmt.Errorf("could not get locode record from DB: %w", err) } - err = checkAttribute(n, "CountryCode", lAttr[:locodedb.CountryCodeLen]) - if err != nil { - return err + if want, got := lAttr[:locodedb.CountryCodeLen], n.CountryCode(); want != got { + return wrongLocodeAttrErr("country code", want, got) } - err = checkAttribute(n, "Country", record.Country) - if err != nil { - return err + if want, got := record.Country, n.CountryName(); want != got { + return wrongLocodeAttrErr("country name", want, got) } - err = checkAttribute(n, "Location", record.Location) - if err != nil { - return err + if want, got := record.Location, n.LocationName(); want != got { + return wrongLocodeAttrErr("location", want, got) } - err = checkAttribute(n, "Continent", record.Cont.String()) - if err != nil { - return err + if want, got := record.Cont.String(), n.ContinentName(); want != got { + return wrongLocodeAttrErr("continent", want, got) } - err = checkAttribute(n, "SubDivCode", record.SubDivCode) - if err != nil { - return err + if want, got := record.SubDivCode, n.SubdivisionCode(); want != got { + return wrongLocodeAttrErr("subdivision code", want, got) } - err = checkAttribute(n, "SubDiv", record.SubDivName) - if err != nil { - return err + if want, got := record.SubDivName, n.SubdivisionName(); want != got { + return wrongLocodeAttrErr("subdivision name", want, got) } return nil } -func checkAttribute(n netmap.NodeInfo, key, expectedVal string) error { - val := n.Attribute(key) - if val != expectedVal { - return fmt.Errorf("wrong '%q' attribute value: want '%q', got '%q'", key, expectedVal, val) - } - - return nil +func wrongLocodeAttrErr(attrName, want, got string) error { + return fmt.Errorf("wrong %q attribute value: want '%q', got '%q'", attrName, want, got) } From f8f081709d1a14648dc5ba62dc664560d71c11e0 Mon Sep 17 00:00:00 2001 From: Pavel Karpy Date: Thu, 23 Nov 2023 20:39:35 +0300 Subject: [PATCH 8/8] node: Warn user on LOCODE mismatches If a configuration sets LOCODE attributes (non-emtpy values) and they differ from "the database" ones, use the user's ones still but with a warning message. Signed-off-by: Pavel Karpy --- cmd/neofs-node/attributes.go | 66 +++++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 12 deletions(-) diff --git a/cmd/neofs-node/attributes.go b/cmd/neofs-node/attributes.go index 9dec8ae79b..a381b22f39 100644 --- a/cmd/neofs-node/attributes.go +++ b/cmd/neofs-node/attributes.go @@ -6,6 +6,7 @@ import ( "github.com/nspcc-dev/locode-db/pkg/locodedb" nodeconfig "github.com/nspcc-dev/neofs-node/cmd/neofs-node/config/node" "github.com/nspcc-dev/neofs-node/pkg/util/attributes" + "go.uber.org/zap" ) func parseAttributes(c *cfg) { @@ -31,23 +32,58 @@ func parseAttributes(c *cfg) { countryCode := locAttr[:locodedb.CountryCodeLen] n := &c.cfgNodeInfo.localInfo - if countryCode != "" && n.CountryCode() == "" { - n.SetCountryCode(countryCode) + fromUser := n.CountryCode() + if fromUser != "" && fromUser != countryCode { + c.log.Warn("locode attribute mismatch, configuration value kept: country code", + zap.String("configuration_value", fromUser), + zap.String("database_value", countryCode)) + } else { + setIfNotEmpty(n.SetCountryCode, countryCode) } - if record.Country != "" && n.CountryName() == "" { - n.SetCountryName(record.Country) + + fromUser = n.CountryName() + if fromUser != "" && fromUser != record.Country { + c.log.Warn("locode attribute mismatch, configuration value kept: country name", + zap.String("configuration_value", fromUser), + zap.String("database_value", record.Country)) + } else { + setIfNotEmpty(n.SetCountryName, record.Country) } - if record.Location != "" && n.LocationName() == "" { - n.SetLocationName(record.Location) + + fromUser = n.LocationName() + if fromUser != "" && fromUser != record.Location { + c.log.Warn("locode attribute mismatch, configuration value kept: location name", + zap.String("configuration_value", fromUser), + zap.String("database_value", record.Location)) + } else { + setIfNotEmpty(n.SetLocationName, record.Location) } - if record.Cont.String() != "" && n.ContinentName() == "" { - n.SetContinentName(record.Cont.String()) + + fromUser = n.ContinentName() + if fromUser != "" && fromUser != record.Cont.String() { + c.log.Warn("locode attribute mismatch, configuration value kept: continent", + zap.String("configuration_value", fromUser), + zap.String("database_value", record.Cont.String())) + } else { + setIfNotEmpty(n.SetContinentName, record.Cont.String()) } - if record.SubDivCode != "" && n.SubdivisionCode() == "" { - n.SetSubdivisionCode(record.SubDivCode) + + fromUser = n.SubdivisionCode() + if fromUser != "" && fromUser != record.SubDivCode { + c.log.Warn("locode attribute mismatch, configuration value kept: subdivision code", + zap.String("configuration_value", fromUser), + zap.String("database_value", record.SubDivCode)) + } else { + setIfNotEmpty(n.SetSubdivisionCode, record.SubDivCode) } - if record.SubDivName != "" && n.SubdivisionName() == "" { - n.SetSubdivisionName(record.SubDivName) + + fromUser = n.SubdivisionName() + if fromUser != "" && fromUser != record.SubDivName { + c.log.Warn("locode attribute mismatch, configuration value kept: subdivision name", + zap.String("configuration_value", fromUser), + zap.String("database_value", record.SubDivName)) + } else { + setIfNotEmpty(n.SetSubdivisionName, record.SubDivName) } } @@ -55,3 +91,9 @@ func getRecord(lc string) (locodedb.Record, error) { rec, err := locodedb.Get(lc) return rec, err } + +func setIfNotEmpty(setter func(string), value string) { + if value != "" { + setter(value) + } +}