Skip to content

Commit 9782ff4

Browse files
committed
[*] improve error messages
1 parent ab9a7b2 commit 9782ff4

5 files changed

Lines changed: 68 additions & 24 deletions

File tree

checker/consul_leader_checker.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@ func NewConsulLeaderChecker(con *vipconfig.Config) (lc *ConsulLeaderChecker, err
2323

2424
url, err := url.Parse(con.Endpoints[0])
2525
if err != nil {
26-
return nil, err
26+
return nil, fmt.Errorf("failed to parse consul endpoint URL %s: %w", con.Endpoints[0], err)
27+
}
28+
29+
if url.Hostname() == "" {
30+
return nil, fmt.Errorf("invalid consul endpoint URL: hostname is empty in %s", con.Endpoints[0])
2731
}
2832

2933
config := &api.Config{
@@ -34,7 +38,7 @@ func NewConsulLeaderChecker(con *vipconfig.Config) (lc *ConsulLeaderChecker, err
3438
}
3539

3640
if lc.Client, err = api.NewClient(config); err != nil {
37-
return nil, err
41+
return nil, fmt.Errorf("failed to create consul client for endpoint %s: %w", con.Endpoints[0], err)
3842
}
3943

4044
return lc, nil

checker/etcd_leader_checker.go

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ type EtcdLeaderChecker struct {
2323
func NewEtcdLeaderChecker(conf *vipconfig.Config) (*EtcdLeaderChecker, error) {
2424
tlsConfig, err := getTransport(conf)
2525
if err != nil {
26-
return nil, err
26+
return nil, fmt.Errorf("failed to create TLS transport for etcd: %w", err)
2727
}
2828
cfg := clientv3.Config{
2929
Endpoints: conf.Endpoints,
@@ -35,7 +35,10 @@ func NewEtcdLeaderChecker(conf *vipconfig.Config) (*EtcdLeaderChecker, error) {
3535
Logger: conf.Logger,
3636
}
3737
c, err := clientv3.New(cfg)
38-
return &EtcdLeaderChecker{conf, c}, err
38+
if err != nil {
39+
return nil, fmt.Errorf("failed to connect to etcd at endpoints %v: %w", conf.Endpoints, err)
40+
}
41+
return &EtcdLeaderChecker{conf, c}, nil
3942
}
4043

4144
func getTransport(conf *vipconfig.Config) (*tls.Config, error) {
@@ -74,7 +77,17 @@ func getTransport(conf *vipconfig.Config) (*tls.Config, error) {
7477
func (elc *EtcdLeaderChecker) get(ctx context.Context, out chan<- bool) {
7578
resp, err := elc.Get(ctx, elc.TriggerKey)
7679
if err != nil {
77-
elc.Logger.Error("Failed to get etcd value:", zap.Error(err))
80+
elc.Logger.Error("Failed to get etcd value", zap.String("key", elc.TriggerKey), zap.Error(err))
81+
out <- false
82+
return
83+
}
84+
if resp == nil {
85+
elc.Logger.Error("Received nil response from etcd", zap.String("key", elc.TriggerKey))
86+
out <- false
87+
return
88+
}
89+
if len(resp.Kvs) == 0 {
90+
elc.Logger.Sugar().Info("No value found for key ", elc.TriggerKey, " - DCS may not have a leader yet")
7891
out <- false
7992
return
8093
}
@@ -99,6 +112,7 @@ func (elc *EtcdLeaderChecker) watch(ctx context.Context, out chan<- bool) error
99112
continue
100113
}
101114
if err := watchResp.Err(); err != nil {
115+
elc.Logger.Error("Watch error for key "+elc.TriggerKey+":", zap.Error(err))
102116
elc.get(ctx, out) // RPC failed, try to get the key directly to be on the safe side
103117
continue
104118
}

checker/patroni_leader_checker.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,17 @@ func (c *PatroniLeaderChecker) GetChangeNotificationStream(ctx context.Context,
4747
case <-ctx.Done():
4848
return nil
4949
case <-time.After(time.Duration(c.Interval) * time.Millisecond):
50-
r, err := c.Get(c.Endpoints[0] + c.TriggerKey)
50+
url := c.Endpoints[0] + c.TriggerKey
51+
r, err := c.Get(url)
5152
if err != nil {
52-
c.Logger.Sugar().Error("patroni REST API error:", err)
53+
c.Logger.Sugar().Errorf("patroni REST API error connecting to %s: %v", url, err)
54+
out <- false
5355
continue
5456
}
5557
r.Body.Close() //throw away the body
58+
if r.StatusCode < 200 || r.StatusCode >= 300 {
59+
c.Logger.Sugar().Warnf("patroni REST API returned non-success status code %d for %s (expected %s)", r.StatusCode, url, c.TriggerValue)
60+
}
5661
out <- strconv.Itoa(r.StatusCode) == c.TriggerValue
5762
}
5863
}

ipmanager/hetznerConfigurer.go

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bufio"
55
"encoding/json"
66
"errors"
7+
"fmt"
78
"net"
89
"os"
910
"os/exec"
@@ -40,17 +41,16 @@ func newHetznerConfigurer(config *IPConfiguration, verbose bool) (*HetznerConfig
4041
* In order to tell the Hetzner API to route the failover-ip to
4142
* this machine, we must attach our own IP address to the API request.
4243
*/
43-
func getOutboundIP() net.IP {
44+
func getOutboundIP() (net.IP, error) {
4445
conn, err := net.Dial("udp", "8.8.8.8:80")
4546
if err != nil || conn == nil {
46-
log.Error("error dialing 8.8.8.8 to retrieve preferred outbound IP", err)
47-
return nil
47+
return nil, fmt.Errorf("error dialing 8.8.8.8 to retrieve preferred outbound IP: %w", err)
4848
}
4949
defer conn.Close()
5050

5151
localAddr := conn.LocalAddr().(*net.UDPAddr)
5252

53-
return localAddr.IP
53+
return localAddr.IP, nil
5454
}
5555

5656
func (c *HetznerConfigurer) curlQueryFailover(post bool) (string, error) {
@@ -98,10 +98,10 @@ func (c *HetznerConfigurer) curlQueryFailover(post bool) (string, error) {
9898
*/
9999
var cmd *exec.Cmd
100100
if post {
101-
myOwnIP := getOutboundIP()
102-
if myOwnIP == nil {
103-
log.Error("Error determining this machine's IP address.")
104-
return "", errors.New("error determining this machine's IP address")
101+
myOwnIP, err := getOutboundIP()
102+
if err != nil {
103+
log.Error("Error determining this machine's IP address.", err)
104+
return "", fmt.Errorf("error determining this machine's IP address: %w", err)
105105
}
106106
log.Infof("my_own_ip: %s\n", myOwnIP.String())
107107

@@ -224,7 +224,14 @@ func (c *HetznerConfigurer) queryAddress() bool {
224224
c.cachedState = unknown
225225
}
226226

227-
if currentFailoverDestinationIP.Equal(getOutboundIP()) {
227+
myOwnIP, err := getOutboundIP()
228+
if err != nil {
229+
log.Error("Error determining this machine's IP address.", err)
230+
c.cachedState = unknown
231+
return false
232+
}
233+
234+
if currentFailoverDestinationIP.Equal(myOwnIP) {
228235
//We "are" the current failover destination.
229236
c.cachedState = configured
230237
return true
@@ -262,7 +269,14 @@ func (c *HetznerConfigurer) runAddressConfiguration() bool {
262269

263270
c.lastAPICheck = time.Now()
264271

265-
if currentFailoverDestinationIP.Equal(getOutboundIP()) {
272+
myOwnIP, err := getOutboundIP()
273+
if err != nil {
274+
log.Error("Error determining this machine's IP address.", err)
275+
c.cachedState = unknown
276+
return false
277+
}
278+
279+
if currentFailoverDestinationIP.Equal(myOwnIP) {
266280
//We "are" the current failover destination.
267281
log.Info("Failover was successfully executed!")
268282
c.cachedState = configured
@@ -271,7 +285,7 @@ func (c *HetznerConfigurer) runAddressConfiguration() bool {
271285

272286
log.Infof("The failover command was issued, but the current Failover destination (%s) is different from what it should be (%s).",
273287
currentFailoverDestinationIP.String(),
274-
getOutboundIP().String())
288+
myOwnIP.String())
275289
//Something must have gone wrong while trying to switch IP's...
276290
c.cachedState = unknown
277291
return false

ipmanager/ip_manager.go

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package ipmanager
22

33
import (
44
"context"
5+
"fmt"
56
"net"
67
"net/netip"
78
"sync/atomic"
@@ -18,7 +19,7 @@ type ipConfigurer interface {
1819
getCIDR() string
1920
}
2021

21-
var log *zap.SugaredLogger = zap.L().Sugar()
22+
var log *zap.SugaredLogger
2223

2324
// IPManager implements the main functionality of the VIP manager
2425
type IPManager struct {
@@ -40,22 +41,28 @@ func getMask(vip netip.Addr, mask int) net.IPMask {
4041
return net.CIDRMask(mask, 128) //IPv6
4142
}
4243

43-
func getNetIface(iface string) *net.Interface {
44+
func getNetIface(iface string) (*net.Interface, error) {
4445
netIface, err := net.InterfaceByName(iface)
4546
if err != nil {
46-
log.Fatalf("Obtaining the interface raised an error: %s", err)
47+
return nil, fmt.Errorf("failed to get interface %s: %w", iface, err)
4748
}
48-
return netIface
49+
if netIface.Flags&net.FlagUp == 0 {
50+
return nil, fmt.Errorf("interface %s is not up", iface)
51+
}
52+
return netIface, nil
4953
}
5054

5155
// NewIPManager returns a new instance of IPManager
5256
func NewIPManager(conf *vipconfig.Config, states <-chan bool) (m *IPManager, err error) {
5357
vip, err := netip.ParseAddr(conf.IP)
5458
if err != nil {
55-
return nil, err
59+
return nil, fmt.Errorf("failed to parse VIP address: %w", err)
5660
}
5761
vipMask := getMask(vip, conf.Mask)
58-
netIface := getNetIface(conf.Iface)
62+
netIface, err := getNetIface(conf.Iface)
63+
if err != nil {
64+
return nil, err
65+
}
5966
ipConf := &IPConfiguration{
6067
VIP: vip,
6168
Netmask: vipMask,

0 commit comments

Comments
 (0)