*: improve error handling

* objectstorage: remove `types` package and move `ErrNotExist` in base package
* objectstorage: Implement .Is and add helper `IsErrNotExist` for `ErrNotExist`
* util: Rename `ErrNotFound` to `ErrNotExist`
* util: Add `IsErr*` helpers and use them in place of `errors.Is()`
* datamanager: add `ErrNoDataStatus` to report when there's not data status in ost
* runservice/common: remove `ErrNotExist` and use errors in util package
This commit is contained in:
Simone Gotti 2019-11-06 13:29:42 +01:00
parent 89eb87a827
commit 72f279c4c3
28 changed files with 155 additions and 126 deletions

View File

@ -28,11 +28,15 @@ import (
"agola.io/agola/internal/objectstorage" "agola.io/agola/internal/objectstorage"
"agola.io/agola/internal/sequence" "agola.io/agola/internal/sequence"
"agola.io/agola/internal/util"
uuid "github.com/satori/go.uuid" uuid "github.com/satori/go.uuid"
errors "golang.org/x/xerrors" errors "golang.org/x/xerrors"
) )
// ErrNoDataStatus represent when there's no data status files in the ost
var ErrNoDataStatus = errors.New("no data status files")
const ( const (
DefaultMaxDataFileSize = 10 * 1024 * 1024 DefaultMaxDataFileSize = 10 * 1024 * 1024
dataStatusToKeep = 3 dataStatusToKeep = 3
@ -165,7 +169,7 @@ func (d *DataManager) writeDataSnapshot(ctx context.Context, wals []*WalData) er
} }
curDataStatus, err := d.GetLastDataStatus() curDataStatus, err := d.GetLastDataStatus()
if err != nil && err != objectstorage.ErrNotExist { if err != nil && !errors.Is(err, ErrNoDataStatus) {
return err return err
} }
@ -321,10 +325,10 @@ func (d *DataManager) writeDataType(ctx context.Context, wi walIndex, dataType s
if actionGroup.DataStatusFile != nil { if actionGroup.DataStatusFile != nil {
// TODO(sgotti) instead of reading all entries in memory decode it's contents one by one when needed // TODO(sgotti) instead of reading all entries in memory decode it's contents one by one when needed
oldDataf, err := d.ost.ReadObject(d.DataFilePath(dataType, actionGroup.DataStatusFile.ID)) oldDataf, err := d.ost.ReadObject(d.DataFilePath(dataType, actionGroup.DataStatusFile.ID))
if err != nil && err != objectstorage.ErrNotExist { if err != nil && !objectstorage.IsNotExist(err) {
return nil, err return nil, err
} }
if err != objectstorage.ErrNotExist { if !objectstorage.IsNotExist(err) {
dec := json.NewDecoder(oldDataf) dec := json.NewDecoder(oldDataf)
for { for {
var de *DataEntry var de *DataEntry
@ -481,7 +485,7 @@ func (d *DataManager) Read(dataType, id string) (io.Reader, error) {
var matchingDataFileID string var matchingDataFileID string
// get the matching data file for the action entry ID // get the matching data file for the action entry ID
if len(curFiles[dataType]) == 0 { if len(curFiles[dataType]) == 0 {
return nil, objectstorage.ErrNotExist return nil, util.NewErrNotExist(errors.Errorf("datatype %q doesn't exists", dataType))
} }
matchingDataFileID = curFiles[dataType][0].ID matchingDataFileID = curFiles[dataType][0].ID
@ -507,7 +511,7 @@ func (d *DataManager) Read(dataType, id string) (io.Reader, error) {
pos, ok := dataFileIndex.Index[id] pos, ok := dataFileIndex.Index[id]
if !ok { if !ok {
return nil, objectstorage.ErrNotExist return nil, util.NewErrNotExist(errors.Errorf("datatype %q, id %q doesn't exists", dataType, id))
} }
dataf, err := d.ost.ReadObject(d.DataFilePath(dataType, matchingDataFileID)) dataf, err := d.ost.ReadObject(d.DataFilePath(dataType, matchingDataFileID))
@ -560,7 +564,7 @@ func (d *DataManager) GetFirstDataStatusSequences(n int) ([]*sequence.Sequence,
} }
if len(dataStatusSequences) == 0 { if len(dataStatusSequences) == 0 {
return nil, objectstorage.ErrNotExist return nil, ErrNoDataStatus
} }
return dataStatusSequences, nil return dataStatusSequences, nil
@ -601,7 +605,7 @@ func (d *DataManager) GetLastDataStatusSequences(n int) ([]*sequence.Sequence, e
}) })
if len(dataStatusSequences) == 0 { if len(dataStatusSequences) == 0 {
return nil, objectstorage.ErrNotExist return nil, ErrNoDataStatus
} }
return dataStatusSequences, nil return dataStatusSequences, nil
@ -862,7 +866,7 @@ func (d *DataManager) cleanOldCheckpoints(ctx context.Context, dataStatusSequenc
if _, ok := dataStatusPathsMap[object.Path]; !ok { if _, ok := dataStatusPathsMap[object.Path]; !ok {
d.log.Infof("removing %q", object.Path) d.log.Infof("removing %q", object.Path)
if err := d.ost.DeleteObject(object.Path); err != nil { if err := d.ost.DeleteObject(object.Path); err != nil {
if err != objectstorage.ErrNotExist { if !objectstorage.IsNotExist(err) {
return err return err
} }
} }
@ -930,7 +934,7 @@ func (d *DataManager) cleanOldCheckpoints(ctx context.Context, dataStatusSequenc
if _, ok := files[pne]; !ok { if _, ok := files[pne]; !ok {
d.log.Infof("removing %q", object.Path) d.log.Infof("removing %q", object.Path)
if err := d.ost.DeleteObject(object.Path); err != nil { if err := d.ost.DeleteObject(object.Path); err != nil {
if err != objectstorage.ErrNotExist { if !objectstorage.IsNotExist(err) {
return err return err
} }
} }

View File

@ -32,11 +32,12 @@ import (
slog "agola.io/agola/internal/log" slog "agola.io/agola/internal/log"
"agola.io/agola/internal/objectstorage" "agola.io/agola/internal/objectstorage"
"agola.io/agola/internal/testutil" "agola.io/agola/internal/testutil"
"github.com/google/go-cmp/cmp" "agola.io/agola/internal/util"
errors "golang.org/x/xerrors"
"github.com/google/go-cmp/cmp"
"go.uber.org/zap" "go.uber.org/zap"
"go.uber.org/zap/zapcore" "go.uber.org/zap/zapcore"
errors "golang.org/x/xerrors"
) )
var level = zap.NewAtomicLevelAt(zapcore.InfoLevel) var level = zap.NewAtomicLevelAt(zapcore.InfoLevel)
@ -558,8 +559,8 @@ func TestReadObject(t *testing.T) {
// should not exists // should not exists
_, _, err = dm.ReadObject("datatype01", "object1", nil) _, _, err = dm.ReadObject("datatype01", "object1", nil)
if err != objectstorage.ErrNotExist { if !util.IsNotExist(err) {
t.Fatalf("expected err %v, got: %v", objectstorage.ErrNotExist, err) t.Fatalf("expected err %v, got: %v", &util.ErrNotExist{}, err)
} }
// should exist // should exist
_, _, err = dm.ReadObject("datatype01", "object19", nil) _, _, err = dm.ReadObject("datatype01", "object19", nil)
@ -582,8 +583,8 @@ func TestReadObject(t *testing.T) {
// should not exists // should not exists
_, _, err = dm.ReadObject("datatype01", "object1", nil) _, _, err = dm.ReadObject("datatype01", "object1", nil)
if err != objectstorage.ErrNotExist { if !util.IsNotExist(err) {
t.Fatalf("expected err %v, got: %v", objectstorage.ErrNotExist, err) t.Fatalf("expected err %v, got: %v", &util.ErrNotExist{}, err)
} }
// should exist // should exist
_, _, err = dm.ReadObject("datatype01", "object19", nil) _, _, err = dm.ReadObject("datatype01", "object19", nil)

View File

@ -28,6 +28,7 @@ import (
"agola.io/agola/internal/etcd" "agola.io/agola/internal/etcd"
"agola.io/agola/internal/objectstorage" "agola.io/agola/internal/objectstorage"
"agola.io/agola/internal/sequence" "agola.io/agola/internal/sequence"
"agola.io/agola/internal/util"
uuid "github.com/satori/go.uuid" uuid "github.com/satori/go.uuid"
etcdclientv3 "go.etcd.io/etcd/clientv3" etcdclientv3 "go.etcd.io/etcd/clientv3"
@ -123,7 +124,7 @@ func (d *DataManager) ReadObject(dataType, id string, cgNames []string) (io.Read
} }
} }
} }
return nil, nil, errors.Errorf("no datatype %q, id %q in wal %s", dataType, id, walseq) return nil, nil, util.NewErrNotExist(errors.Errorf("no datatype %q, id %q in wal %s", dataType, id, walseq))
} }
f, err := d.Read(dataType, id) f, err := d.Read(dataType, id)
@ -132,7 +133,7 @@ func (d *DataManager) ReadObject(dataType, id string, cgNames []string) (io.Read
func (d *DataManager) HasOSTWal(walseq string) (bool, error) { func (d *DataManager) HasOSTWal(walseq string) (bool, error) {
_, err := d.ost.Stat(d.storageWalStatusFile(walseq) + ".committed") _, err := d.ost.Stat(d.storageWalStatusFile(walseq) + ".committed")
if err == objectstorage.ErrNotExist { if objectstorage.IsNotExist(err) {
return false, nil return false, nil
} }
if err != nil { if err != nil {
@ -909,7 +910,7 @@ func (d *DataManager) storageWalCleaner(ctx context.Context) error {
walStatusFilePath := d.storageWalDataFile(header.WalDataFileID) walStatusFilePath := d.storageWalDataFile(header.WalDataFileID)
d.log.Infof("removing %q", walStatusFilePath) d.log.Infof("removing %q", walStatusFilePath)
if err := d.ost.DeleteObject(walStatusFilePath); err != nil { if err := d.ost.DeleteObject(walStatusFilePath); err != nil {
if err != objectstorage.ErrNotExist { if !objectstorage.IsNotExist(err) {
return err return err
} }
} }
@ -917,7 +918,7 @@ func (d *DataManager) storageWalCleaner(ctx context.Context) error {
// then remove wal status files // then remove wal status files
d.log.Infof("removing %q", object.Path) d.log.Infof("removing %q", object.Path)
if err := d.ost.DeleteObject(object.Path); err != nil { if err := d.ost.DeleteObject(object.Path); err != nil {
if err != objectstorage.ErrNotExist { if !objectstorage.IsNotExist(err) {
return err return err
} }
} }
@ -928,7 +929,7 @@ func (d *DataManager) storageWalCleaner(ctx context.Context) error {
if ext == ".checkpointed" { if ext == ".checkpointed" {
d.log.Infof("removing %q", object.Path) d.log.Infof("removing %q", object.Path)
if err := d.ost.DeleteObject(object.Path); err != nil { if err := d.ost.DeleteObject(object.Path); err != nil {
if err != objectstorage.ErrNotExist { if !objectstorage.IsNotExist(err) {
return err return err
} }
} }
@ -1149,7 +1150,7 @@ func (d *DataManager) InitEtcd(ctx context.Context, dataStatus *DataStatus) erro
firstWal = dataStatus.WalSequence firstWal = dataStatus.WalSequence
} else { } else {
dataStatus, err = d.GetLastDataStatus() dataStatus, err = d.GetLastDataStatus()
if err != nil && err != objectstorage.ErrNotExist { if err != nil && !errors.Is(err, ErrNoDataStatus) {
return err return err
} }
// set the first wal to import in etcd if there's a snapshot. In this way we'll // set the first wal to import in etcd if there's a snapshot. In this way we'll

View File

@ -34,7 +34,26 @@ type Storage interface {
List(prefix, startWith, delimiter string, doneCh <-chan struct{}) <-chan ObjectInfo List(prefix, startWith, delimiter string, doneCh <-chan struct{}) <-chan ObjectInfo
} }
var ErrNotExist = errors.New("does not exist") type ErrNotExist struct {
err error
}
func NewErrNotExist(err error) error {
return &ErrNotExist{err: err}
}
func (e *ErrNotExist) Error() string {
return e.err.Error()
}
func (*ErrNotExist) Is(err error) bool {
_, ok := err.(*ErrNotExist)
return ok
}
func IsNotExist(err error) bool {
return errors.Is(err, &ErrNotExist{})
}
type ReadSeekCloser interface { type ReadSeekCloser interface {
io.Reader io.Reader

View File

@ -65,7 +65,7 @@ func (s *PosixStorage) Stat(p string) (*ObjectInfo, error) {
fi, err := os.Stat(fspath) fi, err := os.Stat(fspath)
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
return nil, ErrNotExist return nil, NewErrNotExist(errors.Errorf("object %q doesn't exist", p))
} }
return nil, err return nil, err
} }
@ -81,7 +81,7 @@ func (s *PosixStorage) ReadObject(p string) (ReadSeekCloser, error) {
f, err := os.Open(fspath) f, err := os.Open(fspath)
if err != nil && os.IsNotExist(err) { if err != nil && os.IsNotExist(err) {
return nil, ErrNotExist return nil, NewErrNotExist(errors.Errorf("object %q doesn't exist", p))
} }
return f, err return f, err
} }
@ -114,7 +114,7 @@ func (s *PosixStorage) DeleteObject(p string) error {
if err := os.Remove(fspath); err != nil { if err := os.Remove(fspath); err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
return ErrNotExist return NewErrNotExist(errors.Errorf("object %q doesn't exist", p))
} }
return err return err
} }

View File

@ -239,7 +239,7 @@ func (s *PosixFlatStorage) Stat(p string) (*ObjectInfo, error) {
fi, err := os.Stat(fspath) fi, err := os.Stat(fspath)
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
return nil, ErrNotExist return nil, NewErrNotExist(errors.Errorf("object %q doesn't exist", p))
} }
return nil, err return nil, err
} }
@ -255,7 +255,7 @@ func (s *PosixFlatStorage) ReadObject(p string) (ReadSeekCloser, error) {
f, err := os.Open(fspath) f, err := os.Open(fspath)
if err != nil && os.IsNotExist(err) { if err != nil && os.IsNotExist(err) {
return nil, ErrNotExist return nil, NewErrNotExist(errors.Errorf("object %q doesn't exist", p))
} }
return f, err return f, err
} }
@ -288,7 +288,7 @@ func (s *PosixFlatStorage) DeleteObject(p string) error {
if err := os.Remove(fspath); err != nil { if err := os.Remove(fspath); err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
return ErrNotExist return NewErrNotExist(errors.Errorf("object %q doesn't exist", p))
} }
return err return err
} }

View File

@ -65,7 +65,7 @@ func (s *S3Storage) Stat(p string) (*ObjectInfo, error) {
if err != nil { if err != nil {
merr := minio.ToErrorResponse(err) merr := minio.ToErrorResponse(err)
if merr.StatusCode == http.StatusNotFound { if merr.StatusCode == http.StatusNotFound {
return nil, ErrNotExist return nil, NewErrNotExist(errors.Errorf("object %q doesn't exist", p))
} }
return nil, merr return nil, merr
} }
@ -77,7 +77,7 @@ func (s *S3Storage) ReadObject(filepath string) (ReadSeekCloser, error) {
if _, err := s.minioClient.StatObject(s.bucket, filepath, minio.StatObjectOptions{}); err != nil { if _, err := s.minioClient.StatObject(s.bucket, filepath, minio.StatObjectOptions{}); err != nil {
merr := minio.ToErrorResponse(err) merr := minio.ToErrorResponse(err)
if merr.StatusCode == http.StatusNotFound { if merr.StatusCode == http.StatusNotFound {
return nil, ErrNotExist return nil, NewErrNotExist(errors.Errorf("object %q doesn't exist", filepath))
} }
return nil, merr return nil, merr
} }

View File

@ -51,7 +51,7 @@ func (h *ActionHandler) GetOrgMembers(ctx context.Context, orgRef string) ([]*Or
return err return err
} }
if org == nil { if org == nil {
return util.NewErrNotFound(errors.Errorf("org %q doesn't exist", orgRef)) return util.NewErrNotExist(errors.Errorf("org %q doesn't exist", orgRef))
} }
orgUsers, err = h.readDB.GetOrgUsers(tx, org.ID) orgUsers, err = h.readDB.GetOrgUsers(tx, org.ID)

View File

@ -76,7 +76,7 @@ func (h *ActionHandler) GetProject(ctx context.Context, projectRef string) (*typ
} }
if project == nil { if project == nil {
return nil, util.NewErrNotFound(errors.Errorf("project %q doesn't exist", projectRef)) return nil, util.NewErrNotExist(errors.Errorf("project %q doesn't exist", projectRef))
} }
return project, nil return project, nil

View File

@ -41,7 +41,7 @@ func (h *ActionHandler) GetProjectGroup(ctx context.Context, projectGroupRef str
} }
if projectGroup == nil { if projectGroup == nil {
return nil, util.NewErrNotFound(errors.Errorf("project group %q doesn't exist", projectGroupRef)) return nil, util.NewErrNotExist(errors.Errorf("project group %q doesn't exist", projectGroupRef))
} }
return projectGroup, nil return projectGroup, nil
@ -57,7 +57,7 @@ func (h *ActionHandler) GetProjectGroupSubgroups(ctx context.Context, projectGro
} }
if projectGroup == nil { if projectGroup == nil {
return util.NewErrNotFound(errors.Errorf("project group %q doesn't exist", projectGroupRef)) return util.NewErrNotExist(errors.Errorf("project group %q doesn't exist", projectGroupRef))
} }
projectGroups, err = h.readDB.GetProjectGroupSubgroups(tx, projectGroup.ID) projectGroups, err = h.readDB.GetProjectGroupSubgroups(tx, projectGroup.ID)
@ -80,7 +80,7 @@ func (h *ActionHandler) GetProjectGroupProjects(ctx context.Context, projectGrou
} }
if projectGroup == nil { if projectGroup == nil {
return util.NewErrNotFound(errors.Errorf("project group %q doesn't exist", projectGroupRef)) return util.NewErrNotExist(errors.Errorf("project group %q doesn't exist", projectGroupRef))
} }
projects, err = h.readDB.GetProjectGroupProjects(tx, projectGroup.ID) projects, err = h.readDB.GetProjectGroupProjects(tx, projectGroup.ID)

View File

@ -39,7 +39,7 @@ func (h *ActionHandler) GetSecret(ctx context.Context, secretID string) (*types.
} }
if secret == nil { if secret == nil {
return nil, util.NewErrNotFound(errors.Errorf("secret %q doesn't exist", secretID)) return nil, util.NewErrNotExist(errors.Errorf("secret %q doesn't exist", secretID))
} }
return secret, nil return secret, nil

View File

@ -651,7 +651,7 @@ func (h *ActionHandler) GetUserOrgs(ctx context.Context, userRef string) ([]*Use
return err return err
} }
if user == nil { if user == nil {
return util.NewErrNotFound(errors.Errorf("user %q doesn't exist", userRef)) return util.NewErrNotExist(errors.Errorf("user %q doesn't exist", userRef))
} }
userOrgs, err = h.readDB.GetUserOrgs(tx, user.ID) userOrgs, err = h.readDB.GetUserOrgs(tx, user.ID)

