-
Notifications
You must be signed in to change notification settings - Fork 380
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* consul like approach: add server_lookup to make dkron independent from server node IP on raft layer * handle memberupdate event * query other servers before start & add test * don't remove itself if node is a raft leader * don't remove dkron server node if id matches
- Loading branch information
1 parent
2f40b60
commit 1c45fdf
Showing
6 changed files
with
257 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package dkron | ||
|
||
import ( | ||
"fmt" | ||
"sync" | ||
|
||
"github.com/hashicorp/raft" | ||
) | ||
|
||
// ServerLookup encapsulates looking up servers by id and address | ||
type ServerLookup struct { | ||
lock sync.RWMutex | ||
addressToServer map[raft.ServerAddress]*ServerParts | ||
idToServer map[raft.ServerID]*ServerParts | ||
} | ||
|
||
func NewServerLookup() *ServerLookup { | ||
return &ServerLookup{ | ||
lock: sync.RWMutex{}, | ||
addressToServer: make(map[raft.ServerAddress]*ServerParts), | ||
idToServer: make(map[raft.ServerID]*ServerParts), | ||
} | ||
} | ||
|
||
func (sl *ServerLookup) AddServer(server *ServerParts) { | ||
sl.lock.Lock() | ||
defer sl.lock.Unlock() | ||
sl.addressToServer[raft.ServerAddress(server.RPCAddr.String())] = server | ||
sl.idToServer[raft.ServerID(server.ID)] = server | ||
} | ||
|
||
func (sl *ServerLookup) RemoveServer(server *ServerParts) { | ||
sl.lock.Lock() | ||
defer sl.lock.Unlock() | ||
delete(sl.addressToServer, raft.ServerAddress(server.RPCAddr.String())) | ||
delete(sl.idToServer, raft.ServerID(server.ID)) | ||
} | ||
|
||
// Implements the ServerAddressProvider interface | ||
func (sl *ServerLookup) ServerAddr(id raft.ServerID) (raft.ServerAddress, error) { | ||
sl.lock.RLock() | ||
defer sl.lock.RUnlock() | ||
svr, ok := sl.idToServer[id] | ||
if !ok { | ||
return "", fmt.Errorf("Could not find address for server id %v", id) | ||
} | ||
return raft.ServerAddress(svr.RPCAddr.String()), nil | ||
} | ||
|
||
// Server looks up the server by address, returns a boolean if not found | ||
func (sl *ServerLookup) Server(addr raft.ServerAddress) *ServerParts { | ||
sl.lock.RLock() | ||
defer sl.lock.RUnlock() | ||
return sl.addressToServer[addr] | ||
} | ||
|
||
func (sl *ServerLookup) Servers() []*ServerParts { | ||
sl.lock.RLock() | ||
defer sl.lock.RUnlock() | ||
var ret []*ServerParts | ||
for _, svr := range sl.addressToServer { | ||
ret = append(ret, svr) | ||
} | ||
return ret | ||
} | ||
|
||
func (sl *ServerLookup) CheckServers(fn func(srv *ServerParts) bool) { | ||
sl.lock.RLock() | ||
defer sl.lock.RUnlock() | ||
|
||
for _, srv := range sl.addressToServer { | ||
if !fn(srv) { | ||
return | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
package dkron | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/hashicorp/raft" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
type testAddr struct { | ||
addr string | ||
} | ||
|
||
func (ta *testAddr) Network() string { | ||
return "tcp" | ||
} | ||
|
||
func (ta *testAddr) String() string { | ||
return ta.addr | ||
} | ||
|
||
func TestAddServer(t *testing.T) { | ||
// arrange | ||
lookup := NewServerLookup() | ||
id1, addr1 := "server-1", "127.0.0.1:8300" | ||
id2, addr2 := "server-2", "127.0.0.2:8300" | ||
server1, server2 := buildServerParts(id1, addr1), buildServerParts(id2, addr2) | ||
|
||
// act | ||
lookup.AddServer(server1) | ||
lookup.AddServer(server2) | ||
|
||
// assert | ||
servers := lookup.Servers() | ||
expectedServers := []*ServerParts{server1, server2} | ||
require.EqualValuesf(t, expectedServers, servers, "Expected %v but got %v", expectedServers, servers) | ||
|
||
got, err := lookup.ServerAddr(raft.ServerID(id1)) | ||
require.NoErrorf(t, err, "Unexpected error: %v", err) | ||
require.EqualValuesf(t, addr1, string(got), "Expected %v but got %v", addr1, got) | ||
|
||
server := lookup.Server(raft.ServerAddress(addr1)) | ||
strAddr := server.RPCAddr.String() | ||
require.EqualValuesf(t, addr1, strAddr, "Expected lookup to return address %v but got %v", addr1, strAddr) | ||
|
||
got, err = lookup.ServerAddr(raft.ServerID(id2)) | ||
require.NoErrorf(t, err, "Unexpected error: %v", err) | ||
require.EqualValuesf(t, addr2, string(got), "Expected %v but got %v", addr2, got) | ||
|
||
server = lookup.Server(raft.ServerAddress(addr2)) | ||
strAddr = server.RPCAddr.String() | ||
require.EqualValuesf(t, addr2, strAddr, "Expected lookup to return address %v but got %v", addr2, strAddr) | ||
} | ||
|
||
func TestRemoveServer(t *testing.T) { | ||
// arrange | ||
lookup := NewServerLookup() | ||
id1, addr1 := "server-1", "127.0.0.1:8300" | ||
id2, addr2 := "server-2", "127.0.0.2:8300" | ||
server1, server2 := buildServerParts(id1, addr1), buildServerParts(id2, addr2) | ||
lookup.AddServer(server1) | ||
lookup.AddServer(server2) | ||
|
||
// act | ||
lookup.RemoveServer(server1) | ||
|
||
// assert | ||
servers := lookup.Servers() | ||
expectedServers := []*ServerParts{server2} | ||
require.EqualValuesf(t, expectedServers, servers, "Expected %v but got %v", expectedServers, servers) | ||
|
||
require.Nilf(t, lookup.Server(raft.ServerAddress(addr1)), "Expected lookup to return nil") | ||
addr, err := lookup.ServerAddr(raft.ServerID(id1)) | ||
require.Errorf(t, err, "Expected lookup to return error") | ||
require.EqualValuesf(t, "", string(addr), "Expected empty address but got %v", addr) | ||
|
||
got, err := lookup.ServerAddr(raft.ServerID(id2)) | ||
require.NoErrorf(t, err, "Unexpected error: %v", err) | ||
require.EqualValuesf(t, addr2, string(got), "Expected %v but got %v", addr2, got) | ||
|
||
server := lookup.Server(raft.ServerAddress(addr2)) | ||
strAddr := server.RPCAddr.String() | ||
require.EqualValuesf(t, addr2, strAddr, "Expected lookup to return address %v but got %v", addr2, strAddr) | ||
} | ||
|
||
func buildServerParts(id, addr string) *ServerParts { | ||
return &ServerParts{ | ||
ID: id, | ||
RPCAddr: &testAddr{addr}, | ||
} | ||
} |