Skip to content

Commit 334de29

Browse files
committed
Split gRPC and HTTP error utility into seperate packages
By having seperate packages, users can consume base package without pulling gRPC or HTTP as a dependency if not required. Signed-off-by: Austin Vazquez <macedonv@amazon.com>
1 parent 98ae5ec commit 334de29

File tree

6 files changed

+319
-121
lines changed

6 files changed

+319
-121
lines changed

errors.go

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,11 @@
2121
//
2222
// To detect an error class, use the IsXXX functions to tell whether an error
2323
// is of a certain type.
24-
//
25-
// The functions ToGRPC and FromGRPC can be used to map server-side and
26-
// client-side errors to the correct types.
2724
package errdefs
2825

2926
import (
3027
"context"
3128
"errors"
32-
"fmt"
3329
)
3430

3531
// Definitions of common error types used throughout containerd. All containerd
@@ -73,18 +69,6 @@ func (errUnknown) Error() string { return "unknown" }
7369

7470
func (errUnknown) Unknown() {}
7571

76-
type errUnexpectedStatus struct {
77-
status int
78-
}
79-
80-
const unexpectedStatusPrefix = "unexpected status "
81-
82-
func (e errUnexpectedStatus) Error() string {
83-
return fmt.Sprintf("%s%d", unexpectedStatusPrefix, e.status)
84-
}
85-
86-
func (errUnexpectedStatus) Unknown() {}
87-
8872
// unknown maps to Moby's "ErrUnknown"
8973
type unknown interface {
9074
Unknown()

grpc.go renamed to grpc/grpc.go

Lines changed: 49 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,12 @@
1414
limitations under the License.
1515
*/
1616

17-
package errdefs
17+
// Package grpc provides utility functions for translating errors to
18+
// and from a gRPC context.
19+
//
20+
// The functions ToGRPC and ToNative can be used to map server-side and
21+
// client-side errors to the correct types.
22+
package grpc
1823

1924
import (
2025
"context"
@@ -24,6 +29,9 @@ import (
2429

2530
"google.golang.org/grpc/codes"
2631
"google.golang.org/grpc/status"
32+
33+
"github.com/containerd/errdefs"
34+
"github.com/containerd/errdefs/internal/cause"
2735
)
2836

2937
// ToGRPC will attempt to map the backend containerd error into a grpc error,
@@ -45,37 +53,37 @@ func ToGRPC(err error) error {
4553
}
4654

4755
switch {
48-
case IsInvalidArgument(err):
56+
case errdefs.IsInvalidArgument(err):
4957
return status.Error(codes.InvalidArgument, err.Error())
50-
case IsNotFound(err):
58+
case errdefs.IsNotFound(err):
5159
return status.Error(codes.NotFound, err.Error())
52-
case IsAlreadyExists(err):
60+
case errdefs.IsAlreadyExists(err):
5361
return status.Error(codes.AlreadyExists, err.Error())
54-
case IsFailedPrecondition(err) || IsConflict(err) || IsNotModified(err):
62+
case errdefs.IsFailedPrecondition(err) || errdefs.IsConflict(err) || errdefs.IsNotModified(err):
5563
return status.Error(codes.FailedPrecondition, err.Error())
56-
case IsUnavailable(err):
64+
case errdefs.IsUnavailable(err):
5765
return status.Error(codes.Unavailable, err.Error())
58-
case IsNotImplemented(err):
66+
case errdefs.IsNotImplemented(err):
5967
return status.Error(codes.Unimplemented, err.Error())
60-
case IsCanceled(err):
68+
case errdefs.IsCanceled(err):
6169
return status.Error(codes.Canceled, err.Error())
62-
case IsDeadlineExceeded(err):
70+
case errdefs.IsDeadlineExceeded(err):
6371
return status.Error(codes.DeadlineExceeded, err.Error())
64-
case IsUnauthorized(err):
72+
case errdefs.IsUnauthorized(err):
6573
return status.Error(codes.Unauthenticated, err.Error())
66-
case IsPermissionDenied(err):
74+
case errdefs.IsPermissionDenied(err):
6775
return status.Error(codes.PermissionDenied, err.Error())
68-
case IsInternal(err):
76+
case errdefs.IsInternal(err):
6977
return status.Error(codes.Internal, err.Error())
70-
case IsDataLoss(err):
78+
case errdefs.IsDataLoss(err):
7179
return status.Error(codes.DataLoss, err.Error())
72-
case IsAborted(err):
80+
case errdefs.IsAborted(err):
7381
return status.Error(codes.Aborted, err.Error())
74-
case IsOutOfRange(err):
82+
case errdefs.IsOutOfRange(err):
7583
return status.Error(codes.OutOfRange, err.Error())
76-
case IsResourceExhausted(err):
84+
case errdefs.IsResourceExhausted(err):
7785
return status.Error(codes.ResourceExhausted, err.Error())
78-
case IsUnknown(err):
86+
case errdefs.IsUnknown(err):
7987
return status.Error(codes.Unknown, err.Error())
8088
}
8189

@@ -85,13 +93,13 @@ func ToGRPC(err error) error {
8593
// ToGRPCf maps the error to grpc error codes, assembling the formatting string
8694
// and combining it with the target error string.
8795
//
88-
// This is equivalent to errdefs.ToGRPC(fmt.Errorf("%s: %w", fmt.Sprintf(format, args...), err))
96+
// This is equivalent to grpc.ToGRPC(fmt.Errorf("%s: %w", fmt.Sprintf(format, args...), err))
8997
func ToGRPCf(err error, format string, args ...interface{}) error {
9098
return ToGRPC(fmt.Errorf("%s: %w", fmt.Sprintf(format, args...), err))
9199
}
92100

93-
// FromGRPC returns the underlying error from a grpc service based on the grpc error code
94-
func FromGRPC(err error) error {
101+
// ToNative returns the underlying error from a grpc service based on the grpc error code
102+
func ToNative(err error) error {
95103
if err == nil {
96104
return nil
97105
}
@@ -102,49 +110,49 @@ func FromGRPC(err error) error {
102110

103111
switch code(err) {
104112
case codes.InvalidArgument:
105-
cls = ErrInvalidArgument
113+
cls = errdefs.ErrInvalidArgument
106114
case codes.AlreadyExists:
107-
cls = ErrAlreadyExists
115+
cls = errdefs.ErrAlreadyExists
108116
case codes.NotFound:
109-
cls = ErrNotFound
117+
cls = errdefs.ErrNotFound
110118
case codes.Unavailable:
111-
cls = ErrUnavailable
119+
cls = errdefs.ErrUnavailable
112120
case codes.FailedPrecondition:
113-
if desc == ErrConflict.Error() || strings.HasSuffix(desc, ": "+ErrConflict.Error()) {
114-
cls = ErrConflict
115-
} else if desc == ErrNotModified.Error() || strings.HasSuffix(desc, ": "+ErrNotModified.Error()) {
116-
cls = ErrNotModified
121+
if desc == errdefs.ErrConflict.Error() || strings.HasSuffix(desc, ": "+errdefs.ErrConflict.Error()) {
122+
cls = errdefs.ErrConflict
123+
} else if desc == errdefs.ErrNotModified.Error() || strings.HasSuffix(desc, ": "+errdefs.ErrNotModified.Error()) {
124+
cls = errdefs.ErrNotModified
117125
} else {
118-
cls = ErrFailedPrecondition
126+
cls = errdefs.ErrFailedPrecondition
119127
}
120128
case codes.Unimplemented:
121-
cls = ErrNotImplemented
129+
cls = errdefs.ErrNotImplemented
122130
case codes.Canceled:
123131
cls = context.Canceled
124132
case codes.DeadlineExceeded:
125133
cls = context.DeadlineExceeded
126134
case codes.Aborted:
127-
cls = ErrAborted
135+
cls = errdefs.ErrAborted
128136
case codes.Unauthenticated:
129-
cls = ErrUnauthenticated
137+
cls = errdefs.ErrUnauthenticated
130138
case codes.PermissionDenied:
131-
cls = ErrPermissionDenied
139+
cls = errdefs.ErrPermissionDenied
132140
case codes.Internal:
133-
cls = ErrInternal
141+
cls = errdefs.ErrInternal
134142
case codes.DataLoss:
135-
cls = ErrDataLoss
143+
cls = errdefs.ErrDataLoss
136144
case codes.OutOfRange:
137-
cls = ErrOutOfRange
145+
cls = errdefs.ErrOutOfRange
138146
case codes.ResourceExhausted:
139-
cls = ErrResourceExhausted
147+
cls = errdefs.ErrResourceExhausted
140148
default:
141-
if idx := strings.LastIndex(desc, unexpectedStatusPrefix); idx > 0 {
142-
if status, err := strconv.Atoi(desc[idx+len(unexpectedStatusPrefix):]); err == nil && status >= 200 && status < 600 {
143-
cls = errUnexpectedStatus{status}
149+
if idx := strings.LastIndex(desc, cause.UnexpectedStatusPrefix); idx > 0 {
150+
if status, err := strconv.Atoi(desc[idx+len(cause.UnexpectedStatusPrefix):]); err == nil && status >= 200 && status < 600 {
151+
cls = cause.ErrUnexpectedStatus{Status: status}
144152
}
145153
}
146154
if cls == nil {
147-
cls = ErrUnknown
155+
cls = errdefs.ErrUnknown
148156
}
149157
}
150158

grpc_test.go renamed to grpc/grpc_test.go

Lines changed: 73 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
limitations under the License.
1515
*/
1616

17-
package errdefs
17+
package grpc
1818

1919
import (
2020
"context"
@@ -24,8 +24,20 @@ import (
2424

2525
"google.golang.org/grpc/codes"
2626
"google.golang.org/grpc/status"
27+
28+
"github.com/containerd/errdefs"
29+
"github.com/containerd/errdefs/internal/cause"
2730
)
2831

32+
func TestGRPCNilInput(t *testing.T) {
33+
if err := ToGRPC(nil); err != nil {
34+
t.Fatalf("Expected nil error, got %v", err)
35+
}
36+
if err := ToNative(nil); err != nil {
37+
t.Fatalf("Expected nil error, got %v", err)
38+
}
39+
}
40+
2941
func TestGRPCRoundTrip(t *testing.T) {
3042
errShouldLeaveAlone := errors.New("unknown to package")
3143

@@ -35,28 +47,72 @@ func TestGRPCRoundTrip(t *testing.T) {
3547
str string
3648
}{
3749
{
38-
input: ErrAlreadyExists,
39-
cause: ErrAlreadyExists,
50+
input: errdefs.ErrInvalidArgument,
51+
cause: errdefs.ErrInvalidArgument,
52+
},
53+
{
54+
input: errdefs.ErrAlreadyExists,
55+
cause: errdefs.ErrAlreadyExists,
56+
},
57+
{
58+
input: errdefs.ErrNotFound,
59+
cause: errdefs.ErrNotFound,
60+
},
61+
{
62+
input: errdefs.ErrUnavailable,
63+
cause: errdefs.ErrUnavailable,
64+
},
65+
{
66+
input: errdefs.ErrNotImplemented,
67+
cause: errdefs.ErrNotImplemented,
68+
},
69+
{
70+
input: errdefs.ErrUnauthenticated,
71+
cause: errdefs.ErrUnauthenticated,
72+
},
73+
{
74+
input: errdefs.ErrPermissionDenied,
75+
cause: errdefs.ErrPermissionDenied,
76+
},
77+
{
78+
input: errdefs.ErrInternal,
79+
cause: errdefs.ErrInternal,
80+
},
81+
{
82+
input: errdefs.ErrDataLoss,
83+
cause: errdefs.ErrDataLoss,
4084
},
4185
{
42-
input: ErrNotFound,
43-
cause: ErrNotFound,
86+
input: errdefs.ErrAborted,
87+
cause: errdefs.ErrAborted,
88+
},
89+
{
90+
input: errdefs.ErrOutOfRange,
91+
cause: errdefs.ErrOutOfRange,
92+
},
93+
{
94+
input: errdefs.ErrResourceExhausted,
95+
cause: errdefs.ErrResourceExhausted,
96+
},
97+
{
98+
input: errdefs.ErrUnknown,
99+
cause: errdefs.ErrUnknown,
44100
},
45101
//nolint:dupword
46102
{
47-
input: fmt.Errorf("test test test: %w", ErrFailedPrecondition),
48-
cause: ErrFailedPrecondition,
103+
input: fmt.Errorf("test test test: %w", errdefs.ErrFailedPrecondition),
104+
cause: errdefs.ErrFailedPrecondition,
49105
str: "test test test: failed precondition",
50106
},
51107
{
52108
input: status.Errorf(codes.Unavailable, "should be not available"),
53-
cause: ErrUnavailable,
109+
cause: errdefs.ErrUnavailable,
54110
str: "should be not available: unavailable",
55111
},
56112
{
57113
input: errShouldLeaveAlone,
58-
cause: ErrUnknown,
59-
str: errShouldLeaveAlone.Error() + ": " + ErrUnknown.Error(),
114+
cause: errdefs.ErrUnknown,
115+
str: errShouldLeaveAlone.Error() + ": " + errdefs.ErrUnknown.Error(),
60116
},
61117
{
62118
input: context.Canceled,
@@ -79,26 +135,26 @@ func TestGRPCRoundTrip(t *testing.T) {
79135
str: "this is a test deadline exceeded: context deadline exceeded",
80136
},
81137
{
82-
input: fmt.Errorf("something conflicted: %w", ErrConflict),
83-
cause: ErrConflict,
138+
input: fmt.Errorf("something conflicted: %w", errdefs.ErrConflict),
139+
cause: errdefs.ErrConflict,
84140
str: "something conflicted: conflict",
85141
},
86142
{
87-
input: fmt.Errorf("everything is the same: %w", ErrNotModified),
88-
cause: ErrNotModified,
143+
input: fmt.Errorf("everything is the same: %w", errdefs.ErrNotModified),
144+
cause: errdefs.ErrNotModified,
89145
str: "everything is the same: not modified",
90146
},
91147
{
92-
input: fmt.Errorf("odd HTTP response: %w", FromHTTP(418)),
93-
cause: errUnexpectedStatus{418},
148+
input: fmt.Errorf("odd HTTP response: %w", errhttp.ToNative(418)),
149+
cause: cause.ErrUnexpectedStatus{Status: 418},
94150
str: "odd HTTP response: unexpected status 418",
95151
},
96152
} {
97153
t.Run(testcase.input.Error(), func(t *testing.T) {
98154
t.Logf("input: %v", testcase.input)
99155
gerr := ToGRPC(testcase.input)
100156
t.Logf("grpc: %v", gerr)
101-
ferr := FromGRPC(gerr)
157+
ferr := ToNative(gerr)
102158
t.Logf("recovered: %v", ferr)
103159

104160
if !errors.Is(ferr, testcase.cause) {
@@ -114,5 +170,4 @@ func TestGRPCRoundTrip(t *testing.T) {
114170
}
115171
})
116172
}
117-
118173
}

0 commit comments

Comments
 (0)