Skip to content

Commit

Permalink
fix(updater): triage all monitor messages based on success/failure (#631
Browse files Browse the repository at this point in the history
)
  • Loading branch information
favonia authored Nov 4, 2023
1 parent 1d51ef1 commit b23ba55
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 124 deletions.
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ require (
github.com/goccy/go-json v0.10.2 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/sync v0.5.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
kernel.org/pub/linux/libs/security/libcap/psx v1.2.69 // indirect
)
12 changes: 6 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,14 @@ go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo=
go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY=
golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
Expand Down
2 changes: 1 addition & 1 deletion internal/config/network_probe.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (

// ProbeURL quickly checks whether one can send a HEAD request to the url.
func ProbeURL(ctx context.Context, url string) bool {
ctx, cancel := context.WithDeadline(ctx, time.Now().Add(time.Second))
ctx, cancel := context.WithTimeout(ctx, time.Second)
defer cancel()

req, err := http.NewRequestWithContext(ctx, http.MethodHead, url, nil)
Expand Down
91 changes: 54 additions & 37 deletions internal/updater/updater.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package updater

import (
"context"
"errors"
"fmt"
"net/netip"
"strings"
Expand All @@ -15,6 +16,25 @@ import (
"github.com/favonia/cloudflare-ddns/internal/setter"
)

// ShouldDisplayHints determines whether help messages should be displayed.
// The help messages are to help beginners detect possible misconfiguration.
// These messages should be displayed at most once, and thus the value of this map
// will be changed to false after displaying the help messages.
//
//nolint:gochecknoglobals
var ShouldDisplayHints = map[string]bool{
"detect-ip4-fail": true,
"detect-ip6-fail": true,
"update-timeout": true,
}

func getHintIDForDetection(ipNet ipnet.Type) string {
return map[ipnet.Type]string{
ipnet.IP4: "detect-ip4-fail",
ipnet.IP6: "detect-ip6-fail",
}[ipNet]
}

func getProxied(ppfmt pp.PP, c *config.Config, domain domain.Domain) bool {
if proxied, ok := c.Proxied[domain]; ok {
return proxied
Expand All @@ -27,32 +47,43 @@ func getProxied(ppfmt pp.PP, c *config.Config, domain domain.Domain) bool {
return false
}

var errSettingTimeout = errors.New("setting timeout")

// setIP extracts relevant settings from the configuration and calls [setter.Setter.Set] with timeout.
// ip must be non-zero.
func setIP(ctx context.Context, ppfmt pp.PP,
c *config.Config, s setter.Setter, ipNet ipnet.Type, ip netip.Addr,
) (bool, string) {
) (bool, []string) {
allOk := true
var msgs []string

// [msgs[false]] collects all the error messages and [msgs[true]] collects all the success messages.
msgs := map[bool][]string{}

for _, domain := range c.Domains[ipNet] {
ctx, cancel := context.WithTimeout(ctx, c.UpdateTimeout)
ctx, cancel := context.WithTimeoutCause(ctx, c.UpdateTimeout, errSettingTimeout)
defer cancel()

ok, msg := s.Set(ctx, ppfmt, domain, ipNet, ip, c.TTL, getProxied(ppfmt, c, domain))
allOk = allOk && ok
if msg != "" {
msgs = append(msgs, msg)
msgs[ok] = append(msgs[ok], msg)
}

if !ok && ShouldDisplayHints["update-timeout"] && errors.Is(context.Cause(ctx), errSettingTimeout) {
ppfmt.Infof(pp.EmojiConfig, "If your network is working but with high latency, consider increasing the value of UPDATE_TIMEOUT") //nolint:lll
ShouldDisplayHints["update-timeout"] = false
}
}

return allOk, strings.Join(msgs, "\n")
return allOk, msgs[allOk]
}

// clearIP extracts relevant settings from the configuration and calls [setter.Setter.Clear] with a deadline.
func clearIP(ctx context.Context, ppfmt pp.PP, c *config.Config, s setter.Setter, ipNet ipnet.Type) (bool, string) {
func clearIP(ctx context.Context, ppfmt pp.PP, c *config.Config, s setter.Setter, ipNet ipnet.Type) (bool, []string) {
allOk := true
var msgs []string

// [msgs[false]] collects all the error messages and [msgs[true]] collects all the success messages.
msgs := map[bool][]string{}

for _, domain := range c.Domains[ipNet] {
ctx, cancel := context.WithTimeout(ctx, c.UpdateTimeout)
Expand All @@ -61,38 +92,28 @@ func clearIP(ctx context.Context, ppfmt pp.PP, c *config.Config, s setter.Setter
ok, msg := s.Clear(ctx, ppfmt, domain, ipNet)
allOk = allOk && ok
if msg != "" {
msgs = append(msgs, msg)
msgs[ok] = append(msgs[ok], msg)
}
}

return allOk, strings.Join(msgs, "\n")
}

// ShouldDisplayHelpMessages determines whether help messages should be displayed.
// The help messages are to help beginners detect possible misconfiguration.
// These messages should be displayed at most once, and thus the value of this map
// will be changed to false after displaying the help messages.
//
//nolint:gochecknoglobals
var ShouldDisplayHelpMessages = map[ipnet.Type]bool{
ipnet.IP4: true,
ipnet.IP6: true,
return allOk, msgs[allOk]
}

func detectIP(ctx context.Context, ppfmt pp.PP,
c *config.Config, ipNet ipnet.Type, use1001 bool,
) (netip.Addr, bool, string) {
) (netip.Addr, bool, []string) {
ctx, cancel := context.WithTimeout(ctx, c.DetectionTimeout)
defer cancel()

msg := ""
var msgs []string
ip, ok := c.Provider[ipNet].GetIP(ctx, ppfmt, ipNet, use1001)
if ok {
ppfmt.Infof(pp.EmojiInternet, "Detected the %s address: %v", ipNet.Describe(), ip)
} else {
msg = fmt.Sprintf("Failed to detect the %s address", ipNet.Describe())
msg := fmt.Sprintf("Failed to detect the %s address", ipNet.Describe())
msgs = append(msgs, msg)
ppfmt.Errorf(pp.EmojiError, "%s", msg)
if ShouldDisplayHelpMessages[ipNet] {
if ShouldDisplayHints[getHintIDForDetection(ipNet)] {
switch ipNet {
case ipnet.IP6:
ppfmt.Infof(pp.EmojiConfig, "If you are using Docker or Kubernetes, IPv6 often requires additional setups") //nolint:lll
Expand All @@ -103,8 +124,8 @@ func detectIP(ctx context.Context, ppfmt pp.PP,
}
}
}
ShouldDisplayHelpMessages[ipNet] = false
return ip, ok, msg
ShouldDisplayHints[getHintIDForDetection(ipNet)] = false
return ip, ok, msgs
}

// UpdateIPs detect IP addresses and update DNS records of managed domains.
Expand All @@ -117,19 +138,15 @@ func UpdateIPs(ctx context.Context, ppfmt pp.PP, c *config.Config, s setter.Sett
for _, ipNet := range [...]ipnet.Type{ipnet.IP4, ipnet.IP6} {
if c.Provider[ipNet] != nil {
ip, ok, msg := detectIP(ctx, ppfmt, c, ipNet, c.Use1001)
if len(msg) != 0 {
msgs[ok] = append(msgs[ok], msg)
}
msgs[ok] = append(msgs[ok], msg...)
if !ok {
// We can't detect the new IP address. It's probably better to leave existing IP addresses alone.
allOk = false
continue
}

ok, msg = setIP(ctx, ppfmt, c, s, ipNet, ip)
if len(msg) != 0 {
msgs[ok] = append(msgs[ok], msg)
}
msgs[ok] = append(msgs[ok], msg...)
allOk = allOk && ok
}
}
Expand All @@ -146,17 +163,17 @@ func UpdateIPs(ctx context.Context, ppfmt pp.PP, c *config.Config, s setter.Sett
// ClearIPs removes all DNS records of managed domains.
func ClearIPs(ctx context.Context, ppfmt pp.PP, c *config.Config, s setter.Setter) (bool, string) {
allOk := true
var msgs []string

// [msgs[false]] collects all the error messages and [msgs[true]] collects all the success messages.
msgs := map[bool][]string{}

for _, ipNet := range [...]ipnet.Type{ipnet.IP4, ipnet.IP6} {
if c.Provider[ipNet] != nil {
ok, msg := clearIP(ctx, ppfmt, c, s, ipNet)
allOk = allOk && ok
if msg != "" {
msgs = append(msgs, msg)
}
msgs[ok] = append(msgs[ok], msg...)
}
}

return allOk, strings.Join(msgs, "\n")
return allOk, strings.Join(msgs[allOk], "\n")
}
Loading

0 comments on commit b23ba55

Please sign in to comment.