Skip to content

Commit

Permalink
utils: extract IsErr into package
Browse files Browse the repository at this point in the history
  • Loading branch information
ChrisSchinnerl committed Mar 8, 2024
1 parent 9bc66bf commit e80f974
Show file tree
Hide file tree
Showing 9 changed files with 56 additions and 54 deletions.
11 changes: 6 additions & 5 deletions autopilot/autopilot.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"go.sia.tech/renterd/api"
"go.sia.tech/renterd/build"
"go.sia.tech/renterd/hostdb"
"go.sia.tech/renterd/internal/utils"
"go.sia.tech/renterd/object"
"go.sia.tech/renterd/wallet"
"go.sia.tech/renterd/webhooks"
Expand Down Expand Up @@ -299,7 +300,7 @@ func (ap *Autopilot) Run() error {

// perform maintenance
setChanged, err := ap.c.performContractMaintenance(ap.shutdownCtx, w)
if err != nil && isErr(err, context.Canceled) {
if err != nil && utils.IsErr(err, context.Canceled) {
return
} else if err != nil {
ap.logger.Errorf("contract maintenance failed, err: %v", err)
Expand Down Expand Up @@ -405,9 +406,9 @@ func (ap *Autopilot) blockUntilConfigured(interrupt <-chan time.Time) (configure
cancel()

// if the config was not found, or we were unable to fetch it, keep blocking
if isErr(err, context.Canceled) {
if utils.IsErr(err, context.Canceled) {
return
} else if isErr(err, api.ErrAutopilotNotFound) {
} else if utils.IsErr(err, api.ErrAutopilotNotFound) {
once.Do(func() { ap.logger.Info("autopilot is waiting to be configured...") })
} else if err != nil {
ap.logger.Errorf("autopilot is unable to fetch its configuration from the bus, err: %v", err)
Expand Down Expand Up @@ -438,7 +439,7 @@ func (ap *Autopilot) blockUntilOnline() (online bool) {
online = len(peers) > 0
cancel()

if isErr(err, context.Canceled) {
if utils.IsErr(err, context.Canceled) {
return
} else if err != nil {
ap.logger.Errorf("failed to get peers, err: %v", err)
Expand Down Expand Up @@ -472,7 +473,7 @@ func (ap *Autopilot) blockUntilSynced(interrupt <-chan time.Time) (synced, block
cancel()

// if an error occurred, or if we're not synced, we continue
if isErr(err, context.Canceled) {
if utils.IsErr(err, context.Canceled) {
return
} else if err != nil {
ap.logger.Errorf("failed to get consensus state, err: %v", err)
Expand Down
19 changes: 10 additions & 9 deletions autopilot/contract_pruning.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"go.sia.tech/core/types"
"go.sia.tech/renterd/alerts"
"go.sia.tech/renterd/api"
"go.sia.tech/renterd/internal/utils"
"go.sia.tech/siad/build"
)

Expand Down Expand Up @@ -65,14 +66,14 @@ func (pm pruneMetrics) String() string {
func (pr pruneResult) toAlert() (id types.Hash256, alert *alerts.Alert) {
id = alertIDForContract(alertPruningID, pr.fcid)

if shouldTrigger := pr.err != nil && !((isErr(pr.err, errInvalidMerkleProof) && build.VersionCmp(pr.version, "1.6.0") < 0) ||
isErr(pr.err, api.ErrContractNotFound) || // contract got archived
isErr(pr.err, errConnectionRefused) ||
isErr(pr.err, errConnectionTimedOut) ||
isErr(pr.err, errConnectionResetByPeer) ||
isErr(pr.err, errInvalidHandshakeSignature) ||
isErr(pr.err, errNoRouteToHost) ||
isErr(pr.err, errNoSuchHost)); shouldTrigger {
if shouldTrigger := pr.err != nil && !((utils.IsErr(pr.err, errInvalidMerkleProof) && build.VersionCmp(pr.version, "1.6.0") < 0) ||
utils.IsErr(pr.err, api.ErrContractNotFound) || // contract got archived
utils.IsErr(pr.err, errConnectionRefused) ||
utils.IsErr(pr.err, errConnectionTimedOut) ||
utils.IsErr(pr.err, errConnectionResetByPeer) ||
utils.IsErr(pr.err, errInvalidHandshakeSignature) ||
utils.IsErr(pr.err, errNoRouteToHost) ||
utils.IsErr(pr.err, errNoSuchHost)); shouldTrigger {
alert = newContractPruningFailedAlert(pr.hk, pr.version, pr.fcid, pr.err)
}
return
Expand Down Expand Up @@ -196,7 +197,7 @@ func (c *contractor) pruneContract(w Worker, fcid types.FileContractID) pruneRes
pruned, remaining, err := w.RHPPruneContract(ctx, fcid, timeoutPruneContract)
if err != nil && pruned == 0 {
return pruneResult{fcid: fcid, hk: host.PublicKey, version: host.Settings.Version, err: err}
} else if err != nil && isErr(err, context.DeadlineExceeded) {
} else if err != nil && utils.IsErr(err, context.DeadlineExceeded) {
err = nil
}

Expand Down
10 changes: 2 additions & 8 deletions autopilot/ipfilter.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"time"

"go.sia.tech/core/types"
"go.sia.tech/renterd/internal/utils"
"go.uber.org/zap"
)

Expand Down Expand Up @@ -137,7 +138,7 @@ func (r *ipResolver) lookup(hostIP string) ([]string, error) {
addrs, err := r.resolver.LookupIPAddr(ctx, host)
if err != nil {
// check the cache if it's an i/o timeout or server misbehaving error
if isErr(err, errIOTimeout) || isErr(err, errServerMisbehaving) {
if utils.IsErr(err, errIOTimeout) || utils.IsErr(err, errServerMisbehaving) {
if entry, found := r.cache[hostIP]; found && time.Since(entry.created) < ipCacheEntryValidity {
r.logger.Debugf("using cached IP addresses for %v, err: %v", hostIP, err)
return entry.subnets, nil
Expand Down Expand Up @@ -188,10 +189,3 @@ func parseSubnets(addresses []net.IPAddr) []string {

return subnets
}

func isErr(err error, target error) bool {
if errors.Is(err, target) {
return true
}
return err != nil && target != nil && strings.Contains(err.Error(), target.Error())
}
3 changes: 2 additions & 1 deletion autopilot/migrator.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"time"

"go.sia.tech/renterd/api"
"go.sia.tech/renterd/internal/utils"
"go.sia.tech/renterd/object"
"go.sia.tech/renterd/stats"
"go.uber.org/zap"
Expand Down Expand Up @@ -156,7 +157,7 @@ func (m *migrator) performMigrations(p *workerPool) {

if err != nil {
m.logger.Errorf("%v: migration %d/%d failed, key: %v, health: %v, overpaid: %v, err: %v", id, j.slabIdx+1, j.batchSize, j.Key, j.Health, res.SurchargeApplied, err)
skipAlert := isErr(err, api.ErrSlabNotFound)
skipAlert := utils.IsErr(err, api.ErrSlabNotFound)
if !skipAlert {
if res.SurchargeApplied {
m.ap.RegisterAlert(ctx, newCriticalMigrationFailedAlert(j.Key, j.Health, err))
Expand Down
3 changes: 2 additions & 1 deletion autopilot/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"go.sia.tech/core/types"
"go.sia.tech/renterd/api"
"go.sia.tech/renterd/hostdb"
"go.sia.tech/renterd/internal/utils"
"go.uber.org/zap"
)

Expand Down Expand Up @@ -314,7 +315,7 @@ func (s *scanner) launchScanWorkers(ctx context.Context, w scanWorker, reqs chan
scan, err := w.RHPScan(ctx, req.hostKey, req.hostIP, s.currentTimeout())
if err != nil {
break // abort
} else if !isErr(errors.New(scan.ScanError), errIOTimeout) && scan.Ping > 0 {
} else if !utils.IsErr(errors.New(scan.ScanError), errIOTimeout) && scan.Ping > 0 {
s.tracker.addDataPoint(time.Duration(scan.Ping))
}

Expand Down
18 changes: 18 additions & 0 deletions internal/utils/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package utils

import (
"errors"
"strings"
)

// IsErr can be used to compare an error to a target and also works when used on
// errors that haven't been wrapped since it will fall back to a string
// comparison. Useful to check errors returned over the network.
func IsErr(err error, target error) bool {
if (err == nil) != (target == nil) {
return false
} else if errors.Is(err, target) {
return true
}
return strings.Contains(err.Error(), target.Error())
}
40 changes: 12 additions & 28 deletions worker/rhpv3.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"math"
"math/big"
"net"
"strings"
"sync"
"time"

Expand All @@ -20,6 +19,7 @@ import (
"go.sia.tech/mux/v1"
"go.sia.tech/renterd/api"
"go.sia.tech/renterd/hostdb"
"go.sia.tech/renterd/internal/utils"
"go.sia.tech/siad/crypto"
"go.uber.org/zap"
)
Expand Down Expand Up @@ -91,38 +91,23 @@ var (

// IsErrHost indicates whether an error was returned by a host as part of an RPC.
func IsErrHost(err error) bool {
if err == nil {
return false
}
return errors.Is(err, errHost) || strings.Contains(err.Error(), errHost.Error())
return utils.IsErr(err, errHost)
}

func isBalanceInsufficient(err error) bool { return isError(err, errBalanceInsufficient) }
func isBalanceMaxExceeded(err error) bool { return isError(err, errBalanceMaxExceeded) }
func isBalanceInsufficient(err error) bool { return utils.IsErr(err, errBalanceInsufficient) }
func isBalanceMaxExceeded(err error) bool { return utils.IsErr(err, errBalanceMaxExceeded) }
func isClosedStream(err error) bool {
return isError(err, mux.ErrClosedStream) || isError(err, net.ErrClosed)
return utils.IsErr(err, mux.ErrClosedStream) || utils.IsErr(err, net.ErrClosed)
}
func isInsufficientFunds(err error) bool { return isError(err, ErrInsufficientFunds) }
func isPriceTableExpired(err error) bool { return isError(err, errPriceTableExpired) }
func isPriceTableGouging(err error) bool { return isError(err, errPriceTableGouging) }
func isPriceTableNotFound(err error) bool { return isError(err, errPriceTableNotFound) }
func isInsufficientFunds(err error) bool { return utils.IsErr(err, ErrInsufficientFunds) }
func isPriceTableExpired(err error) bool { return utils.IsErr(err, errPriceTableExpired) }
func isPriceTableGouging(err error) bool { return utils.IsErr(err, errPriceTableGouging) }
func isPriceTableNotFound(err error) bool { return utils.IsErr(err, errPriceTableNotFound) }
func isSectorNotFound(err error) bool {
return isError(err, errSectorNotFound) || isError(err, errSectorNotFoundOld)
}
func isWithdrawalsInactive(err error) bool { return isError(err, errWithdrawalsInactive) }
func isWithdrawalExpired(err error) bool { return isError(err, errWithdrawalExpired) }

func isError(err error, target error) bool {
if err == nil {
return err == target
}
// compare error first
if errors.Is(err, target) {
return true
}
// then compare the string in case the error was returned by a host
return strings.Contains(strings.ToLower(err.Error()), strings.ToLower(target.Error()))
return utils.IsErr(err, errSectorNotFound) || utils.IsErr(err, errSectorNotFoundOld)
}
func isWithdrawalsInactive(err error) bool { return utils.IsErr(err, errWithdrawalsInactive) }
func isWithdrawalExpired(err error) bool { return utils.IsErr(err, errWithdrawalExpired) }

// wrapRPCErr extracts the innermost error, wraps it in either a errHost or
// errTransport and finally wraps it using the provided fnName.
Expand Down Expand Up @@ -167,7 +152,6 @@ func (s *streamV3) WriteResponse(resp rhpv3.ProtocolObject) (err error) {
return s.Stream.WriteResponse(resp)
}

// ReadRequest reads an RPC request using the new loop protocol.
func (s *streamV3) ReadRequest(req rhpv3.ProtocolObject, maxLen uint64) (err error) {
defer wrapRPCErr(&err, "ReadRequest")
return s.Stream.ReadRequest(req, maxLen)
Expand Down
3 changes: 2 additions & 1 deletion worker/uploader.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
rhpv2 "go.sia.tech/core/rhp/v2"
"go.sia.tech/core/types"
"go.sia.tech/renterd/api"
"go.sia.tech/renterd/internal/utils"
"go.sia.tech/renterd/stats"
"go.uber.org/zap"
)
Expand Down Expand Up @@ -298,7 +299,7 @@ func (u *uploader) tryRecomputeStats() {
func (u *uploader) tryRefresh(ctx context.Context) bool {
// fetch the renewed contract
renewed, err := u.cs.RenewedContract(ctx, u.ContractID())
if isError(err, api.ErrContractNotFound) || isError(err, context.Canceled) {
if utils.IsErr(err, api.ErrContractNotFound) || utils.IsErr(err, context.Canceled) {
return false
} else if err != nil {
u.logger.Errorf("failed to fetch renewed contract %v, err: %v", u.ContractID(), err)
Expand Down
3 changes: 2 additions & 1 deletion worker/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"go.sia.tech/renterd/api"
"go.sia.tech/renterd/build"
"go.sia.tech/renterd/hostdb"
"go.sia.tech/renterd/internal/utils"
"go.sia.tech/renterd/object"
"go.sia.tech/renterd/webhooks"
"go.sia.tech/renterd/worker/client"
Expand Down Expand Up @@ -1197,7 +1198,7 @@ func (w *worker) multipartUploadHandlerPUT(jc jape.Context) {

// fetch upload from bus
upload, err := w.bus.MultipartUpload(ctx, uploadID)
if isError(err, api.ErrMultipartUploadNotFound) {
if utils.IsErr(err, api.ErrMultipartUploadNotFound) {
jc.Error(err, http.StatusNotFound)
return
} else if jc.Check("failed to fetch multipart upload", err) != nil {
Expand Down

0 comments on commit e80f974

Please sign in to comment.