Skip to content

Commit a50f8e6

Browse files
authored
Merge pull request #11 from storpool/master
Add support for authenticating against Sentinel
2 parents 8e55241 + 7fa8b1f commit a50f8e6

File tree

2 files changed

+49
-17
lines changed

2 files changed

+49
-17
lines changed

main.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,28 +20,34 @@ func main() {
2020
sentinelAddr = ":26379"
2121
masterName = "mymaster"
2222
masterResolveRetries = 3
23+
password = ""
2324
)
2425

2526
flag.StringVar(&localAddr, "listen", localAddr, "local address")
2627
flag.StringVar(&sentinelAddr, "sentinel", sentinelAddr, "remote address")
2728
flag.StringVar(&masterName, "master", masterName, "name of the master redis node")
29+
flag.StringVar(&password, "password", password, "redis password")
2830
flag.IntVar(&masterResolveRetries, "resolve-retries", masterResolveRetries, "number of consecutive retries of the redis master node resolve")
2931
flag.Parse()
3032

31-
if err := runProxying(localAddr, sentinelAddr, masterName, masterResolveRetries); err != nil {
33+
if envPassword := os.Getenv("SENTINEL_PASSWORD"); envPassword != "" {
34+
password = envPassword
35+
}
36+
37+
if err := runProxying(localAddr, sentinelAddr, password, masterName, masterResolveRetries); err != nil {
3238
log.Fatalf("Fatal: %s", err)
3339
}
3440
log.Println("Exiting...")
3541
}
3642

