diff --git a/bootcfg/rpc/errors.go b/bootcfg/rpc/errors.go new file mode 100644 index 00000000..e64f4c96 --- /dev/null +++ b/bootcfg/rpc/errors.go @@ -0,0 +1,30 @@ +package rpc + +import ( + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + + "github.com/coreos/coreos-baremetal/bootcfg/server" +) + +var ( + // work around go vet false positive https://github.com/grpc/grpc-go/issues/90 + grpcErrorf = grpc.Errorf + errNoMatchingGroup = grpcErrorf(codes.NotFound, "bootcfg: No matching Group") + errNoMatchingProfile = grpcErrorf(codes.NotFound, "bootcfg: No matching Profile") +) + +// grpcError transforms an error into a gRPC errors with canonical error codes. +func grpcError(err error) error { + if err == nil { + return err + } + switch err { + case server.ErrNoMatchingGroup: + return errNoMatchingGroup + case server.ErrNoMatchingProfile: + return errNoMatchingProfile + default: + return grpcErrorf(codes.Unknown, err.Error()) + } +} diff --git a/bootcfg/rpc/errors_test.go b/bootcfg/rpc/errors_test.go new file mode 100644 index 00000000..974c94dd --- /dev/null +++ b/bootcfg/rpc/errors_test.go @@ -0,0 +1,27 @@ +package rpc + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/assert" + "google.golang.org/grpc/codes" + + "github.com/coreos/coreos-baremetal/bootcfg/server" +) + +func TestGRPCError(t *testing.T) { + cases := []struct { + input error + output error + }{ + {nil, nil}, + {server.ErrNoMatchingGroup, errNoMatchingGroup}, + {server.ErrNoMatchingProfile, errNoMatchingProfile}, + {errors.New("other error"), grpcErrorf(codes.Unknown, "other error")}, + } + for _, c := range cases { + err := grpcError(c.input) + assert.Equal(t, c.output, err) + } +} diff --git a/bootcfg/rpc/groups.go b/bootcfg/rpc/groups.go index 026fe0fb..a2be4df8 100644 --- a/bootcfg/rpc/groups.go +++ b/bootcfg/rpc/groups.go @@ -21,10 +21,10 @@ func newGroupServer(s server.Server) rpcpb.GroupsServer { func (s *groupServer) GroupGet(ctx context.Context, req *pb.GroupGetRequest) (*pb.GroupGetResponse, error) { group, err := s.srv.GroupGet(ctx, req) - return &pb.GroupGetResponse{Group: group}, err + return &pb.GroupGetResponse{Group: group}, grpcError(err) } func (s *groupServer) GroupList(ctx context.Context, req *pb.GroupListRequest) (*pb.GroupListResponse, error) { groups, err := s.srv.GroupList(ctx, req) - return &pb.GroupListResponse{Groups: groups}, err + return &pb.GroupListResponse{Groups: groups}, grpcError(err) } diff --git a/bootcfg/rpc/profiles.go b/bootcfg/rpc/profiles.go index 62dce471..05ee711b 100644 --- a/bootcfg/rpc/profiles.go +++ b/bootcfg/rpc/profiles.go @@ -22,15 +22,15 @@ func newProfileServer(s server.Server) rpcpb.ProfilesServer { func (s *profileServer) ProfilePut(ctx context.Context, req *pb.ProfilePutRequest) (*pb.ProfilePutResponse, error) { _, err := s.srv.ProfilePut(ctx, req) // TODO(dghubble): Decide on create/put and response(s). - return &pb.ProfilePutResponse{}, err + return &pb.ProfilePutResponse{}, grpcError(err) } func (s *profileServer) ProfileGet(ctx context.Context, req *pb.ProfileGetRequest) (*pb.ProfileGetResponse, error) { profile, err := s.srv.ProfileGet(ctx, req) - return &pb.ProfileGetResponse{Profile: profile}, err + return &pb.ProfileGetResponse{Profile: profile}, grpcError(err) } func (s *profileServer) ProfileList(ctx context.Context, req *pb.ProfileListRequest) (*pb.ProfileListResponse, error) { profiles, err := s.srv.ProfileList(ctx, req) - return &pb.ProfileListResponse{Profiles: profiles}, err + return &pb.ProfileListResponse{Profiles: profiles}, grpcError(err) } diff --git a/bootcfg/rpc/select.go b/bootcfg/rpc/select.go index 6d2c4915..fafc7e08 100644 --- a/bootcfg/rpc/select.go +++ b/bootcfg/rpc/select.go @@ -22,10 +22,10 @@ func newSelectServer(s server.Server) rpcpb.SelectServer { func (s *selectServer) SelectGroup(ctx context.Context, req *pb.SelectGroupRequest) (*pb.SelectGroupResponse, error) { group, err := s.srv.SelectGroup(ctx, req) - return &pb.SelectGroupResponse{Group: group}, err + return &pb.SelectGroupResponse{Group: group}, grpcError(err) } func (s *selectServer) SelectProfile(ctx context.Context, req *pb.SelectProfileRequest) (*pb.SelectProfileResponse, error) { profile, err := s.srv.SelectProfile(ctx, req) - return &pb.SelectProfileResponse{Profile: profile}, err + return &pb.SelectProfileResponse{Profile: profile}, grpcError(err) } diff --git a/bootcfg/server/server.go b/bootcfg/server/server.go index d8d19032..1c937018 100644 --- a/bootcfg/server/server.go +++ b/bootcfg/server/server.go @@ -11,9 +11,10 @@ import ( "github.com/coreos/coreos-baremetal/bootcfg/storage/storagepb" ) +// Possible service errors var ( - errNoMatchingGroup = errors.New("bootcfg: No matching Group") - errNoProfileFound = errors.New("bootcfg: No Profile found") + ErrNoMatchingGroup = errors.New("bootcfg: No matching Group") + ErrNoMatchingProfile = errors.New("bootcfg: No matching Profile") ) // Server defines a bootcfg server lib. @@ -115,7 +116,7 @@ func (s *server) SelectGroup(ctx context.Context, req *pb.SelectGroupRequest) (* return group, nil } } - return nil, errNoMatchingGroup + return nil, ErrNoMatchingGroup } func (s *server) SelectProfile(ctx context.Context, req *pb.SelectProfileRequest) (*storagepb.Profile, error) { @@ -126,9 +127,9 @@ func (s *server) SelectProfile(ctx context.Context, req *pb.SelectProfileRequest if err == nil { return profile, nil } - return nil, errNoProfileFound + return nil, ErrNoMatchingProfile } - return nil, errNoMatchingGroup + return nil, ErrNoMatchingGroup } // IgnitionGet gets an Ignition Config template by name. diff --git a/bootcfg/server/server_test.go b/bootcfg/server/server_test.go index d1aa5854..c25aa2e8 100644 --- a/bootcfg/server/server_test.go +++ b/bootcfg/server/server_test.go @@ -23,9 +23,9 @@ func TestSelectGroup(t *testing.T) { expectedErr error }{ {store, map[string]string{"uuid": "a1b2c3d4"}, fake.Group, nil}, - {store, nil, nil, errNoMatchingGroup}, + {store, nil, nil, ErrNoMatchingGroup}, // no groups in the store - {&fake.EmptyStore{}, map[string]string{"a": "b"}, nil, errNoMatchingGroup}, + {&fake.EmptyStore{}, map[string]string{"a": "b"}, nil, ErrNoMatchingGroup}, } for _, c := range cases { srv := NewServer(&Config{c.store})