satellite/nodeselection: add geofencing constraints to the node selection criteria

Closes https://github.com/storj/storj/issues/4242
Change-Id: Ieda59a4f37c673e4e81abb4c89c09daf3199bbc7
This commit is contained in:
Márton Elek 2021-10-29 14:29:14 +02:00 committed by Elek, Márton
parent 696b8f0d8e
commit 9bdcc415bc
8 changed files with 83 additions and 12 deletions

2
go.mod
View File

@ -47,7 +47,7 @@ require (
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e
gopkg.in/segmentio/analytics-go.v3 v3.1.0 gopkg.in/segmentio/analytics-go.v3 v3.1.0
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c
storj.io/common v0.0.0-20211102144601-401a79f0706a storj.io/common v0.0.0-20211108092228-14e900b161d9
storj.io/drpc v0.0.26 storj.io/drpc v0.0.26
storj.io/monkit-jaeger v0.0.0-20210426161729-debb1cbcbbd7 storj.io/monkit-jaeger v0.0.0-20210426161729-debb1cbcbbd7
storj.io/private v0.0.0-20211029202355-a7eae71c382a storj.io/private v0.0.0-20211029202355-a7eae71c382a

4
go.sum
View File

@ -880,8 +880,8 @@ sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3
storj.io/common v0.0.0-20200424175742-65ac59022f4f/go.mod h1:pZyXiIE7bGETIRXtfs0nICqMwp7PM8HqnDuyUeldNA0= storj.io/common v0.0.0-20200424175742-65ac59022f4f/go.mod h1:pZyXiIE7bGETIRXtfs0nICqMwp7PM8HqnDuyUeldNA0=
storj.io/common v0.0.0-20210805073808-8e0feb09e92a/go.mod h1:mhZYWpTojKsACxWE66RfXNz19zbyr/uEDVWHJH8dHog= storj.io/common v0.0.0-20210805073808-8e0feb09e92a/go.mod h1:mhZYWpTojKsACxWE66RfXNz19zbyr/uEDVWHJH8dHog=
storj.io/common v0.0.0-20211019072056-34a5992b4856/go.mod h1:objobGrIWQwhmTSpSm6Y7ykd40wZjB7CezNfic5YLKg= storj.io/common v0.0.0-20211019072056-34a5992b4856/go.mod h1:objobGrIWQwhmTSpSm6Y7ykd40wZjB7CezNfic5YLKg=
storj.io/common v0.0.0-20211102144601-401a79f0706a h1:6AF6LcFbZ8PtQX6omT6npU8Yhh1g7OG2emZKuLgS5+o= storj.io/common v0.0.0-20211108092228-14e900b161d9 h1:PxSH22djpdRU1wHS45QE6Yy9oSsBnl1frp2tURKOV1k=
storj.io/common v0.0.0-20211102144601-401a79f0706a/go.mod h1:a2Kw7Uipu929OFANfWKLHRoD0JfhgssikEvimd6hbSQ= storj.io/common v0.0.0-20211108092228-14e900b161d9/go.mod h1:a2Kw7Uipu929OFANfWKLHRoD0JfhgssikEvimd6hbSQ=
storj.io/drpc v0.0.11/go.mod h1:TiFc2obNjL9/3isMW1Rpxjy8V9uE0B2HMeMFGiiI7Iw= storj.io/drpc v0.0.11/go.mod h1:TiFc2obNjL9/3isMW1Rpxjy8V9uE0B2HMeMFGiiI7Iw=
storj.io/drpc v0.0.24/go.mod h1:ofQUDPQbbIymRDKE0tms48k8bLP5Y+dsI9CbXGv3gko= storj.io/drpc v0.0.24/go.mod h1:ofQUDPQbbIymRDKE0tms48k8bLP5Y+dsI9CbXGv3gko=
storj.io/drpc v0.0.26 h1:T6jJzjby7QUa/2XHR1qMxTCENpDHEw4/o+kfDfZQqQI= storj.io/drpc v0.0.26 h1:T6jJzjby7QUa/2XHR1qMxTCENpDHEw4/o+kfDfZQqQI=

View File

@ -3,12 +3,15 @@
package uploadselection package uploadselection
import "storj.io/common/storj" import (
"storj.io/common/storj"
)
// Criteria to filter nodes. // Criteria to filter nodes.
type Criteria struct { type Criteria struct {
ExcludeNodeIDs []storj.NodeID ExcludeNodeIDs []storj.NodeID
AutoExcludeSubnets map[string]struct{} // initialize it with empty map to keep only one node per subnet. AutoExcludeSubnets map[string]struct{} // initialize it with empty map to keep only one node per subnet.
Placement storj.PlacementConstraint
} }
// MatchInclude returns with true if node is selected. // MatchInclude returns with true if node is selected.
@ -16,6 +19,11 @@ func (c *Criteria) MatchInclude(node *Node) bool {
if ContainsID(c.ExcludeNodeIDs, node.ID) { if ContainsID(c.ExcludeNodeIDs, node.ID) {
return false return false
} }
if !c.Placement.AllowedCountry(node.CountryCode) {
return false
}
if c.AutoExcludeSubnets != nil { if c.AutoExcludeSubnets != nil {
if _, excluded := c.AutoExcludeSubnets[node.LastNet]; excluded { if _, excluded := c.AutoExcludeSubnets[node.LastNet]; excluded {
return false return false

View File

@ -9,6 +9,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"storj.io/common/storj" "storj.io/common/storj"
"storj.io/common/storj/location"
"storj.io/common/testrand" "storj.io/common/testrand"
) )
@ -81,3 +82,59 @@ func TestCriteria_NodeIDAndSubnet(t *testing.T) {
})) }))
} }
func TestCriteria_Geofencing(t *testing.T) {
eu := Criteria{
Placement: storj.EU,
}
us := Criteria{
Placement: storj.US,
}
cases := []struct {
name string
country location.CountryCode
criteria Criteria
expected bool
}{
{
name: "US matches US selector",
country: location.UnitedStates,
criteria: us,
expected: true,
},
{
name: "Germany is EU",
country: location.Germany,
criteria: eu,
expected: true,
},
{
name: "US is not eu",
country: location.UnitedStates,
criteria: eu,
expected: false,
},
{
name: "Empty country doesn't match region",
country: location.CountryCode(0),
criteria: eu,
expected: false,
},
{
name: "Empty country doesn't match country",
country: location.CountryCode(0),
criteria: us,
expected: false,
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
assert.Equal(t, c.expected, c.criteria.MatchInclude(&Node{
CountryCode: c.country,
}))
})
}
}