View File

@ -34,23 +34,23 @@ func ErrorResponseFromError(err error) *ErrorResponse {
var aerr error var aerr error
// use inner errors if of these types // use inner errors if of these types
switch { switch {
case errors.Is(err, &util.ErrBadRequest{}): case util.IsBadRequest(err):
var cerr *util.ErrBadRequest var cerr *util.ErrBadRequest
errors.As(err, &cerr) errors.As(err, &cerr)
aerr = cerr aerr = cerr
case errors.Is(err, &util.ErrNotFound{}): case util.IsNotExist(err):
var cerr *util.ErrNotFound var cerr *util.ErrNotExist
errors.As(err, &cerr) errors.As(err, &cerr)
aerr = cerr aerr = cerr
case errors.Is(err, &util.ErrForbidden{}): case util.IsForbidden(err):
var cerr *util.ErrForbidden var cerr *util.ErrForbidden
errors.As(err, &cerr) errors.As(err, &cerr)
aerr = cerr aerr = cerr
case errors.Is(err, &util.ErrUnauthorized{}): case util.IsUnauthorized(err):
var cerr *util.ErrUnauthorized var cerr *util.ErrUnauthorized
errors.As(err, &cerr) errors.As(err, &cerr)
aerr = cerr aerr = cerr
case errors.Is(err, &util.ErrInternal{}): case util.IsInternal(err):
var cerr *util.ErrInternal var cerr *util.ErrInternal
errors.As(err, &cerr) errors.As(err, &cerr)
aerr = cerr aerr = cerr
@ -76,19 +76,19 @@ func httpError(w http.ResponseWriter, err error) bool {
return true return true
} }
switch { switch {
case errors.Is(err, &util.ErrBadRequest{}): case util.IsBadRequest(err):
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
_, _ = w.Write(resj) _, _ = w.Write(resj)
case errors.Is(err, &util.ErrNotFound{}): case util.IsNotExist(err):
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
_, _ = w.Write(resj) _, _ = w.Write(resj)
case errors.Is(err, &util.ErrForbidden{}): case util.IsForbidden(err):
w.WriteHeader(http.StatusForbidden) w.WriteHeader(http.StatusForbidden)
_, _ = w.Write(resj) _, _ = w.Write(resj)
case errors.Is(err, &util.ErrUnauthorized{}): case util.IsUnauthorized(err):
w.WriteHeader(http.StatusUnauthorized) w.WriteHeader(http.StatusUnauthorized)
_, _ = w.Write(resj) _, _ = w.Write(resj)
case errors.Is(err, &util.ErrInternal{}): case util.IsInternal(err):
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write(resj) _, _ = w.Write(resj)
default: default:

View File

@ -58,7 +58,7 @@ func (h *OrgHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
} }
if org == nil { if org == nil {
httpError(w, util.NewErrNotFound(errors.Errorf("org %q doesn't exist", orgRef))) httpError(w, util.NewErrNotExist(errors.Errorf("org %q doesn't exist", orgRef)))
return return
} }

View File

@ -57,7 +57,7 @@ func (h *RemoteSourceHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
} }
if remoteSource == nil { if remoteSource == nil {
httpError(w, util.NewErrNotFound(errors.Errorf("remote source %q doesn't exist", rsRef))) httpError(w, util.NewErrNotExist(errors.Errorf("remote source %q doesn't exist", rsRef)))
return return
} }

View File

@ -58,7 +58,7 @@ func (h *UserHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
} }
if user == nil { if user == nil {
httpError(w, util.NewErrNotFound(errors.Errorf("user %q doesn't exist", userRef))) httpError(w, util.NewErrNotExist(errors.Errorf("user %q doesn't exist", userRef)))
return return
} }
@ -235,7 +235,7 @@ func (h *UsersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return return
} }
if user == nil { if user == nil {
httpError(w, util.NewErrNotFound(errors.Errorf("user with required token doesn't exist"))) httpError(w, util.NewErrNotExist(errors.Errorf("user with required token doesn't exist")))
return return
} }
users = []*types.User{user} users = []*types.User{user}
@ -253,7 +253,7 @@ func (h *UsersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return return
} }
if user == nil { if user == nil {
httpError(w, util.NewErrNotFound(errors.Errorf("user with linked account %q token doesn't exist", linkedAccountID))) httpError(w, util.NewErrNotExist(errors.Errorf("user with linked account %q token doesn't exist", linkedAccountID)))
return return
} }
users = []*types.User{user} users = []*types.User{user}
@ -272,7 +272,7 @@ func (h *UsersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return return
} }
if user == nil { if user == nil {
httpError(w, util.NewErrNotFound(errors.Errorf("user with remote user %q for remote source %q token doesn't exist", remoteUserID, remoteSourceID))) httpError(w, util.NewErrNotExist(errors.Errorf("user with remote user %q for remote source %q token doesn't exist", remoteUserID, remoteSourceID)))
return return
} }
users = []*types.User{user} users = []*types.User{user}