37-
func runProxying(localAddr, sentinelAddr, masterName string, masterResolveRetries int) error {
43+
func runProxying(localAddr, sentinelAddr, password string, masterName string, masterResolveRetries int) error {
3844
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
3945
defer cancel()
4046

4147
laddr := resolveTCPAddr(localAddr)
4248
saddr := resolveTCPAddr(sentinelAddr)
4349

44-
masterAddrResolver := masterresolver.NewRedisMasterResolver(masterName, saddr, masterResolveRetries)
50+
masterAddrResolver := masterresolver.NewRedisMasterResolver(masterName, saddr, password, masterResolveRetries)
4551
rsp := proxy.NewRedisSentinelProxy(laddr, masterAddrResolver)
4652

4753
eg, ctx := errgroup.WithContext(ctx)

pkg/master_resolver/master_resolver.go

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
type RedisMasterResolver struct {
1717
masterName string
1818
sentinelAddr *net.TCPAddr
19+
sentinelPassword string
1920
retryOnMasterResolveFail int
2021

2122
masterAddrLock *sync.RWMutex
@@ -24,10 +25,11 @@ type RedisMasterResolver struct {
2425
masterAddr string
2526
}
2627

27-
func NewRedisMasterResolver(masterName string, sentinelAddr *net.TCPAddr, retryOnMasterResolveFail int) *RedisMasterResolver {
28+
func NewRedisMasterResolver(masterName string, sentinelAddr *net.TCPAddr, sentinelPassword string, retryOnMasterResolveFail int) *RedisMasterResolver {
2829
return &RedisMasterResolver{
2930
masterName: masterName,
3031
sentinelAddr: sentinelAddr,
32+
sentinelPassword: sentinelPassword,
3133
retryOnMasterResolveFail: retryOnMasterResolveFail,
3234
masterAddrLock: &sync.RWMutex{},
3335
initialMasterResolveLock: make(chan struct{}),
@@ -49,7 +51,7 @@ func (r *RedisMasterResolver) setMasterAddress(masterAddr *net.TCPAddr) {
4951
}
5052

5153
func (r *RedisMasterResolver) updateMasterAddress() error {
52-
masterAddr, err := redisMasterFromSentinelAddr(r.sentinelAddr, r.masterName)
54+
masterAddr, err := redisMasterFromSentinelAddr(r.sentinelAddr, r.sentinelPassword, r.masterName)
5355
if err != nil {
5456
log.Println(err)
5557
return err
@@ -59,7 +61,7 @@ func (r *RedisMasterResolver) updateMasterAddress() error {
5961
}
6062

6163
func (r *RedisMasterResolver) UpdateMasterAddressLoop(ctx context.Context) error {
62-
if err := r.initialMasterAdressResolve(); err != nil {
64+
if err := r.initialMasterAddressResolve(); err != nil {
6365
return err
6466
}
6567

@@ -84,46 +86,70 @@ func (r *RedisMasterResolver) UpdateMasterAddressLoop(ctx context.Context) error
8486
return err
8587
}
8688

87-
func (r *RedisMasterResolver) initialMasterAdressResolve() error {
89+
func (r *RedisMasterResolver) initialMasterAddressResolve() error {
8890
defer close(r.initialMasterResolveLock)
8991
return r.updateMasterAddress()
9092
}
9193

92-
func redisMasterFromSentinelAddr(sentinelAddress *net.TCPAddr, masterName string) (*net.TCPAddr, error) {
94+
func redisMasterFromSentinelAddr(sentinelAddress *net.TCPAddr, sentinelPassword string, masterName string) (*net.TCPAddr, error) {
9395
conn, err := utils.TCPConnectWithTimeout(sentinelAddress.String())
94-
conn.SetDeadline(time.Now().Add(time.Second))
9596
if err != nil {
9697
return nil, fmt.Errorf("error connecting to sentinel: %w", err)
9798
}
9899
defer conn.Close()
99100

100-
getMasterCommand := fmt.Sprintf("sentinel get-master-addr-by-name %s\n", masterName)
101+
conn.SetDeadline(time.Now().Add(time.Second))
102+
103+
// Authenticate with sentinel if password is provided
104+
if sentinelPassword != "" {
105+
authCommand := fmt.Sprintf("AUTH %s\r\n", sentinelPassword)
106+
if _, err := conn.Write([]byte(authCommand)); err != nil {
107+
return nil, fmt.Errorf("error sending AUTH to sentinel: %w", err)
108+
}
109+
110+
// Read response from AUTH
111+
b := make([]byte, 256)
112+
n, err := conn.Read(b)
113+
if err != nil {
114+
return nil, fmt.Errorf("error reading AUTH response: %w", err)
115+
}
116+
response := string(b[:n])
117+
if !strings.HasPrefix(response, "+OK") {
118+
return nil, fmt.Errorf("sentinel AUTH failed: %s", response)
119+
}
120+
}
121+
122+
// Request master address
123+
getMasterCommand := fmt.Sprintf("SENTINEL get-master-addr-by-name %s\r\n", masterName)
101124
if _, err := conn.Write([]byte(getMasterCommand)); err != nil {
102125
return nil, fmt.Errorf("error writing to sentinel: %w", err)
103126
}
104127

128+
// Read response
105129
b := make([]byte, 256)
106-
if _, err := conn.Read(b); err != nil {
130+
n, err := conn.Read(b)
131+
if err != nil {
107132
return nil, fmt.Errorf("error getting info from sentinel: %w", err)
108133
}
109134

110-
parts := strings.Split(string(b), "\r\n")
111-
135+
// Extract master address parts
136+
parts := strings.Split(string(b[:n]), "\r\n")
112137
if len(parts) < 5 {
113138
return nil, errors.New("couldn't get master address from sentinel")
114139
}
115140

116-
// getting the string address for the master node
117-
stringaddr := fmt.Sprintf("%s:%s", parts[2], parts[4])
118-
addr, err := net.ResolveTCPAddr("tcp", stringaddr)
141+
// Assemble master address
142+
formattedMasterAddress := fmt.Sprintf("%s:%s", parts[2], parts[4])
143+
addr, err := net.ResolveTCPAddr("tcp", formattedMasterAddress)
119144
if err != nil {
120145
return nil, fmt.Errorf("error resolving redis master: %w", err)
121146
}
122147

123-
// check that there's actually someone listening on that address
148+
// Check if there is a Redis instance listening on the master address
124149
if err := checkTCPConnect(addr); err != nil {
125150
return nil, fmt.Errorf("error checking redis master: %w", err)
126151
}
152+
127153
return addr, nil
128154
}
129155

0 commit comments

Comments
 (0)