View File

@ -5,20 +5,23 @@ package uploadselection
import ( import (
"storj.io/common/storj" "storj.io/common/storj"
"storj.io/common/storj/location"
) )
// Node defines necessary information for node-selection. // Node defines necessary information for node-selection.
type Node struct { type Node struct {
storj.NodeURL storj.NodeURL
LastNet string LastNet string
LastIPPort string LastIPPort string
CountryCode location.CountryCode
} }
// Clone returns a deep clone of the selected node. // Clone returns a deep clone of the selected node.
func (node *Node) Clone() *Node { func (node *Node) Clone() *Node {
return &Node{ return &Node{
NodeURL: node.NodeURL, NodeURL: node.NodeURL,
LastNet: node.LastNet, LastNet: node.LastNet,
LastIPPort: node.LastIPPort, LastIPPort: node.LastIPPort,
CountryCode: node.CountryCode,
} }
} }

View File

@ -87,6 +87,7 @@ type Request struct {
NewFraction float64 NewFraction float64
Distinct bool Distinct bool
ExcludedIDs []storj.NodeID ExcludedIDs []storj.NodeID
Placement storj.PlacementConstraint
} }
// Select selects requestedCount nodes where there will be newFraction nodes. // Select selects requestedCount nodes where there will be newFraction nodes.
@ -110,6 +111,8 @@ func (state *State) Select(ctx context.Context, request Request) (_ []*Node, err
criteria.ExcludeNodeIDs = request.ExcludedIDs criteria.ExcludeNodeIDs = request.ExcludedIDs
} }
criteria.Placement = request.Placement
if request.Distinct { if request.Distinct {
criteria.AutoExcludeSubnets = make(map[string]struct{}) criteria.AutoExcludeSubnets = make(map[string]struct{})
for _, id := range request.ExcludedIDs { for _, id := range request.ExcludedIDs {

View File

@ -10,7 +10,7 @@ require (
github.com/spf13/pflag v1.0.5 github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.7.0
go.uber.org/zap v1.17.0 go.uber.org/zap v1.17.0
storj.io/common v0.0.0-20211102144601-401a79f0706a storj.io/common v0.0.0-20211108092228-14e900b161d9
storj.io/gateway-mt v1.14.4-0.20211015103214-01eddbc864fb storj.io/gateway-mt v1.14.4-0.20211015103214-01eddbc864fb
storj.io/private v0.0.0-20211029202355-a7eae71c382a storj.io/private v0.0.0-20211029202355-a7eae71c382a
storj.io/storj v0.12.1-0.20211102170500-1de8a695e84a storj.io/storj v0.12.1-0.20211102170500-1de8a695e84a

View File

@ -1396,8 +1396,8 @@ storj.io/common v0.0.0-20210805073808-8e0feb09e92a/go.mod h1:mhZYWpTojKsACxWE66R
storj.io/common v0.0.0-20210916151047-6aaeb34bb916/go.mod h1:objobGrIWQwhmTSpSm6Y7ykd40wZjB7CezNfic5YLKg= storj.io/common v0.0.0-20210916151047-6aaeb34bb916/go.mod h1:objobGrIWQwhmTSpSm6Y7ykd40wZjB7CezNfic5YLKg=
storj.io/common v0.0.0-20211006105453-d3fff091f9d2/go.mod h1:objobGrIWQwhmTSpSm6Y7ykd40wZjB7CezNfic5YLKg= storj.io/common v0.0.0-20211006105453-d3fff091f9d2/go.mod h1:objobGrIWQwhmTSpSm6Y7ykd40wZjB7CezNfic5YLKg=
storj.io/common v0.0.0-20211019072056-34a5992b4856/go.mod h1:objobGrIWQwhmTSpSm6Y7ykd40wZjB7CezNfic5YLKg= storj.io/common v0.0.0-20211019072056-34a5992b4856/go.mod h1:objobGrIWQwhmTSpSm6Y7ykd40wZjB7CezNfic5YLKg=
storj.io/common v0.0.0-20211102144601-401a79f0706a h1:6AF6LcFbZ8PtQX6omT6npU8Yhh1g7OG2emZKuLgS5+o= storj.io/common v0.0.0-20211108092228-14e900b161d9 h1:PxSH22djpdRU1wHS45QE6Yy9oSsBnl1frp2tURKOV1k=
storj.io/common v0.0.0-20211102144601-401a79f0706a/go.mod h1:a2Kw7Uipu929OFANfWKLHRoD0JfhgssikEvimd6hbSQ= storj.io/common v0.0.0-20211108092228-14e900b161d9/go.mod h1:a2Kw7Uipu929OFANfWKLHRoD0JfhgssikEvimd6hbSQ=
storj.io/dotworld v0.0.0-20210324183515-0d11aeccd840/go.mod h1:KU9YvEgRrMMiWLvH8pzn1UkoCoxggKIPvQxmNdx7aXQ= storj.io/dotworld v0.0.0-20210324183515-0d11aeccd840/go.mod h1:KU9YvEgRrMMiWLvH8pzn1UkoCoxggKIPvQxmNdx7aXQ=
storj.io/drpc v0.0.11/go.mod h1:TiFc2obNjL9/3isMW1Rpxjy8V9uE0B2HMeMFGiiI7Iw= storj.io/drpc v0.0.11/go.mod h1:TiFc2obNjL9/3isMW1Rpxjy8V9uE0B2HMeMFGiiI7Iw=
storj.io/drpc v0.0.24/go.mod h1:ofQUDPQbbIymRDKE0tms48k8bLP5Y+dsI9CbXGv3gko= storj.io/drpc v0.0.24/go.mod h1:ofQUDPQbbIymRDKE0tms48k8bLP5Y+dsI9CbXGv3gko=