summaryrefslogtreecommitdiffhomepage
path: root/control/controlclient/errors.go
diff options
context:
space:
mode:
Diffstat (limited to 'control/controlclient/errors.go')
-rw-r--r--control/controlclient/errors.go51
1 files changed, 51 insertions, 0 deletions
diff --git a/control/controlclient/errors.go b/control/controlclient/errors.go
new file mode 100644
index 000000000..9b4dab844
--- /dev/null
+++ b/control/controlclient/errors.go
@@ -0,0 +1,51 @@
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+package controlclient
+
+import (
+ "errors"
+ "fmt"
+ "net/http"
+)
+
+// apiResponseError is an error type that can be returned by controlclient
+// api requests.
+//
+// It wraps an underlying error and a flag for clients to query if the
+// error is retryable via the Retryable() method.
+type apiResponseError struct {
+ err error
+ retryable bool
+}
+
+// Error implements [error].
+func (e *apiResponseError) Error() string {
+ return e.err.Error()
+}
+
+// Retryable reports whether the error is retryable.
+func (e *apiResponseError) Retryable() bool {
+ return e.retryable
+}
+
+func (e *apiResponseError) Unwrap() error { return e.err }
+
+var (
+ errNoNodeKey = &apiResponseError{errors.New("no node key"), true}
+ errNoNoiseClient = &apiResponseError{errors.New("no noise client"), true}
+ errHTTPPostFailure = &apiResponseError{errors.New("http failure"), true}
+)
+
+func errBadHTTPResponse(code int, msg string) error {
+ retryable := false
+ switch code {
+ case http.StatusTooManyRequests,
+ http.StatusInternalServerError,
+ http.StatusBadGateway,
+ http.StatusServiceUnavailable,
+ http.StatusGatewayTimeout:
+ retryable = true
+ }
+ return &apiResponseError{fmt.Errorf("http error %d: %s", code, msg), retryable}
+}