diff --git a/Gopkg.lock b/Gopkg.lock index b88eb80f8..6cafc76e8 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -145,18 +145,6 @@ revision = "24333298e36590ea0716598caacc8959fc393c48" version = "v0.0.2" -[[projects]] - digest = "1:62e5b997b5ada9b5f71e759c3474f2a0de8de1b21473bab9e4f98c5aa69c05eb" - name = "github.com/cpuguy83/strongerrors" - packages = [ - ".", - "status", - "status/ocstatus", - ] - pruneopts = "NUT" - revision = "05f877ca1e627f0a1e01902ba78c63f1ef7db5a3" - version = "v0.2.1" - [[projects]] digest = "1:a2c1d0e43bd3baaa071d1b9ed72c27d78169b2b269f71c105ac4ba34b1be4a39" name = "github.com/davecgh/go-spew" @@ -1332,9 +1320,6 @@ "github.com/aws/aws-sdk-go/service/ecs/ecsiface", "github.com/aws/aws-sdk-go/service/iam", "github.com/cenkalti/backoff", - "github.com/cpuguy83/strongerrors", - "github.com/cpuguy83/strongerrors/status", - "github.com/cpuguy83/strongerrors/status/ocstatus", "github.com/davecgh/go-spew/spew", "github.com/google/go-cmp/cmp", "github.com/google/uuid", diff --git a/Gopkg.toml b/Gopkg.toml index 15856e36a..952f82398 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -70,10 +70,6 @@ name = "github.com/gophercloud/gophercloud" revision = "954aa14363ced787c28efcfcd15ae6945eb862fb" -[[constraint]] - name = "github.com/cpuguy83/strongerrors" - version = "0.2.1" - [[override]] name = "github.com/docker/docker" revision = "49bf474f9ed7ce7143a59d1964ff7b7fd9b52178" diff --git a/cmd/virtual-kubelet/commands/root/node.go b/cmd/virtual-kubelet/commands/root/node.go index c949abd64..728575688 100644 --- a/cmd/virtual-kubelet/commands/root/node.go +++ b/cmd/virtual-kubelet/commands/root/node.go @@ -18,8 +18,7 @@ import ( "context" "strings" - "github.com/cpuguy83/strongerrors" - "github.com/pkg/errors" + "github.com/virtual-kubelet/virtual-kubelet/errdefs" "github.com/virtual-kubelet/virtual-kubelet/providers" "github.com/virtual-kubelet/virtual-kubelet/version" corev1 "k8s.io/api/core/v1" @@ -100,7 +99,7 @@ func getTaint(c Opts) (*corev1.Taint, error) { case "PreferNoSchedule": effect = corev1.TaintEffectPreferNoSchedule default: - return nil, strongerrors.InvalidArgument(errors.Errorf("taint effect %q is not supported", effectEnv)) + return nil, errdefs.InvalidInputf("taint effect %q is not supported", effectEnv) } return &corev1.Taint{ diff --git a/cmd/virtual-kubelet/commands/root/root.go b/cmd/virtual-kubelet/commands/root/root.go index aa64890a8..c8813f1fe 100644 --- a/cmd/virtual-kubelet/commands/root/root.go +++ b/cmd/virtual-kubelet/commands/root/root.go @@ -20,9 +20,9 @@ import ( "path" "time" - "github.com/cpuguy83/strongerrors" "github.com/pkg/errors" "github.com/spf13/cobra" + "github.com/virtual-kubelet/virtual-kubelet/errdefs" "github.com/virtual-kubelet/virtual-kubelet/log" "github.com/virtual-kubelet/virtual-kubelet/manager" "github.com/virtual-kubelet/virtual-kubelet/providers" @@ -64,11 +64,11 @@ func runRootCommand(ctx context.Context, c Opts) error { defer cancel() if ok := providers.ValidOperatingSystems[c.OperatingSystem]; !ok { - return strongerrors.InvalidArgument(errors.Errorf("operating system %q is not supported", c.OperatingSystem)) + return errdefs.InvalidInputf("operating system %q is not supported", c.OperatingSystem) } if c.PodSyncWorkers == 0 { - return strongerrors.InvalidArgument(errors.New("pod sync workers must be greater than 0")) + return errdefs.InvalidInput("pod sync workers must be greater than 0") } var taint *corev1.Taint diff --git a/cmd/virtual-kubelet/commands/root/tracing.go b/cmd/virtual-kubelet/commands/root/tracing.go index 9c99829e4..445273d34 100644 --- a/cmd/virtual-kubelet/commands/root/tracing.go +++ b/cmd/virtual-kubelet/commands/root/tracing.go @@ -22,8 +22,8 @@ import ( "strconv" "strings" - "github.com/cpuguy83/strongerrors" "github.com/pkg/errors" + "github.com/virtual-kubelet/virtual-kubelet/errdefs" "github.com/virtual-kubelet/virtual-kubelet/log" "github.com/virtual-kubelet/virtual-kubelet/trace/opencensus" octrace "go.opencensus.io/trace" @@ -41,7 +41,7 @@ var ( func setupTracing(ctx context.Context, c Opts) error { for k := range c.TraceConfig.Tags { if reservedTagNames[k] { - return strongerrors.InvalidArgument(errors.Errorf("invalid trace tag %q, must not use a reserved tag key", k)) + return errdefs.InvalidInputf("invalid trace tag %q, must not use a reserved tag key", k) } } if c.TraceConfig.Tags == nil { @@ -72,10 +72,10 @@ func setupTracing(ctx context.Context, c Opts) error { default: rate, err := strconv.Atoi(c.TraceSampleRate) if err != nil { - return strongerrors.InvalidArgument(errors.Wrap(err, "unsupported trace sample rate")) + return errdefs.AsInvalidInput(errors.Wrap(err, "unsupported trace sample rate")) } if rate < 0 || rate > 100 { - return strongerrors.InvalidArgument(errors.Wrap(err, "trace sample rate must be between 0 and 100")) + return errdefs.AsInvalidInput(errors.Wrap(err, "trace sample rate must be between 0 and 100")) } s = octrace.ProbabilitySampler(float64(rate) / 100) } diff --git a/errdefs/invalid.go b/errdefs/invalid.go new file mode 100644 index 000000000..d2ffa0460 --- /dev/null +++ b/errdefs/invalid.go @@ -0,0 +1,65 @@ +package errdefs + +import ( + "errors" + "fmt" +) + +// InvalidInput is an error interface which denotes whether the opration failed due +// to a the resource not being found. +type ErrInvalidInput interface { + InvalidInput() bool + error +} + +type invalidInputError struct { + error +} + +func (e *invalidInputError) InvalidInput() bool { + return true +} + +func (e *invalidInputError) Cause() error { + return e.error +} + +// AsInvalidInput wraps the passed in error to make it of type ErrInvalidInput +// +// Callers should make sure the passed in error has exactly the error message +// it wants as this function does not decorate the message. +func AsInvalidInput(err error) error { + if err == nil { + return nil + } + return &invalidInputError{err} +} + +// InvalidInput makes an ErrInvalidInput from the provided error message +func InvalidInput(msg string) error { + return &invalidInputError{errors.New(msg)} +} + +// InvalidInputf makes an ErrInvalidInput from the provided error format and args +func InvalidInputf(format string, args ...interface{}) error { + return &invalidInputError{fmt.Errorf(format, args...)} +} + +// IsInvalidInput determines if the passed in error is of type ErrInvalidInput +// +// This will traverse the causal chain (`Cause() error`), until it finds an error +// which implements the `InvalidInput` interface. +func IsInvalidInput(err error) bool { + if err == nil { + return false + } + if e, ok := err.(ErrInvalidInput); ok { + return e.InvalidInput() + } + + if e, ok := err.(causal); ok { + return IsInvalidInput(e) + } + + return false +} diff --git a/errdefs/invalid_test.go b/errdefs/invalid_test.go new file mode 100644 index 000000000..1a3002b45 --- /dev/null +++ b/errdefs/invalid_test.go @@ -0,0 +1,80 @@ +package errdefs + +import ( + "errors" + "fmt" + "testing" + + "gotest.tools/assert" + "gotest.tools/assert/cmp" +) + +type testingInvalidInputError bool + +func (e testingInvalidInputError) Error() string { + return fmt.Sprintf("%v", bool(e)) +} + +func (e testingInvalidInputError) InvalidInput() bool { + return bool(e) +} + +func TestIsInvalidInput(t *testing.T) { + type testCase struct { + name string + err error + xMsg string + xInvalidInput bool + } + + for _, c := range []testCase{ + { + name: "InvalidInputf", + err: InvalidInputf("%s not found", "foo"), + xMsg: "foo not found", + xInvalidInput: true, + }, + { + name: "AsInvalidInput", + err: AsInvalidInput(errors.New("this is a test")), + xMsg: "this is a test", + xInvalidInput: true, + }, + { + name: "AsInvalidInputWithNil", + err: AsInvalidInput(nil), + xMsg: "", + xInvalidInput: false, + }, + { + name: "nilError", + err: nil, + xMsg: "", + xInvalidInput: false, + }, + { + name: "customInvalidInputFalse", + err: testingInvalidInputError(false), + xMsg: "false", + xInvalidInput: false, + }, + { + name: "customInvalidInputTrue", + err: testingInvalidInputError(true), + xMsg: "true", + xInvalidInput: true, + }, + } { + t.Run(c.name, func(t *testing.T) { + assert.Check(t, cmp.Equal(IsInvalidInput(c.err), c.xInvalidInput)) + if c.err != nil { + assert.Check(t, cmp.Equal(c.err.Error(), c.xMsg)) + } + }) + } +} + +func TestInvalidInputCause(t *testing.T) { + err := errors.New("test") + assert.Equal(t, (&invalidInputError{err}).Cause(), err) +} diff --git a/errdefs/notfound.go b/errdefs/notfound.go new file mode 100644 index 000000000..c55274dc9 --- /dev/null +++ b/errdefs/notfound.go @@ -0,0 +1,65 @@ +package errdefs + +import ( + "errors" + "fmt" +) + +// NotFound is an error interface which denotes whether the opration failed due +// to a the resource not being found. +type ErrNotFound interface { + NotFound() bool + error +} + +type notFoundError struct { + error +} + +func (e *notFoundError) NotFound() bool { + return true +} + +func (e *notFoundError) Cause() error { + return e.error +} + +// AsNotFound wraps the passed in error to make it of type ErrNotFound +// +// Callers should make sure the passed in error has exactly the error message +// it wants as this function does not decorate the message. +func AsNotFound(err error) error { + if err == nil { + return nil + } + return ¬FoundError{err} +} + +// NotFound makes an ErrNotFound from the provided error message +func NotFound(msg string) error { + return ¬FoundError{errors.New(msg)} +} + +// NotFoundf makes an ErrNotFound from the provided error format and args +func NotFoundf(format string, args ...interface{}) error { + return ¬FoundError{fmt.Errorf(format, args...)} +} + +// IsNotFound determines if the passed in error is of type ErrNotFound +// +// This will traverse the causal chain (`Cause() error`), until it finds an error +// which implements the `NotFound` interface. +func IsNotFound(err error) bool { + if err == nil { + return false + } + if e, ok := err.(ErrNotFound); ok { + return e.NotFound() + } + + if e, ok := err.(causal); ok { + return IsNotFound(e) + } + + return false +} diff --git a/errdefs/notfound_test.go b/errdefs/notfound_test.go new file mode 100644 index 000000000..52a67c458 --- /dev/null +++ b/errdefs/notfound_test.go @@ -0,0 +1,80 @@ +package errdefs + +import ( + "errors" + "fmt" + "testing" + + "gotest.tools/assert" + "gotest.tools/assert/cmp" +) + +type testingNotFoundError bool + +func (e testingNotFoundError) Error() string { + return fmt.Sprintf("%v", bool(e)) +} + +func (e testingNotFoundError) NotFound() bool { + return bool(e) +} + +func TestIsNotFound(t *testing.T) { + type testCase struct { + name string + err error + xMsg string + xNotFound bool + } + + for _, c := range []testCase{ + { + name: "NotFoundf", + err: NotFoundf("%s not found", "foo"), + xMsg: "foo not found", + xNotFound: true, + }, + { + name: "AsNotFound", + err: AsNotFound(errors.New("this is a test")), + xMsg: "this is a test", + xNotFound: true, + }, + { + name: "AsNotFoundWithNil", + err: AsNotFound(nil), + xMsg: "", + xNotFound: false, + }, + { + name: "nilError", + err: nil, + xMsg: "", + xNotFound: false, + }, + { + name: "customNotFoundFalse", + err: testingNotFoundError(false), + xMsg: "false", + xNotFound: false, + }, + { + name: "customNotFoundTrue", + err: testingNotFoundError(true), + xMsg: "true", + xNotFound: true, + }, + } { + t.Run(c.name, func(t *testing.T) { + assert.Check(t, cmp.Equal(IsNotFound(c.err), c.xNotFound)) + if c.err != nil { + assert.Check(t, cmp.Equal(c.err.Error(), c.xMsg)) + } + }) + } +} + +func TestNotFoundCause(t *testing.T) { + err := errors.New("test") + assert.Equal(t, (¬FoundError{err}).Cause(), err) +} diff --git a/errdefs/wrapped.go b/errdefs/wrapped.go new file mode 100644 index 000000000..446239311 --- /dev/null +++ b/errdefs/wrapped.go @@ -0,0 +1,10 @@ +package errdefs + +// Causal is an error interface for errors which have wrapped another error +// in a non-opaque way. +// +// This pattern is used by github.com/pkg/errors +type causal interface { + Cause() error + error +} diff --git a/providers/alibabacloud/eci.go b/providers/alibabacloud/eci.go index af919a178..080ef0549 100644 --- a/providers/alibabacloud/eci.go +++ b/providers/alibabacloud/eci.go @@ -17,7 +17,7 @@ import ( "time" "github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests" - "github.com/cpuguy83/strongerrors" + "github.com/virtual-kubelet/virtual-kubelet/errdefs" "github.com/virtual-kubelet/virtual-kubelet/log" "github.com/virtual-kubelet/virtual-kubelet/manager" "github.com/virtual-kubelet/virtual-kubelet/providers/alibabacloud/eci" @@ -254,7 +254,7 @@ func (p *ECIProvider) DeletePod(ctx context.Context, pod *v1.Pod) error { } } if eciId == "" { - return strongerrors.NotFound(fmt.Errorf("DeletePod can't find Pod %s-%s", pod.Namespace, pod.Name)) + return errdefs.NotFoundf("DeletePod can't find Pod %s-%s", pod.Namespace, pod.Name) } request := eci.CreateDeleteContainerGroupRequest() diff --git a/providers/alibabacloud/errors.go b/providers/alibabacloud/errors.go index 97807a4c4..1040eb196 100644 --- a/providers/alibabacloud/errors.go +++ b/providers/alibabacloud/errors.go @@ -4,7 +4,7 @@ import ( "net/http" "github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors" - "github.com/cpuguy83/strongerrors" + "github.com/virtual-kubelet/virtual-kubelet/errdefs" ) func wrapError(err error) error { @@ -19,7 +19,7 @@ func wrapError(err error) error { switch se.HttpStatus() { case http.StatusNotFound: - return strongerrors.NotFound(err) + return errdefs.AsNotFound(err) default: return err } diff --git a/providers/aws/fargate/cluster.go b/providers/aws/fargate/cluster.go index 57f27e642..dc07be79d 100644 --- a/providers/aws/fargate/cluster.go +++ b/providers/aws/fargate/cluster.go @@ -12,7 +12,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/cloudwatchlogs" "github.com/aws/aws-sdk-go/service/ecs" - "github.com/cpuguy83/strongerrors" + "github.com/virtual-kubelet/virtual-kubelet/errdefs" "github.com/virtual-kubelet/virtual-kubelet/vkubelet/api" k8sTypes "k8s.io/apimachinery/pkg/types" ) @@ -276,7 +276,7 @@ func (c *Cluster) GetPod(namespace string, name string) (*Pod, error) { tag := buildTaskDefinitionTag(c.name, namespace, name) pod, ok := c.pods[tag] if !ok { - return nil, strongerrors.NotFound(fmt.Errorf("pod %s/%s is not found", namespace, name)) + return nil, errdefs.NotFoundf("pod %s/%s is not found", namespace, name) } return pod, nil diff --git a/providers/azure/aci.go b/providers/azure/aci.go index bb0b9a32c..10355e42e 100644 --- a/providers/azure/aci.go +++ b/providers/azure/aci.go @@ -19,11 +19,11 @@ import ( "sync" "time" - "github.com/cpuguy83/strongerrors" "github.com/gorilla/websocket" client "github.com/virtual-kubelet/azure-aci/client" "github.com/virtual-kubelet/azure-aci/client/aci" "github.com/virtual-kubelet/azure-aci/client/network" + "github.com/virtual-kubelet/virtual-kubelet/errdefs" "github.com/virtual-kubelet/virtual-kubelet/log" "github.com/virtual-kubelet/virtual-kubelet/manager" "github.com/virtual-kubelet/virtual-kubelet/trace" @@ -777,7 +777,7 @@ func (p *ACIProvider) GetContainerLogs(ctx context.Context, namespace, podName, } if cg.Tags["NodeName"] != p.nodeName { - return nil, strongerrors.NotFound(errors.New("got unexpected pod node name")) + return nil, errdefs.NotFound("got unexpected pod node name") } // get logs from cg diff --git a/providers/azure/errors.go b/providers/azure/errors.go index 876b00e01..61115eb19 100644 --- a/providers/azure/errors.go +++ b/providers/azure/errors.go @@ -3,8 +3,8 @@ package azure import ( "net/http" - "github.com/cpuguy83/strongerrors" "github.com/virtual-kubelet/azure-aci/client/api" + "github.com/virtual-kubelet/virtual-kubelet/errdefs" ) func wrapError(err error) error { @@ -19,7 +19,7 @@ func wrapError(err error) error { switch e.StatusCode { case http.StatusNotFound: - return strongerrors.NotFound(err) + return errdefs.AsNotFound(err) default: return err } diff --git a/providers/azure/metrics.go b/providers/azure/metrics.go index eeb140d4a..893fe1c43 100644 --- a/providers/azure/metrics.go +++ b/providers/azure/metrics.go @@ -5,7 +5,6 @@ import ( "strings" "time" - "github.com/cpuguy83/strongerrors/status/ocstatus" "github.com/pkg/errors" "github.com/virtual-kubelet/azure-aci/client/aci" "github.com/virtual-kubelet/virtual-kubelet/log" @@ -97,7 +96,7 @@ func (p *ACIProvider) GetStatsSummary(ctx context.Context) (summary *stats.Summa Types: []aci.MetricType{aci.MetricTypeCPUUsage, aci.MetricTypeMemoryUsage}, }) if err != nil { - span.SetStatus(ocstatus.FromError(err)) + span.SetStatus(err) return errors.Wrapf(err, "error fetching cpu/mem stats for container group %s", cgName) } logger.Debug("Got system stats") @@ -109,7 +108,7 @@ func (p *ACIProvider) GetStatsSummary(ctx context.Context) (summary *stats.Summa Types: []aci.MetricType{aci.MetricTyperNetworkBytesRecievedPerSecond, aci.MetricTyperNetworkBytesTransmittedPerSecond}, }) if err != nil { - span.SetStatus(ocstatus.FromError(err)) + span.SetStatus(err) return errors.Wrapf(err, "error fetching network stats for container group %s", cgName) } logger.Debug("Got network stats") @@ -120,7 +119,7 @@ func (p *ACIProvider) GetStatsSummary(ctx context.Context) (summary *stats.Summa } if err := errGroup.Wait(); err != nil { - span.SetStatus(ocstatus.FromError(err)) + span.SetStatus(err) return nil, errors.Wrap(err, "error in request to fetch container group metrics") } close(chResult) diff --git a/providers/azurebatch/errors.go b/providers/azurebatch/errors.go index 811484cca..6aaff40d5 100644 --- a/providers/azurebatch/errors.go +++ b/providers/azurebatch/errors.go @@ -5,7 +5,7 @@ import ( "github.com/Azure/go-autorest/autorest" "github.com/Azure/go-autorest/autorest/azure" - "github.com/cpuguy83/strongerrors" + "github.com/virtual-kubelet/virtual-kubelet/errdefs" ) func wrapError(err error) error { @@ -14,7 +14,7 @@ func wrapError(err error) error { } switch { case isStatus(err, http.StatusNotFound): - return strongerrors.NotFound(err) + return errdefs.AsNotFound(err) default: return err } diff --git a/providers/cri/cri.go b/providers/cri/cri.go index e89b252f8..93368a4e0 100644 --- a/providers/cri/cri.go +++ b/providers/cri/cri.go @@ -16,8 +16,8 @@ import ( "syscall" "time" - "github.com/cpuguy83/strongerrors" log "github.com/sirupsen/logrus" + "github.com/virtual-kubelet/virtual-kubelet/errdefs" "github.com/virtual-kubelet/virtual-kubelet/manager" "github.com/virtual-kubelet/virtual-kubelet/providers" "github.com/virtual-kubelet/virtual-kubelet/vkubelet/api" @@ -569,7 +569,7 @@ func (p *CRIProvider) DeletePod(ctx context.Context, pod *v1.Pod) error { ps, ok := p.podStatus[pod.UID] if !ok { - return strongerrors.NotFound(fmt.Errorf("Pod %s not found", pod.UID)) + return errdefs.NotFoundf("Pod %s not found", pod.UID) } // TODO: Check pod status for running state @@ -601,7 +601,7 @@ func (p *CRIProvider) GetPod(ctx context.Context, namespace, name string) (*v1.P pod := p.findPodByName(namespace, name) if pod == nil { - return nil, strongerrors.NotFound(fmt.Errorf("Pod %s in namespace %s could not be found on the node", name, namespace)) + return nil, errdefs.NotFoundf("Pod %s in namespace %s could not be found on the node", name, namespace) } return createPodSpecFromCRI(pod, p.nodeName), nil @@ -638,11 +638,11 @@ func (p *CRIProvider) GetContainerLogs(ctx context.Context, namespace, podName, pod := p.findPodByName(namespace, podName) if pod == nil { - return nil, strongerrors.NotFound(fmt.Errorf("Pod %s in namespace %s not found", podName, namespace)) + return nil, errdefs.NotFoundf("Pod %s in namespace %s not found", podName, namespace) } container := pod.containers[containerName] if container == nil { - return nil, strongerrors.NotFound(fmt.Errorf("Cannot find container %s in pod %s namespace %s", containerName, podName, namespace)) + return nil, errdefs.NotFoundf("Cannot find container %s in pod %s namespace %s", containerName, podName, namespace) } return readLogFile(container.LogPath, opts) @@ -686,7 +686,7 @@ func (p *CRIProvider) GetPodStatus(ctx context.Context, namespace, name string) pod := p.findPodByName(namespace, name) if pod == nil { - return nil, strongerrors.NotFound(fmt.Errorf("Pod %s in namespace %s could not be found on the node", name, namespace)) + return nil, errdefs.NotFoundf("Pod %s in namespace %s could not be found on the node", name, namespace) } return createPodStatusFromCRI(pod), nil diff --git a/providers/huawei/cci.go b/providers/huawei/cci.go index 941d6496a..5a722eb0d 100644 --- a/providers/huawei/cci.go +++ b/providers/huawei/cci.go @@ -15,7 +15,7 @@ import ( "strings" "time" - "github.com/cpuguy83/strongerrors" + "github.com/virtual-kubelet/virtual-kubelet/errdefs" "github.com/virtual-kubelet/virtual-kubelet/manager" "github.com/virtual-kubelet/virtual-kubelet/providers/huawei/auth" "github.com/virtual-kubelet/virtual-kubelet/vkubelet/api" @@ -257,7 +257,7 @@ func errorFromResponse(resp *http.Response) error { switch resp.StatusCode { case http.StatusNotFound: - return strongerrors.NotFound(err) + return errdefs.AsNotFound(err) default: return err } diff --git a/providers/mock/mock.go b/providers/mock/mock.go index 67ee94547..6e40e60e6 100644 --- a/providers/mock/mock.go +++ b/providers/mock/mock.go @@ -10,8 +10,7 @@ import ( "strings" "time" - "github.com/cpuguy83/strongerrors" - "github.com/cpuguy83/strongerrors/status/ocstatus" + "github.com/virtual-kubelet/virtual-kubelet/errdefs" "github.com/virtual-kubelet/virtual-kubelet/log" "github.com/virtual-kubelet/virtual-kubelet/trace" "github.com/virtual-kubelet/virtual-kubelet/vkubelet/api" @@ -189,7 +188,7 @@ func (p *MockProvider) DeletePod(ctx context.Context, pod *v1.Pod) (err error) { } if _, exists := p.pods[key]; !exists { - return strongerrors.NotFound(fmt.Errorf("pod not found")) + return errdefs.NotFound("pod not found") } delete(p.pods, key) @@ -201,7 +200,7 @@ func (p *MockProvider) DeletePod(ctx context.Context, pod *v1.Pod) (err error) { func (p *MockProvider) GetPod(ctx context.Context, namespace, name string) (pod *v1.Pod, err error) { ctx, span := trace.StartSpan(ctx, "GetPod") defer func() { - span.SetStatus(ocstatus.FromError(err)) + span.SetStatus(err) span.End() }() @@ -218,7 +217,7 @@ func (p *MockProvider) GetPod(ctx context.Context, namespace, name string) (pod if pod, ok := p.pods[key]; ok { return pod, nil } - return nil, strongerrors.NotFound(fmt.Errorf("pod \"%s/%s\" is not known to the provider", namespace, name)) + return nil, errdefs.NotFoundf("pod \"%s/%s\" is not known to the provider", namespace, name) } // GetContainerLogs retrieves the logs of a container by name from the provider. diff --git a/providers/provider.go b/providers/provider.go index 36fcf2afc..f0976fc7a 100644 --- a/providers/provider.go +++ b/providers/provider.go @@ -11,6 +11,10 @@ import ( ) // Provider contains the methods required to implement a virtual-kubelet provider. +// +// Errors produced by these methods should implement an interface from +// github.com/virtual-kubelet/virtual-kubelet/errdefs package in order for the +// core logic to be able to understand the type of failure. type Provider interface { vkubelet.PodLifecycleHandler diff --git a/providers/register/register.go b/providers/register/register.go index b8d979fde..51a75d039 100644 --- a/providers/register/register.go +++ b/providers/register/register.go @@ -3,8 +3,7 @@ package register import ( "sort" - "github.com/cpuguy83/strongerrors" - "github.com/pkg/errors" + "github.com/virtual-kubelet/virtual-kubelet/errdefs" "github.com/virtual-kubelet/virtual-kubelet/manager" "github.com/virtual-kubelet/virtual-kubelet/providers" ) @@ -27,7 +26,7 @@ type initFunc func(InitConfig) (providers.Provider, error) func GetProvider(name string, cfg InitConfig) (providers.Provider, error) { f, ok := providerInits[name] if !ok { - return nil, strongerrors.NotFound(errors.Errorf("provider not found: %s", name)) + return nil, errdefs.NotFoundf("provider not found: %s", name) } return f(cfg) } diff --git a/providers/web/broker.go b/providers/web/broker.go index 9587f2351..32e33f336 100644 --- a/providers/web/broker.go +++ b/providers/web/broker.go @@ -29,7 +29,7 @@ import ( "time" "github.com/cenkalti/backoff" - "github.com/cpuguy83/strongerrors" + "github.com/virtual-kubelet/virtual-kubelet/errdefs" "github.com/virtual-kubelet/virtual-kubelet/vkubelet/api" v1 "k8s.io/api/core/v1" ) @@ -292,7 +292,7 @@ func checkResponseStatus(r *http.Response, err error) error { if r.StatusCode < 200 || r.StatusCode > 299 { switch r.StatusCode { case http.StatusNotFound: - return strongerrors.NotFound(errors.New(r.Status)) + return errdefs.NotFound(r.Status) default: return errors.New(r.Status) } diff --git a/trace/nop.go b/trace/nop.go index 2954ec63c..7a50bcf61 100644 --- a/trace/nop.go +++ b/trace/nop.go @@ -4,7 +4,6 @@ import ( "context" "github.com/virtual-kubelet/virtual-kubelet/log" - "go.opencensus.io/trace" ) type nopTracer struct{} @@ -15,9 +14,9 @@ func (nopTracer) StartSpan(ctx context.Context, _ string) (context.Context, Span type nopSpan struct{} -func (nopSpan) End() {} -func (nopSpan) SetStatus(trace.Status) {} -func (nopSpan) Logger() log.Logger { return nil } +func (nopSpan) End() {} +func (nopSpan) SetStatus(error) {} +func (nopSpan) Logger() log.Logger { return nil } func (nopSpan) WithField(ctx context.Context, _ string, _ interface{}) context.Context { return ctx } func (nopSpan) WithFields(ctx context.Context, _ log.Fields) context.Context { return ctx } diff --git a/trace/opencensus/ocagent.go b/trace/opencensus/ocagent.go index 8c813eb50..7b219a65b 100644 --- a/trace/opencensus/ocagent.go +++ b/trace/opencensus/ocagent.go @@ -6,8 +6,7 @@ import ( "os" "contrib.go.opencensus.io/exporter/ocagent" - "github.com/cpuguy83/strongerrors" - "github.com/pkg/errors" + "github.com/virtual-kubelet/virtual-kubelet/errdefs" "go.opencensus.io/trace" ) @@ -22,7 +21,7 @@ func NewOCAgentExporter(opts TracingExporterOptions) (trace.Exporter, error) { if endpoint := os.Getenv("OCAGENT_ENDPOINT"); endpoint != "" { agentOpts = append(agentOpts, ocagent.WithAddress(endpoint)) } else { - return nil, strongerrors.InvalidArgument(errors.New("must set endpoint address in OCAGENT_ENDPOINT")) + return nil, errdefs.InvalidInput("must set endpoint address in OCAGENT_ENDPOINT") } switch os.Getenv("OCAGENT_INSECURE") { @@ -30,7 +29,7 @@ func NewOCAgentExporter(opts TracingExporterOptions) (trace.Exporter, error) { case "1", "yes", "y", "on": agentOpts = append(agentOpts, ocagent.WithInsecure()) default: - return nil, strongerrors.InvalidArgument(errors.New("invalid value for OCAGENT_INSECURE")) + return nil, errdefs.InvalidInput("invalid value for OCAGENT_INSECURE") } return ocagent.NewExporter(agentOpts...) diff --git a/trace/opencensus/opencensus.go b/trace/opencensus/opencensus.go index afaef4f4d..ae9023d4b 100644 --- a/trace/opencensus/opencensus.go +++ b/trace/opencensus/opencensus.go @@ -9,6 +9,7 @@ import ( "fmt" "sync" + "github.com/virtual-kubelet/virtual-kubelet/errdefs" "github.com/virtual-kubelet/virtual-kubelet/log" "github.com/virtual-kubelet/virtual-kubelet/trace" octrace "go.opencensus.io/trace" @@ -46,7 +47,30 @@ func (s *span) End() { s.s.End() } -func (s *span) SetStatus(status trace.Status) { +func (s *span) SetStatus(err error) { + if !s.s.IsRecordingEvents() { + return + } + + var status octrace.Status + + if err == nil { + status.Code = octrace.StatusCodeOK + s.s.SetStatus(status) + return + } + + switch { + case errdefs.IsNotFound(err): + status.Code = octrace.StatusCodeNotFound + case errdefs.IsInvalidInput(err): + status.Code = octrace.StatusCodeInvalidArgument + // TODO: other error types + default: + status.Code = octrace.StatusCodeUnknown + } + + status.Message = err.Error() s.s.SetStatus(status) } diff --git a/trace/opencensus/register.go b/trace/opencensus/register.go index 2a74a95a4..a77b5c3f6 100644 --- a/trace/opencensus/register.go +++ b/trace/opencensus/register.go @@ -1,8 +1,7 @@ package opencensus import ( - "github.com/cpuguy83/strongerrors" - "github.com/pkg/errors" + "github.com/virtual-kubelet/virtual-kubelet/errdefs" "go.opencensus.io/trace" ) @@ -30,7 +29,7 @@ func RegisterTracingExporter(name string, f TracingExporterInitFunc) { func GetTracingExporter(name string, opts TracingExporterOptions) (trace.Exporter, error) { f, ok := tracingExporters[name] if !ok { - return nil, strongerrors.NotFound(errors.Errorf("tracing exporter %q not found", name)) + return nil, errdefs.NotFoundf("tracing exporter %q not found", name) } return f(opts) } diff --git a/trace/opencensus/register_test.go b/trace/opencensus/register_test.go index 140f0ba77..02c2ee4ab 100644 --- a/trace/opencensus/register_test.go +++ b/trace/opencensus/register_test.go @@ -3,8 +3,7 @@ package opencensus import ( "testing" - "github.com/cpuguy83/strongerrors" - + "github.com/virtual-kubelet/virtual-kubelet/errdefs" "go.opencensus.io/trace" ) @@ -16,7 +15,7 @@ func TestGetTracingExporter(t *testing.T) { } _, err := GetTracingExporter("notexist", TracingExporterOptions{}) - if !strongerrors.IsNotFound(err) { + if !errdefs.IsNotFound(err) { t.Fatalf("expected not found error, got: %v", err) } diff --git a/trace/trace.go b/trace/trace.go index 752432d4c..27e3ce27e 100644 --- a/trace/trace.go +++ b/trace/trace.go @@ -9,15 +9,8 @@ import ( "context" "github.com/virtual-kubelet/virtual-kubelet/log" - "go.opencensus.io/trace" ) -// Status is an alias to opencensus's trace status. -// The main reason we use this instead of implementing our own is library re-use, -// namely for converting an error to a tracing status. -// In the future this may be defined completely in this package. -type Status = trace.Status - // Tracer is the interface used for creating a tracing span type Tracer interface { // StartSpan starts a new span. The span details are emebedded into the returned @@ -41,7 +34,13 @@ func StartSpan(ctx context.Context, name string) (context.Context, Span) { // Span encapsulates a tracing event type Span interface { End() - SetStatus(Status) + + // SetStatus sets the final status of the span. + // errors passed to this should use interfaces defined in + // github.com/virtual-kubelet/virtual-kubelet/errdefs + // + // If the error is nil, the span should be considered successful. + SetStatus(err error) // WithField and WithFields adds attributes to an entire span // diff --git a/vendor/github.com/cpuguy83/strongerrors/LICENSE b/vendor/github.com/cpuguy83/strongerrors/LICENSE deleted file mode 100644 index 261eeb9e9..000000000 --- a/vendor/github.com/cpuguy83/strongerrors/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/github.com/cpuguy83/strongerrors/defs.go b/vendor/github.com/cpuguy83/strongerrors/defs.go deleted file mode 100644 index e67ced8fd..000000000 --- a/vendor/github.com/cpuguy83/strongerrors/defs.go +++ /dev/null @@ -1,84 +0,0 @@ -package strongerrors - -// ErrNotFound signals that the requested object doesn't exist -type ErrNotFound interface { - NotFound() -} - -// ErrInvalidArgument signals that the user input is invalid -type ErrInvalidArgument interface { - InvalidArgument() -} - -// ErrConflict signals that some internal state conflicts with the requested action and can't be performed. -// A change in state should be able to clear this error. -type ErrConflict interface { - Conflict() -} - -// ErrUnauthorized is used to signify that the user is not authorized to perform a specific action -type ErrUnauthorized interface { - Unauthorized() -} - -// ErrUnauthenticated is used to indicate that the caller cannot be identified. -type ErrUnauthenticated interface { - Unauthenticated() -} - -// ErrUnavailable signals that the requested action/subsystem is not available. -type ErrUnavailable interface { - Unavailable() -} - -// ErrForbidden signals that the requested action cannot be performed under any circumstances. -// When a ErrForbidden is returned, the caller should never retry the action. -type ErrForbidden interface { - Forbidden() -} - -// ErrSystem signals that some internal error occurred. -// An example of this would be a failed mount request. -type ErrSystem interface { - System() -} - -// ErrNotModified signals that an action can't be performed because it's already in the desired state -type ErrNotModified interface { - NotModified() -} - -// ErrAlreadyExists is a special case of ErrNotModified which signals that the desired object already exists -type ErrAlreadyExists interface { - AlreadyExists() -} - -// ErrNotImplemented signals that the requested action/feature is not implemented on the system as configured. -type ErrNotImplemented interface { - NotImplemented() -} - -// ErrUnknown signals that the kind of error that occurred is not known. -type ErrUnknown interface { - Unknown() -} - -// ErrCancelled signals that the action was cancelled. -type ErrCancelled interface { - Cancelled() -} - -// ErrDeadline signals that the deadline was reached before the action completed. -type ErrDeadline interface { - DeadlineExceeded() -} - -// ErrExhausted indicates that the action cannot be performed because some resource is exhausted. -type ErrExhausted interface { - Exhausted() -} - -// ErrDataLoss indicates that data was lost or there is data corruption. -type ErrDataLoss interface { - DataLoss() -} diff --git a/vendor/github.com/cpuguy83/strongerrors/doc.go b/vendor/github.com/cpuguy83/strongerrors/doc.go deleted file mode 100644 index f262bf98e..000000000 --- a/vendor/github.com/cpuguy83/strongerrors/doc.go +++ /dev/null @@ -1,12 +0,0 @@ -// Package strongerrors defines a set of error interfaces that packages should use for communicating classes of errors. -// Errors that cross the package boundary should implement one (and only one) of these interfaces. -// -// Packages should not reference these interfaces directly, only implement them. -// To check if a particular error implements one of these interfaces, there are helper -// functions provided (e.g. `Is`) which can be used rather than asserting the interfaces directly. -// If you must assert on these interfaces, be sure to check the causal chain (`err.Cause()`). -// -// A set of helper functions are provided to take any error and turn it into a specific error class. -// This frees you from defining the same error classes all over your code. However, you can still -// implement the error classes ony our own if you desire. -package strongerrors diff --git a/vendor/github.com/cpuguy83/strongerrors/helpers.go b/vendor/github.com/cpuguy83/strongerrors/helpers.go deleted file mode 100644 index 9efe54e25..000000000 --- a/vendor/github.com/cpuguy83/strongerrors/helpers.go +++ /dev/null @@ -1,272 +0,0 @@ -package strongerrors - -import "context" - -type errNotFound struct{ error } - -func (errNotFound) NotFound() {} - -func (e errNotFound) Cause() error { - return e.error -} - -// NotFound is a helper to create an error of the class with the same name from any error type -func NotFound(err error) error { - if err == nil { - return nil - } - return errNotFound{err} -} - -type errInvalidArg struct{ error } - -func (errInvalidArg) InvalidArgument() {} - -func (e errInvalidArg) Cause() error { - return e.error -} - -// InvalidArgument is a helper to create an error of the class with the same name from any error type -func InvalidArgument(err error) error { - if err == nil { - return nil - } - return errInvalidArg{err} -} - -type errConflict struct{ error } - -func (errConflict) Conflict() {} - -func (e errConflict) Cause() error { - return e.error -} - -// Conflict is a helper to create an error of the class with the same name from any error type -func Conflict(err error) error { - if err == nil { - return nil - } - return errConflict{err} -} - -type errUnauthorized struct{ error } - -func (errUnauthorized) Unauthorized() {} - -func (e errUnauthorized) Cause() error { - return e.error -} - -// Unauthorized is a helper to create an error of the class with the same name from any error type -func Unauthorized(err error) error { - if err == nil { - return nil - } - return errUnauthorized{err} -} - -type errUnauthenticated struct{ error } - -func (errUnauthenticated) Unauthenticated() {} - -func (e errUnauthenticated) Cause() error { - return e.error -} - -// Unauthenticated is a helper to create an error of the class with the same name from any error type -func Unauthenticated(err error) error { - if err == nil { - return nil - } - return errUnauthenticated{err} -} - -type errUnavailable struct{ error } - -func (errUnavailable) Unavailable() {} - -func (e errUnavailable) Cause() error { - return e.error -} - -// Unavailable is a helper to create an error of the class with the same name from any error type -func Unavailable(err error) error { - return errUnavailable{err} -} - -type errForbidden struct{ error } - -func (errForbidden) Forbidden() {} - -func (e errForbidden) Cause() error { - return e.error -} - -// Forbidden is a helper to create an error of the class with the same name from any error type -func Forbidden(err error) error { - if err == nil { - return nil - } - return errForbidden{err} -} - -type errSystem struct{ error } - -func (errSystem) System() {} - -func (e errSystem) Cause() error { - return e.error -} - -// System is a helper to create an error of the class with the same name from any error type -func System(err error) error { - if err == nil { - return nil - } - return errSystem{err} -} - -type errNotModified struct{ error } - -func (errNotModified) NotModified() {} - -func (e errNotModified) Cause() error { - return e.error -} - -// NotModified is a helper to create an error of the class with the same name from any error type -func NotModified(err error) error { - if err == nil { - return nil - } - return errNotModified{err} -} - -type errAlreadyExists struct{ error } - -func (errAlreadyExists) AlreadyExists() {} - -func (e errAlreadyExists) Cause() error { - return e.error -} - -// AlreadyExists is a helper to create an error of the class with the same name from any error type -func AlreadyExists(err error) error { - if err == nil { - return nil - } - return errAlreadyExists{err} -} - -type errNotImplemented struct{ error } - -func (errNotImplemented) NotImplemented() {} - -func (e errNotImplemented) Cause() error { - return e.error -} - -// NotImplemented is a helper to create an error of the class with the same name from any error type -func NotImplemented(err error) error { - if err == nil { - return nil - } - return errNotImplemented{err} -} - -type errUnknown struct{ error } - -func (errUnknown) Unknown() {} - -func (e errUnknown) Cause() error { - return e.error -} - -// Unknown is a helper to create an error of the class with the same name from any error type -func Unknown(err error) error { - if err == nil { - return nil - } - return errUnknown{err} -} - -type errCancelled struct{ error } - -func (errCancelled) Cancelled() {} - -func (e errCancelled) Cause() error { - return e.error -} - -// Cancelled is a helper to create an error of the class with the same name from any error type -func Cancelled(err error) error { - if err == nil { - return nil - } - return errCancelled{err} -} - -type errDeadline struct{ error } - -func (errDeadline) DeadlineExceeded() {} - -func (e errDeadline) Cause() error { - return e.error -} - -// Deadline is a helper to create an error of the class with the same name from any error type -func Deadline(err error) error { - if err == nil { - return nil - } - return errDeadline{err} -} - -type errExhausted struct{ error } - -func (errExhausted) Exhausted() {} - -func (e errExhausted) Cause() error { - return e.error -} - -// Exhausted is a helper to create an error of the class with the same name from any error type -func Exhausted(err error) error { - if err == nil { - return nil - } - return errExhausted{err} -} - -type errDataLoss struct{ error } - -func (errDataLoss) DataLoss() {} - -func (e errDataLoss) Cause() error { - return e.error -} - -// DataLoss is a helper to create an error of the class with the same name from any error type -func DataLoss(err error) error { - if err == nil { - return nil - } - return errDataLoss{err} -} - -// FromContext returns the error class from the passed in context -func FromContext(ctx context.Context) error { - e := ctx.Err() - if e == nil { - return nil - } - - if e == context.Canceled { - return Cancelled(e) - } - if e == context.DeadlineExceeded { - return Deadline(e) - } - return Unknown(e) -} diff --git a/vendor/github.com/cpuguy83/strongerrors/is.go b/vendor/github.com/cpuguy83/strongerrors/is.go deleted file mode 100644 index 2d94546d7..000000000 --- a/vendor/github.com/cpuguy83/strongerrors/is.go +++ /dev/null @@ -1,128 +0,0 @@ -package strongerrors - -type causer interface { - Cause() error -} - -func getImplementer(err error) error { - switch e := err.(type) { - case - ErrNotFound, - ErrInvalidArgument, - ErrConflict, - ErrUnauthorized, - ErrUnauthenticated, - ErrUnavailable, - ErrForbidden, - ErrSystem, - ErrNotModified, - ErrAlreadyExists, - ErrNotImplemented, - ErrCancelled, - ErrDeadline, - ErrDataLoss, - ErrExhausted, - ErrUnknown: - return err - case causer: - return getImplementer(e.Cause()) - default: - return err - } -} - -// IsNotFound returns if the passed in error is an ErrNotFound -func IsNotFound(err error) bool { - _, ok := getImplementer(err).(ErrNotFound) - return ok -} - -// IsInvalidArgument returns if the passed in error is an ErrInvalidParameter -func IsInvalidArgument(err error) bool { - _, ok := getImplementer(err).(ErrInvalidArgument) - return ok -} - -// IsConflict returns if the passed in error is an ErrConflict -func IsConflict(err error) bool { - _, ok := getImplementer(err).(ErrConflict) - return ok -} - -// IsUnauthorized returns if the the passed in error is an ErrUnauthorized -func IsUnauthorized(err error) bool { - _, ok := getImplementer(err).(ErrUnauthorized) - return ok -} - -// IsUnauthenticated returns if the the passed in error is an ErrUnauthenticated -func IsUnauthenticated(err error) bool { - _, ok := getImplementer(err).(ErrUnauthenticated) - return ok -} - -// IsUnavailable returns if the passed in error is an ErrUnavailable -func IsUnavailable(err error) bool { - _, ok := getImplementer(err).(ErrUnavailable) - return ok -} - -// IsForbidden returns if the passed in error is an ErrForbidden -func IsForbidden(err error) bool { - _, ok := getImplementer(err).(ErrForbidden) - return ok -} - -// IsSystem returns if the passed in error is an ErrSystem -func IsSystem(err error) bool { - _, ok := getImplementer(err).(ErrSystem) - return ok -} - -// IsNotModified returns if the passed in error is a NotModified error -func IsNotModified(err error) bool { - _, ok := getImplementer(err).(ErrNotModified) - return ok -} - -// IsAlreadyExists returns if the passed in error is a AlreadyExists error -func IsAlreadyExists(err error) bool { - _, ok := getImplementer(err).(ErrAlreadyExists) - return ok -} - -// IsNotImplemented returns if the passed in error is an ErrNotImplemented -func IsNotImplemented(err error) bool { - _, ok := getImplementer(err).(ErrNotImplemented) - return ok -} - -// IsUnknown returns if the passed in error is an ErrUnknown -func IsUnknown(err error) bool { - _, ok := getImplementer(err).(ErrUnknown) - return ok -} - -// IsCancelled returns if the passed in error is an ErrCancelled -func IsCancelled(err error) bool { - _, ok := getImplementer(err).(ErrCancelled) - return ok -} - -// IsDeadline returns if the passed in error is an ErrDeadline -func IsDeadline(err error) bool { - _, ok := getImplementer(err).(ErrDeadline) - return ok -} - -// IsExhausted returns if the passed in error is an ErrDeadline -func IsExhausted(err error) bool { - _, ok := getImplementer(err).(ErrExhausted) - return ok -} - -// IsDataLoss returns if the passed in error is an ErrDataLoss -func IsDataLoss(err error) bool { - _, ok := getImplementer(err).(ErrDataLoss) - return ok -} diff --git a/vendor/github.com/cpuguy83/strongerrors/status/grpc.go b/vendor/github.com/cpuguy83/strongerrors/status/grpc.go deleted file mode 100644 index c446a86a5..000000000 --- a/vendor/github.com/cpuguy83/strongerrors/status/grpc.go +++ /dev/null @@ -1,85 +0,0 @@ -package status - -import ( - "github.com/cpuguy83/strongerrors" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" -) - -// FromGRPC returns an error class from the provided GPRC status -// If the status is nil or OK, this will return nil -// nolint: gocyclo -func FromGRPC(s *status.Status) error { - if s == nil || s.Code() == codes.OK { - return nil - } - - switch s.Code() { - case codes.InvalidArgument: - return strongerrors.InvalidArgument(s.Err()) - case codes.NotFound: - return strongerrors.NotFound(s.Err()) - case codes.Unimplemented: - return strongerrors.NotImplemented(s.Err()) - case codes.DeadlineExceeded: - return strongerrors.Deadline(s.Err()) - case codes.Canceled: - return strongerrors.Cancelled(s.Err()) - case codes.AlreadyExists: - return strongerrors.AlreadyExists(s.Err()) - case codes.PermissionDenied: - return strongerrors.Unauthorized(s.Err()) - case codes.Unauthenticated: - return strongerrors.Unauthenticated(s.Err()) - // TODO(cpuguy83): consider more granular errors for these cases - case codes.FailedPrecondition, codes.Aborted, codes.Unavailable, codes.OutOfRange: - return strongerrors.Conflict(s.Err()) - case codes.ResourceExhausted: - return strongerrors.Exhausted(s.Err()) - case codes.DataLoss: - return strongerrors.DataLoss(s.Err()) - default: - return strongerrors.Unknown(s.Err()) - } -} - -// ToGRPC takes the passed in error and converts it to a GRPC status error -// If the passed in error is already a gprc status error, then it is returned unmodified -// If the passed in error is nil, then a nil error is returned. -// nolint: gocyclo -func ToGRPC(err error) error { - if _, ok := status.FromError(err); ok { - return err - } - - switch { - case strongerrors.IsNotFound(err): - return status.Error(codes.NotFound, err.Error()) - case strongerrors.IsConflict(err), strongerrors.IsNotModified(err): - return status.Error(codes.FailedPrecondition, err.Error()) - case strongerrors.IsInvalidArgument(err): - return status.Error(codes.InvalidArgument, err.Error()) - case strongerrors.IsAlreadyExists(err): - return status.Error(codes.AlreadyExists, err.Error()) - case strongerrors.IsCancelled(err): - return status.Error(codes.Canceled, err.Error()) - case strongerrors.IsDeadline(err): - return status.Error(codes.DeadlineExceeded, err.Error()) - case strongerrors.IsUnauthorized(err): - return status.Error(codes.PermissionDenied, err.Error()) - case strongerrors.IsUnauthenticated(err): - return status.Error(codes.Unauthenticated, err.Error()) - case strongerrors.IsForbidden(err), strongerrors.IsNotImplemented(err): - return status.Error(codes.Unimplemented, err.Error()) - case strongerrors.IsExhausted(err): - return status.Error(codes.ResourceExhausted, err.Error()) - case strongerrors.IsDataLoss(err): - return status.Error(codes.DataLoss, err.Error()) - case strongerrors.IsSystem(err): - return status.Error(codes.Internal, err.Error()) - case strongerrors.IsUnavailable(err): - return status.Error(codes.Unavailable, err.Error()) - default: - return status.Error(codes.Unknown, err.Error()) - } -} diff --git a/vendor/github.com/cpuguy83/strongerrors/status/http.go b/vendor/github.com/cpuguy83/strongerrors/status/http.go deleted file mode 100644 index fa970ce61..000000000 --- a/vendor/github.com/cpuguy83/strongerrors/status/http.go +++ /dev/null @@ -1,37 +0,0 @@ -package status - -import ( - "net/http" - - "github.com/cpuguy83/strongerrors" -) - -// HTTPCode takes an error and returns the HTTP status code for the given error -// If a match is found then the second return argument will be true, otherwise it will be false. -// nolint: gocyclo -func HTTPCode(err error) (int, bool) { - switch { - case strongerrors.IsNotFound(err): - return http.StatusNotFound, true - case strongerrors.IsInvalidArgument(err): - return http.StatusBadRequest, true - case strongerrors.IsConflict(err): - return http.StatusConflict, true - case strongerrors.IsUnauthenticated(err), strongerrors.IsForbidden(err): - return http.StatusForbidden, true - case strongerrors.IsUnauthorized(err): - return http.StatusUnauthorized, true - case strongerrors.IsUnavailable(err): - return http.StatusServiceUnavailable, true - case strongerrors.IsForbidden(err): - return http.StatusForbidden, true - case strongerrors.IsAlreadyExists(err), strongerrors.IsNotModified(err): - return http.StatusNotModified, true - case strongerrors.IsNotImplemented(err): - return http.StatusNotImplemented, true - case strongerrors.IsSystem(err) || strongerrors.IsUnknown(err) || strongerrors.IsDataLoss(err) || strongerrors.IsExhausted(err): - return http.StatusInternalServerError, true - default: - return http.StatusInternalServerError, false - } -} diff --git a/vendor/github.com/cpuguy83/strongerrors/status/ocstatus/status.go b/vendor/github.com/cpuguy83/strongerrors/status/ocstatus/status.go deleted file mode 100644 index e76e19654..000000000 --- a/vendor/github.com/cpuguy83/strongerrors/status/ocstatus/status.go +++ /dev/null @@ -1,49 +0,0 @@ -// Package ocstatus provides error status conversions to opencencus status trace.StatusCode -package ocstatus - -import ( - "github.com/cpuguy83/strongerrors" - "go.opencensus.io/trace" -) - -// FromError makes an opencencus trace.Status from the passed in error. -func FromError(err error) trace.Status { - if err == nil { - return trace.Status{Code: trace.StatusCodeOK} - } - - switch { - case strongerrors.IsNotFound(err): - return status(trace.StatusCodeNotFound, err) - case strongerrors.IsConflict(err), strongerrors.IsNotModified(err): - return status(trace.StatusCodeFailedPrecondition, err) - case strongerrors.IsInvalidArgument(err): - return status(trace.StatusCodeInvalidArgument, err) - case strongerrors.IsAlreadyExists(err): - return status(trace.StatusCodeAlreadyExists, err) - case strongerrors.IsCancelled(err): - return status(trace.StatusCodeCancelled, err) - case strongerrors.IsDeadline(err): - return status(trace.StatusCodeDeadlineExceeded, err) - case strongerrors.IsUnauthorized(err): - return status(trace.StatusCodePermissionDenied, err) - case strongerrors.IsUnauthenticated(err): - return status(trace.StatusCodeUnauthenticated, err) - case strongerrors.IsForbidden(err), strongerrors.IsNotImplemented(err): - return status(trace.StatusCodeUnimplemented, err) - case strongerrors.IsExhausted(err): - return status(trace.StatusCodeResourceExhausted, err) - case strongerrors.IsDataLoss(err): - return status(trace.StatusCodeDataLoss, err) - case strongerrors.IsSystem(err): - return status(trace.StatusCodeInternal, err) - case strongerrors.IsUnavailable(err): - return status(trace.StatusCodeUnavailable, err) - default: - return status(trace.StatusCodeUnknown, err) - } -} - -func status(code int32, err error) trace.Status { - return trace.Status{Code: code, Message: err.Error()} -} diff --git a/vkubelet/api/exec.go b/vkubelet/api/exec.go index ebbacd9ae..310ac3fa8 100644 --- a/vkubelet/api/exec.go +++ b/vkubelet/api/exec.go @@ -7,9 +7,9 @@ import ( "strings" "time" - "github.com/cpuguy83/strongerrors" "github.com/gorilla/mux" "github.com/pkg/errors" + "github.com/virtual-kubelet/virtual-kubelet/errdefs" "k8s.io/apimachinery/pkg/types" remoteutils "k8s.io/client-go/tools/remotecommand" api "k8s.io/kubernetes/pkg/apis/core" @@ -56,7 +56,7 @@ func HandleContainerExec(h ContainerExecHandlerFunc) http.HandlerFunc { streamOpts, err := getExecOptions(req) if err != nil { - return strongerrors.InvalidArgument(err) + return errdefs.AsInvalidInput(err) } idleTimeout := time.Second * 30 diff --git a/vkubelet/api/helpers.go b/vkubelet/api/helpers.go index 1d49f8273..9d8010d1f 100644 --- a/vkubelet/api/helpers.go +++ b/vkubelet/api/helpers.go @@ -4,7 +4,7 @@ import ( "io" "net/http" - "github.com/cpuguy83/strongerrors/status" + "github.com/virtual-kubelet/virtual-kubelet/errdefs" "github.com/virtual-kubelet/virtual-kubelet/log" ) @@ -17,7 +17,7 @@ func handleError(f handlerFunc) http.HandlerFunc { return } - code, _ := status.HTTPCode(err) + code := httpStatusCode(err) w.WriteHeader(code) io.WriteString(w, err.Error()) logger := log.G(req.Context()).WithError(err).WithField("httpStatusCode", code) @@ -55,3 +55,16 @@ func (fw *flushWriter) Write(p []byte) (int, error) { } return n, err } + +func httpStatusCode(err error) int { + switch { + case err == nil: + return http.StatusOK + case errdefs.IsNotFound(err): + return http.StatusNotFound + case errdefs.IsInvalidInput(err): + return http.StatusBadRequest + default: + return http.StatusInternalServerError + } +} diff --git a/vkubelet/api/logs.go b/vkubelet/api/logs.go index d062c98e2..b1dc3a279 100644 --- a/vkubelet/api/logs.go +++ b/vkubelet/api/logs.go @@ -7,9 +7,9 @@ import ( "strconv" "time" - "github.com/cpuguy83/strongerrors" "github.com/gorilla/mux" "github.com/pkg/errors" + "github.com/virtual-kubelet/virtual-kubelet/errdefs" "github.com/virtual-kubelet/virtual-kubelet/log" ) @@ -33,7 +33,7 @@ func HandleContainerLogs(h ContainerLogsHandlerFunc) http.HandlerFunc { return handleError(func(w http.ResponseWriter, req *http.Request) error { vars := mux.Vars(req) if len(vars) != 3 { - return strongerrors.NotFound(errors.New("not found")) + return errdefs.NotFound("not found") } ctx := req.Context() @@ -47,7 +47,7 @@ func HandleContainerLogs(h ContainerLogsHandlerFunc) http.HandlerFunc { if queryTail := q.Get("tailLines"); queryTail != "" { t, err := strconv.Atoi(queryTail) if err != nil { - return strongerrors.InvalidArgument(errors.Wrap(err, "could not parse \"tailLines\"")) + return errdefs.AsInvalidInput(errors.Wrap(err, "could not parse \"tailLines\"")) } tail = t } @@ -73,7 +73,7 @@ func HandleContainerLogs(h ContainerLogsHandlerFunc) http.HandlerFunc { } if _, err := io.Copy(flushOnWrite(w), logs); err != nil { - return strongerrors.Unknown(errors.Wrap(err, "error writing response to client")) + return errors.Wrap(err, "error writing response to client") } return nil }) diff --git a/vkubelet/api/pods.go b/vkubelet/api/pods.go index e0dc3376a..37275d374 100644 --- a/vkubelet/api/pods.go +++ b/vkubelet/api/pods.go @@ -4,7 +4,6 @@ import ( "context" "net/http" - "github.com/cpuguy83/strongerrors" "github.com/virtual-kubelet/virtual-kubelet/log" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" @@ -36,13 +35,13 @@ func HandleRunningPods(getPods PodListerFunc) http.HandlerFunc { codec := codecs.LegacyCodec(v1.SchemeGroupVersion) data, err := runtime.Encode(codec, podList) if err != nil { - return strongerrors.System(err) + return err } w.Header().Set("Content-Type", "application/json") _, err = w.Write(data) if err != nil { - return strongerrors.System(err) + return err } return nil }) diff --git a/vkubelet/api/stats.go b/vkubelet/api/stats.go index 444e26b21..a2a6fbe6f 100644 --- a/vkubelet/api/stats.go +++ b/vkubelet/api/stats.go @@ -5,7 +5,6 @@ import ( "encoding/json" "net/http" - "github.com/cpuguy83/strongerrors" "github.com/pkg/errors" stats "k8s.io/kubernetes/pkg/kubelet/apis/stats/v1alpha1" ) @@ -21,20 +20,36 @@ func HandlePodStatsSummary(h PodStatsSummaryHandlerFunc) http.HandlerFunc { return handleError(func(w http.ResponseWriter, req *http.Request) error { stats, err := h(req.Context()) if err != nil { - if errors.Cause(err) == context.Canceled { - return strongerrors.Cancelled(err) + if isCancelled(err) { + return err } return errors.Wrap(err, "error getting status from provider") } b, err := json.Marshal(stats) if err != nil { - return strongerrors.Unknown(errors.Wrap(err, "error marshalling stats")) + return errors.Wrap(err, "error marshalling stats") } if _, err := w.Write(b); err != nil { - return strongerrors.Unknown(errors.Wrap(err, "could not write to client")) + return errors.Wrap(err, "could not write to client") } return nil }) } + +func isCancelled(err error) bool { + if err == context.Canceled { + return true + } + + if e, ok := err.(causal); ok { + return isCancelled(e.Cause()) + } + return false +} + +type causal interface { + Cause() error + error +} diff --git a/vkubelet/node.go b/vkubelet/node.go index 12c1923cf..4fa73bc21 100644 --- a/vkubelet/node.go +++ b/vkubelet/node.go @@ -6,7 +6,6 @@ import ( "fmt" "time" - "github.com/cpuguy83/strongerrors/status/ocstatus" pkgerrors "github.com/pkg/errors" "github.com/virtual-kubelet/virtual-kubelet/log" "github.com/virtual-kubelet/virtual-kubelet/trace" @@ -275,7 +274,7 @@ func (n *Node) handlePing(ctx context.Context) (retErr error) { ctx, span := trace.StartSpan(ctx, "node.handlePing") defer span.End() defer func() { - span.SetStatus(ocstatus.FromError(retErr)) + span.SetStatus(retErr) }() if err := n.p.Ping(ctx); err != nil { @@ -367,7 +366,7 @@ func UpdateNodeLease(ctx context.Context, leases v1beta1.LeaseInterface, lease * l, err = ensureLease(ctx, leases, lease) } if err != nil { - span.SetStatus(ocstatus.FromError(err)) + span.SetStatus(err) return nil, err } log.G(ctx).Debug("created new lease") @@ -429,7 +428,7 @@ func UpdateNodeStatus(ctx context.Context, nodes v1.NodeInterface, n *corev1.Nod ctx, span := trace.StartSpan(ctx, "UpdateNodeStatus") defer func() { span.End() - span.SetStatus(ocstatus.FromError(retErr)) + span.SetStatus(retErr) }() var node *corev1.Node diff --git a/vkubelet/pod.go b/vkubelet/pod.go index b0a31c010..2473ebbfc 100644 --- a/vkubelet/pod.go +++ b/vkubelet/pod.go @@ -5,7 +5,6 @@ import ( "hash/fnv" "time" - "github.com/cpuguy83/strongerrors/status/ocstatus" "github.com/davecgh/go-spew/spew" pkgerrors "github.com/pkg/errors" "github.com/virtual-kubelet/virtual-kubelet/log" @@ -44,7 +43,7 @@ func (pc *PodController) createOrUpdatePod(ctx context.Context, pod *corev1.Pod) }) if err := populateEnvironmentVariables(ctx, pod, pc.resourceManager, pc.recorder); err != nil { - span.SetStatus(ocstatus.FromError(err)) + span.SetStatus(err) return err } @@ -113,7 +112,7 @@ func (pc *PodController) handleProviderError(ctx context.Context, span trace.Spa } else { logger.Info("Updated k8s pod status") } - span.SetStatus(ocstatus.FromError(origErr)) + span.SetStatus(origErr) } func (pc *PodController) deletePod(ctx context.Context, namespace, name string) error { @@ -132,7 +131,7 @@ func (pc *PodController) deletePod(ctx context.Context, namespace, name string) var delErr error if delErr = pc.provider.DeletePod(ctx, pod); delErr != nil && errors.IsNotFound(delErr) { - span.SetStatus(ocstatus.FromError(delErr)) + span.SetStatus(delErr) return delErr } @@ -140,7 +139,7 @@ func (pc *PodController) deletePod(ctx context.Context, namespace, name string) if !errors.IsNotFound(delErr) { if err := pc.forceDeletePodResource(ctx, namespace, name); err != nil { - span.SetStatus(ocstatus.FromError(err)) + span.SetStatus(err) return err } log.G(ctx).Info("Deleted pod from Kubernetes") @@ -163,7 +162,7 @@ func (pc *PodController) forceDeletePodResource(ctx context.Context, namespace, log.G(ctx).Debug("Pod does not exist in Kubernetes, nothing to delete") return nil } - span.SetStatus(ocstatus.FromError(err)) + span.SetStatus(err) return pkgerrors.Wrap(err, "Failed to delete Kubernetes pod") } return nil @@ -178,7 +177,7 @@ func (pc *PodController) updatePodStatuses(ctx context.Context, q workqueue.Rate pods, err := pc.podsLister.List(labels.Everything()) if err != nil { err = pkgerrors.Wrap(err, "error getting pod list") - span.SetStatus(ocstatus.FromError(err)) + span.SetStatus(err) log.G(ctx).WithError(err).Error("Error updating pod statuses") return } @@ -208,7 +207,7 @@ func (pc *PodController) updatePodStatus(ctx context.Context, pod *corev1.Pod) e status, err := pc.provider.GetPodStatus(ctx, pod.Namespace, pod.Name) if err != nil { - span.SetStatus(ocstatus.FromError(err)) + span.SetStatus(err) return pkgerrors.Wrap(err, "error retreiving pod status") } @@ -238,7 +237,7 @@ func (pc *PodController) updatePodStatus(ctx context.Context, pod *corev1.Pod) e } if _, err := pc.client.Pods(pod.Namespace).UpdateStatus(pod); err != nil { - span.SetStatus(ocstatus.FromError(err)) + span.SetStatus(err) return pkgerrors.Wrap(err, "error while updating pod status in kubernetes") } @@ -265,7 +264,7 @@ func (pc *PodController) podStatusHandler(ctx context.Context, key string) (retE ctx = span.WithField(ctx, "key", key) log.G(ctx).Debug("processing pod status update") defer func() { - span.SetStatus(ocstatus.FromError(retErr)) + span.SetStatus(retErr) if retErr != nil { log.G(ctx).WithError(retErr).Error("Error processing pod status update") } diff --git a/vkubelet/pod_test.go b/vkubelet/pod_test.go index 2396164ca..88cb642d5 100644 --- a/vkubelet/pod_test.go +++ b/vkubelet/pod_test.go @@ -5,8 +5,7 @@ import ( "path" "testing" - "github.com/cpuguy83/strongerrors" - pkgerrors "github.com/pkg/errors" + "github.com/virtual-kubelet/virtual-kubelet/errdefs" testutil "github.com/virtual-kubelet/virtual-kubelet/test/util" "gotest.tools/assert" is "gotest.tools/assert/cmp" @@ -37,7 +36,7 @@ func (m *mockProvider) UpdatePod(ctx context.Context, pod *corev1.Pod) error { func (m *mockProvider) GetPod(ctx context.Context, namespace, name string) (*corev1.Pod, error) { p := m.pods[path.Join(namespace, name)] if p == nil { - return nil, strongerrors.NotFound(pkgerrors.New("not found")) + return nil, errdefs.NotFound("not found") } return p, nil } @@ -45,7 +44,7 @@ func (m *mockProvider) GetPod(ctx context.Context, namespace, name string) (*cor func (m *mockProvider) GetPodStatus(ctx context.Context, namespace, name string) (*corev1.PodStatus, error) { p := m.pods[path.Join(namespace, name)] if p == nil { - return nil, strongerrors.NotFound(pkgerrors.New("not found")) + return nil, errdefs.NotFound("not found") } return &p.Status, nil } diff --git a/vkubelet/podcontroller.go b/vkubelet/podcontroller.go index 262f9382f..503c78f8b 100644 --- a/vkubelet/podcontroller.go +++ b/vkubelet/podcontroller.go @@ -22,9 +22,8 @@ import ( "sync" "time" - "github.com/cpuguy83/strongerrors" - "github.com/cpuguy83/strongerrors/status/ocstatus" pkgerrors "github.com/pkg/errors" + "github.com/virtual-kubelet/virtual-kubelet/errdefs" "github.com/virtual-kubelet/virtual-kubelet/log" "github.com/virtual-kubelet/virtual-kubelet/manager" "github.com/virtual-kubelet/virtual-kubelet/trace" @@ -41,6 +40,10 @@ import ( // PodLifecycleHandler defines the interface used by the PodController to react // to new and changed pods scheduled to the node that is being managed. +// +// Errors produced by these methods should implement an interface from +// github.com/virtual-kubelet/virtual-kubelet/errdefs package in order for the +// core logic to be able to understand the type of failure. type PodLifecycleHandler interface { // CreatePod takes a Kubernetes Pod and deploys it within the provider. CreatePod(ctx context.Context, pod *corev1.Pod) error @@ -113,13 +116,13 @@ type PodControllerConfig struct { func NewPodController(cfg PodControllerConfig) (*PodController, error) { if cfg.PodClient == nil { - return nil, strongerrors.InvalidArgument(pkgerrors.New("must set core client")) + return nil, errdefs.InvalidInput("must set core client") } if cfg.EventRecorder == nil { - return nil, strongerrors.InvalidArgument(pkgerrors.New("must set event recorder")) + return nil, errdefs.InvalidInput("must set event recorder") } if cfg.PodInformer == nil { - return nil, strongerrors.InvalidArgument(pkgerrors.New("must set informer")) + return nil, errdefs.InvalidInput("must set informer") } return &PodController{ @@ -257,14 +260,14 @@ func (pc *PodController) syncHandler(ctx context.Context, key string) error { // We've failed to fetch the pod from the lister, but the error is not a 404. // Hence, we add the key back to the work queue so we can retry processing it later. err := pkgerrors.Wrapf(err, "failed to fetch pod with key %q from lister", key) - span.SetStatus(ocstatus.FromError(err)) + span.SetStatus(err) return err } // At this point we know the Pod resource doesn't exist, which most probably means it was deleted. // Hence, we must delete it from the provider if it still exists there. if err := pc.deletePod(ctx, namespace, name); err != nil { err := pkgerrors.Wrapf(err, "failed to delete pod %q in the provider", loggablePodNameFromCoordinates(namespace, name)) - span.SetStatus(ocstatus.FromError(err)) + span.SetStatus(err) return err } return nil @@ -286,7 +289,7 @@ func (pc *PodController) syncPodInProvider(ctx context.Context, pod *corev1.Pod) if pod.DeletionTimestamp != nil { if err := pc.deletePod(ctx, pod.Namespace, pod.Name); err != nil { err := pkgerrors.Wrapf(err, "failed to delete pod %q in the provider", loggablePodName(pod)) - span.SetStatus(ocstatus.FromError(err)) + span.SetStatus(err) return err } return nil @@ -301,7 +304,7 @@ func (pc *PodController) syncPodInProvider(ctx context.Context, pod *corev1.Pod) // Create or update the pod in the provider. if err := pc.createOrUpdatePod(ctx, pod); err != nil { err := pkgerrors.Wrapf(err, "failed to sync pod %q in the provider", loggablePodName(pod)) - span.SetStatus(ocstatus.FromError(err)) + span.SetStatus(err) return err } return nil @@ -316,7 +319,7 @@ func (pc *PodController) deleteDanglingPods(ctx context.Context, threadiness int pps, err := pc.provider.GetPods(ctx) if err != nil { err := pkgerrors.Wrap(err, "failed to fetch the list of pods from the provider") - span.SetStatus(ocstatus.FromError(err)) + span.SetStatus(err) log.G(ctx).Error(err) return } @@ -335,7 +338,7 @@ func (pc *PodController) deleteDanglingPods(ctx context.Context, threadiness int } // For some reason we couldn't fetch the pod from the lister, so we propagate the error. err := pkgerrors.Wrap(err, "failed to fetch pod from the lister") - span.SetStatus(ocstatus.FromError(err)) + span.SetStatus(err) log.G(ctx).Error(err) return } @@ -363,7 +366,7 @@ func (pc *PodController) deleteDanglingPods(ctx context.Context, threadiness int ctx = addPodAttributes(ctx, span, pod) // Actually delete the pod. if err := pc.deletePod(ctx, pod.Namespace, pod.Name); err != nil { - span.SetStatus(ocstatus.FromError(err)) + span.SetStatus(err) log.G(ctx).Errorf("failed to delete pod %q in provider", loggablePodName(pod)) } else { log.G(ctx).Infof("deleted leaked pod %q in provider", loggablePodName(pod)) diff --git a/vkubelet/queue.go b/vkubelet/queue.go index 790f07a50..854fe4d39 100644 --- a/vkubelet/queue.go +++ b/vkubelet/queue.go @@ -5,7 +5,6 @@ import ( "strconv" "time" - "github.com/cpuguy83/strongerrors/status/ocstatus" pkgerrors "github.com/pkg/errors" "github.com/virtual-kubelet/virtual-kubelet/log" "github.com/virtual-kubelet/virtual-kubelet/trace" @@ -71,7 +70,7 @@ func handleQueueItem(ctx context.Context, q workqueue.RateLimitingInterface, han if err != nil { // We've actually hit an error, so we set the span's status based on the error. - span.SetStatus(ocstatus.FromError(err)) + span.SetStatus(err) log.G(ctx).Error(err) return true }