View File

@ -129,12 +129,9 @@ func (r *ReadDB) ResetDB(ctx context.Context) error {
func (r *ReadDB) SyncFromDump(ctx context.Context) (string, error) { func (r *ReadDB) SyncFromDump(ctx context.Context) (string, error) {
dumpIndex, err := r.dm.GetLastDataStatus() dumpIndex, err := r.dm.GetLastDataStatus()
if err != nil && err != objectstorage.ErrNotExist { if err != nil {
return "", err return "", err
} }
if err == objectstorage.ErrNotExist {
return "", nil
}
for dataType, files := range dumpIndex.Files { for dataType, files := range dumpIndex.Files {
for _, file := range files { for _, file := range files {
dumpf, err := r.ost.ReadObject(r.dm.DataFilePath(dataType, file.ID)) dumpf, err := r.ost.ReadObject(r.dm.DataFilePath(dataType, file.ID))

View File

@ -57,7 +57,7 @@ func ErrFromRemote(resp *http.Response, err error) error {
case http.StatusBadRequest: case http.StatusBadRequest:
return util.NewErrBadRequest(err) return util.NewErrBadRequest(err)
case http.StatusNotFound: case http.StatusNotFound:
return util.NewErrNotFound(err) return util.NewErrNotExist(err)
} }
} }

View File

@ -34,23 +34,23 @@ func ErrorResponseFromError(err error) *ErrorResponse {
var aerr error var aerr error
// use inner errors if of these types // use inner errors if of these types
switch { switch {
case errors.Is(err, &util.ErrBadRequest{}): case util.IsBadRequest(err):
var cerr *util.ErrBadRequest var cerr *util.ErrBadRequest
errors.As(err, &cerr) errors.As(err, &cerr)
aerr = cerr aerr = cerr
case errors.Is(err, &util.ErrNotFound{}): case util.IsNotExist(err):
var cerr *util.ErrNotFound var cerr *util.ErrNotExist
errors.As(err, &cerr) errors.As(err, &cerr)
aerr = cerr aerr = cerr
case errors.Is(err, &util.ErrForbidden{}): case util.IsForbidden(err):
var cerr *util.ErrForbidden var cerr *util.ErrForbidden
errors.As(err, &cerr) errors.As(err, &cerr)
aerr = cerr aerr = cerr
case errors.Is(err, &util.ErrUnauthorized{}): case util.IsUnauthorized(err):
var cerr *util.ErrUnauthorized var cerr *util.ErrUnauthorized
errors.As(err, &cerr) errors.As(err, &cerr)
aerr = cerr aerr = cerr
case errors.Is(err, &util.ErrInternal{}): case util.IsInternal(err):
var cerr *util.ErrInternal var cerr *util.ErrInternal
errors.As(err, &cerr) errors.As(err, &cerr)
aerr = cerr aerr = cerr
@ -76,19 +76,19 @@ func httpError(w http.ResponseWriter, err error) bool {
return true return true
} }
switch { switch {
case errors.Is(err, &util.ErrBadRequest{}): case util.IsBadRequest(err):
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
_, _ = w.Write(resj) _, _ = w.Write(resj)
case errors.Is(err, &util.ErrNotFound{}): case util.IsNotExist(err):
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
_, _ = w.Write(resj) _, _ = w.Write(resj)
case errors.Is(err, &util.ErrForbidden{}): case util.IsForbidden(err):
w.WriteHeader(http.StatusForbidden) w.WriteHeader(http.StatusForbidden)
_, _ = w.Write(resj) _, _ = w.Write(resj)
case errors.Is(err, &util.ErrUnauthorized{}): case util.IsUnauthorized(err):
w.WriteHeader(http.StatusUnauthorized) w.WriteHeader(http.StatusUnauthorized)
_, _ = w.Write(resj) _, _ = w.Write(resj)
case errors.Is(err, &util.ErrInternal{}): case util.IsInternal(err):
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write(resj) _, _ = w.Write(resj)
default: default:

View File

@ -197,7 +197,7 @@ func (h *RuntaskHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
rt, ok := run.Tasks[taskID] rt, ok := run.Tasks[taskID]
if !ok { if !ok {
httpError(w, util.NewErrNotFound(errors.Errorf("run %q task %q not found", runID, taskID))) httpError(w, util.NewErrNotExist(errors.Errorf("run %q task %q not found", runID, taskID)))
return return
} }
rct := rc.Tasks[rt.ID] rct := rc.Tasks[rt.ID]

View File

@ -592,7 +592,7 @@ func (h *ActionHandler) GetExecutorTask(ctx context.Context, etID string) (*type
return nil, err return nil, err
} }
if et == nil { if et == nil {
return nil, util.NewErrNotFound(errors.Errorf("executor task %q not found", etID)) return nil, util.NewErrNotExist(errors.Errorf("executor task %q not found", etID))
} }
r, _, err := store.GetRun(ctx, h.e, et.Spec.RunID) r, _, err := store.GetRun(ctx, h.e, et.Spec.RunID)

View File

@ -50,23 +50,23 @@ func ErrorResponseFromError(err error) *ErrorResponse {
var aerr error var aerr error
// use inner errors if of these types // use inner errors if of these types
switch { switch {
case errors.Is(err, &util.ErrBadRequest{}): case util.IsBadRequest(err):
var cerr *util.ErrBadRequest var cerr *util.ErrBadRequest
errors.As(err, &cerr) errors.As(err, &cerr)
aerr = cerr aerr = cerr
case errors.Is(err, &util.ErrNotFound{}): case util.IsNotExist(err):
var cerr *util.ErrNotFound var cerr *util.ErrNotExist
errors.As(err, &cerr) errors.As(err, &cerr)
aerr = cerr aerr = cerr
case errors.Is(err, &util.ErrForbidden{}): case util.IsForbidden(err):
var cerr *util.ErrForbidden var cerr *util.ErrForbidden
errors.As(err, &cerr) errors.As(err, &cerr)
aerr = cerr aerr = cerr
case errors.Is(err, &util.ErrUnauthorized{}): case util.IsUnauthorized(err):
var cerr *util.ErrUnauthorized var cerr *util.ErrUnauthorized
errors.As(err, &cerr) errors.As(err, &cerr)
aerr = cerr aerr = cerr
case errors.Is(err, &util.ErrInternal{}): case util.IsInternal(err):
var cerr *util.ErrInternal var cerr *util.ErrInternal
errors.As(err, &cerr) errors.As(err, &cerr)
aerr = cerr aerr = cerr
@ -92,19 +92,19 @@ func httpError(w http.ResponseWriter, err error) bool {
return true return true
} }
switch { switch {
case errors.Is(err, &util.ErrBadRequest{}): case util.IsBadRequest(err):
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
_, _ = w.Write(resj) _, _ = w.Write(resj)
case errors.Is(err, &util.ErrNotFound{}): case util.IsNotExist(err):
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
_, _ = w.Write(resj) _, _ = w.Write(resj)
case errors.Is(err, &util.ErrForbidden{}): case util.IsForbidden(err):
w.WriteHeader(http.StatusForbidden) w.WriteHeader(http.StatusForbidden)
_, _ = w.Write(resj) _, _ = w.Write(resj)
case errors.Is(err, &util.ErrUnauthorized{}): case util.IsUnauthorized(err):
w.WriteHeader(http.StatusUnauthorized) w.WriteHeader(http.StatusUnauthorized)
_, _ = w.Write(resj) _, _ = w.Write(resj)
case errors.Is(err, &util.ErrInternal{}): case util.IsInternal(err):
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write(resj) _, _ = w.Write(resj)
default: default:
@ -193,8 +193,8 @@ func (h *LogsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if err, sendError := h.readTaskLogs(ctx, runID, taskID, setup, step, w, follow); err != nil { if err, sendError := h.readTaskLogs(ctx, runID, taskID, setup, step, w, follow); err != nil {
h.log.Errorf("err: %+v", err) h.log.Errorf("err: %+v", err)
if sendError { if sendError {
switch err.(type) { switch {
case common.ErrNotExist: case util.IsNotExist(err):
http.Error(w, err.Error(), http.StatusNotFound) http.Error(w, err.Error(), http.StatusNotFound)
default: default:
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
@ -230,8 +230,8 @@ func (h *LogsHandler) readTaskLogs(ctx context.Context, runID, taskID string, se
} }
f, err := h.ost.ReadObject(logPath) f, err := h.ost.ReadObject(logPath)
if err != nil { if err != nil {
if err == objectstorage.ErrNotExist { if objectstorage.IsNotExist(err) {
return common.NewErrNotExist(err), true return util.NewErrNotExist(err), true
} }
return err, true return err, true
} }
@ -248,7 +248,7 @@ func (h *LogsHandler) readTaskLogs(ctx context.Context, runID, taskID string, se
return err, true return err, true
} }
if executor == nil { if executor == nil {
return common.NewErrNotExist(errors.Errorf("executor with id %q doesn't exist", et.Spec.ExecutorID)), true return util.NewErrNotExist(errors.Errorf("executor with id %q doesn't exist", et.Spec.ExecutorID)), true
} }
var url string var url string
@ -267,7 +267,7 @@ func (h *LogsHandler) readTaskLogs(ctx context.Context, runID, taskID string, se
defer req.Body.Close() defer req.Body.Close()
if req.StatusCode != http.StatusOK { if req.StatusCode != http.StatusOK {
if req.StatusCode == http.StatusNotFound { if req.StatusCode == http.StatusNotFound {
return common.NewErrNotExist(errors.New("no log on executor")), true return util.NewErrNotExist(errors.New("no log on executor")), true
} }
return errors.Errorf("received http status: %d", req.StatusCode), true return errors.Errorf("received http status: %d", req.StatusCode), true
} }
@ -393,7 +393,7 @@ func (h *RunHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return return
} }
if run == nil { if run == nil {
httpError(w, util.NewErrNotFound(errors.Errorf("run %q doesn't exist", runID))) httpError(w, util.NewErrNotExist(errors.Errorf("run %q doesn't exist", runID)))
return return
} }

View File

@ -234,8 +234,8 @@ func (h *ArchivesHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Cache-Control", "no-cache") w.Header().Set("Cache-Control", "no-cache")
if err := h.readArchive(taskID, step, w); err != nil { if err := h.readArchive(taskID, step, w); err != nil {
switch err.(type) { switch {
case common.ErrNotExist: case util.IsNotExist(err):
http.Error(w, err.Error(), http.StatusNotFound) http.Error(w, err.Error(), http.StatusNotFound)
default: default:
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
@ -248,8 +248,8 @@ func (h *ArchivesHandler) readArchive(rtID string, step int, w io.Writer) error
archivePath := store.OSTRunTaskArchivePath(rtID, step) archivePath := store.OSTRunTaskArchivePath(rtID, step)
f, err := h.ost.ReadObject(archivePath) f, err := h.ost.ReadObject(archivePath)
if err != nil { if err != nil {
if err == objectstorage.ErrNotExist { if objectstorage.IsNotExist(err) {
return common.NewErrNotExist(err) return util.NewErrNotExist(err)
} }
return err return err
} }
@ -307,8 +307,8 @@ func (h *CacheHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Cache-Control", "no-cache") w.Header().Set("Cache-Control", "no-cache")
if err := h.readCache(matchedKey, w); err != nil { if err := h.readCache(matchedKey, w); err != nil {
switch err.(type) { switch {
case common.ErrNotExist: case util.IsNotExist(err):
http.Error(w, err.Error(), http.StatusNotFound) http.Error(w, err.Error(), http.StatusNotFound)
default: default:
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
@ -344,7 +344,7 @@ func matchCache(ost *objectstorage.ObjStorage, key string, prefix bool) (string,
} }
_, err := ost.Stat(cachePath) _, err := ost.Stat(cachePath)
if err == objectstorage.ErrNotExist { if objectstorage.IsNotExist(err) {
return "", nil return "", nil
} }
if err != nil { if err != nil {
@ -357,8 +357,8 @@ func (h *CacheHandler) readCache(key string, w io.Writer) error {
cachePath := store.OSTCachePath(key) cachePath := store.OSTCachePath(key)
f, err := h.ost.ReadObject(cachePath) f, err := h.ost.ReadObject(cachePath)
if err != nil { if err != nil {
if err == objectstorage.ErrNotExist { if objectstorage.IsNotExist(err) {
return common.NewErrNotExist(err) return util.NewErrNotExist(err)
} }
return err return err
} }

View File

@ -28,18 +28,6 @@ const (
MaxCacheKeyLength = 200 MaxCacheKeyLength = 200
) )
type ErrNotExist struct {
err error
}
func NewErrNotExist(err error) error {
return ErrNotExist{err: err}
}
func (e ErrNotExist) Error() string {
return e.err.Error()
}
var ( var (
EtcdSchedulerBaseDir = "scheduler" EtcdSchedulerBaseDir = "scheduler"

View File

@ -667,12 +667,9 @@ func (r *ReadDB) SyncObjectStorage(ctx context.Context) error {
func (r *ReadDB) SyncFromDump(ctx context.Context) (string, error) { func (r *ReadDB) SyncFromDump(ctx context.Context) (string, error) {
dumpIndex, err := r.dm.GetLastDataStatus() dumpIndex, err := r.dm.GetLastDataStatus()
if err != nil && err != objectstorage.ErrNotExist { if err != nil {
return "", err return "", err
} }
if err == objectstorage.ErrNotExist {
return "", nil
}
for dataType, files := range dumpIndex.Files { for dataType, files := range dumpIndex.Files {
for _, file := range files { for _, file := range files {
dumpf, err := r.ost.ReadObject(r.dm.DataFilePath(dataType, file.ID)) dumpf, err := r.ost.ReadObject(r.dm.DataFilePath(dataType, file.ID))

View File

@ -865,7 +865,7 @@ func (s *Runservice) runTasksUpdater(ctx context.Context) error {
func (s *Runservice) OSTFileExists(path string) (bool, error) { func (s *Runservice) OSTFileExists(path string) (bool, error) {
_, err := s.ost.Stat(path) _, err := s.ost.Stat(path)
if err != nil && err != objectstorage.ErrNotExist { if err != nil && !objectstorage.IsNotExist(err) {
return false, err return false, err
} }
return err == nil, nil return err == nil, nil
@ -1359,7 +1359,7 @@ func (s *Runservice) cacheCleaner(ctx context.Context, cacheExpireInterval time.
} }
if object.LastModified.Add(cacheExpireInterval).Before(time.Now()) { if object.LastModified.Add(cacheExpireInterval).Before(time.Now()) {
if err := s.ost.DeleteObject(object.Path); err != nil { if err := s.ost.DeleteObject(object.Path); err != nil {
if err != objectstorage.ErrNotExist { if !objectstorage.IsNotExist(err) {
log.Warnf("failed to delete cache object %q: %v", object.Path, err) log.Warnf("failed to delete cache object %q: %v", object.Path, err)
} }
} }
@ -1411,7 +1411,7 @@ func (s *Runservice) workspaceCleaner(ctx context.Context, workspaceExpireInterv
} }
if object.LastModified.Add(workspaceExpireInterval).Before(time.Now()) { if object.LastModified.Add(workspaceExpireInterval).Before(time.Now()) {
if err := s.ost.DeleteObject(object.Path); err != nil { if err := s.ost.DeleteObject(object.Path); err != nil {
if err != objectstorage.ErrNotExist { if !objectstorage.IsNotExist(err) {
log.Warnf("failed to delete workspace object %q: %v", object.Path, err) log.Warnf("failed to delete workspace object %q: %v", object.Path, err)
} }
} }

View File

@ -504,7 +504,7 @@ func GetRunEtcdOrOST(ctx context.Context, e *etcd.Store, dm *datamanager.DataMan
} }
if r == nil { if r == nil {
r, err = OSTGetRun(dm, runID) r, err = OSTGetRun(dm, runID)
if err != nil && err != objectstorage.ErrNotExist { if err != nil && !objectstorage.IsNotExist(err) {
return nil, err return nil, err
} }
} }

View File

@ -16,6 +16,8 @@ package util
import ( import (
"strings" "strings"
errors "golang.org/x/xerrors"
) )
// Errors is an error that contains multiple errors // Errors is an error that contains multiple errors
@ -75,25 +77,33 @@ func (*ErrBadRequest) Is(err error) bool {
return ok return ok
} }
// ErrNotFound represent a not found error func IsBadRequest(err error) bool {
return errors.Is(err, &ErrBadRequest{})
}
// ErrNotExist represent a not exist error
// it's used to differentiate an internal error from an user error // it's used to differentiate an internal error from an user error
type ErrNotFound struct { type ErrNotExist struct {
Err error Err error
} }
func (e *ErrNotFound) Error() string { func (e *ErrNotExist) Error() string {
return e.Err.Error() return e.Err.Error()
} }
func NewErrNotFound(err error) *ErrNotFound { func NewErrNotExist(err error) *ErrNotExist {
return &ErrNotFound{Err: err} return &ErrNotExist{Err: err}
} }
func (*ErrNotFound) Is(err error) bool { func (*ErrNotExist) Is(err error) bool {
_, ok := err.(*ErrNotFound) _, ok := err.(*ErrNotExist)
return ok return ok
} }
func IsNotExist(err error) bool {
return errors.Is(err, &ErrNotExist{})
}
// ErrForbidden represent an error caused by an forbidden operation // ErrForbidden represent an error caused by an forbidden operation
// it's used to differentiate an internal error from an user error // it's used to differentiate an internal error from an user error
type ErrForbidden struct { type ErrForbidden struct {
@ -113,6 +123,10 @@ func (*ErrForbidden) Is(err error) bool {
return ok return ok
} }
func IsForbidden(err error) bool {
return errors.Is(err, &ErrForbidden{})
}
// ErrUnauthorized represent an error caused by an unauthorized request // ErrUnauthorized represent an error caused by an unauthorized request
// it's used to differentiate an internal error from an user error // it's used to differentiate an internal error from an user error
type ErrUnauthorized struct { type ErrUnauthorized struct {
@ -132,6 +146,10 @@ func (*ErrUnauthorized) Is(err error) bool {
return ok return ok
} }
func IsUnauthorized(err error) bool {
return errors.Is(err, &ErrUnauthorized{})
}
type ErrInternal struct { type ErrInternal struct {
Err error Err error
} }
@ -149,3 +167,7 @@ func (*ErrInternal) Is(err error) bool {
_, ok := err.(*ErrInternal) _, ok := err.(*ErrInternal)
return ok return ok
} }
func IsInternal(err error) bool {
return errors.Is(err, &ErrInternal{})
}