feat(sync): support for periodic repo sync in scale-out cluster (#2424)

This commit includes support for periodic repo sync in a scale-out
cluster.
Before this commit, all cluster members would sync all the repos as
the config is shared.

With this change, in periodic sync, the cluster member checks whether
it manages the repo. If it does not manage the repo, it will skip the
sync.

This commit also includes a unit test to test on-demand sync too, but
there are no logic changes for it as it is implicitly handled by the
proxying logic.

Signed-off-by: Vishwas Rajashekar <vrajashe@cisco.com>
This commit is contained in:
Vishwas Rajashekar
2024-05-31 21:55:34 +05:30
committed by GitHub
parent 2bb46b0562
commit 767f81d4f5
7 changed files with 521 additions and 21 deletions
+17
View File
@@ -0,0 +1,17 @@
package cluster
import "github.com/dchest/siphash"
// computes the target member using siphash and returns the index and the member
// siphash was chosen to prevent against hash attacks where an attacker
// can target all requests to one given instance instead of balancing across the cluster
// resulting in a Denial-of-Service (DOS).
// ref: https://en.wikipedia.org/wiki/SipHash
func ComputeTargetMember(hashKey string, members []string, repoName string) (uint64, string) {
h := siphash.New([]byte(hashKey))
h.Write([]byte(repoName))
sum64 := h.Sum64()
targetIdx := sum64 % uint64(len(members))
return targetIdx, members[targetIdx]
}
+25
View File
@@ -0,0 +1,25 @@
package cluster_test
import (
"testing"
. "github.com/smartystreets/goconvey/convey"
"zotregistry.dev/zot/pkg/cluster"
)
func TestComputeTargetMember(t *testing.T) {
Convey("Should panic when the hashKey is not long enough", t, func() {
So(func() { cluster.ComputeTargetMember("lorem", []string{"member1", "member2"}, "zot-test") }, ShouldPanic)
})
Convey("Should panic when there are no members", t, func() {
So(func() { cluster.ComputeTargetMember("loremipsumdolors", []string{}, "zot-test") }, ShouldPanic)
})
Convey("Should return a valid result when input is valid", t, func() {
index, member := cluster.ComputeTargetMember("loremipsumdolors", []string{"member1", "member2"}, "zot-test")
So(index, ShouldEqual, 1)
So(member, ShouldEqual, "member2")
})
}