From c1da3ab5663a106ab4a0e61aa96e206520981b71 Mon Sep 17 00:00:00 2001 From: Simone Gotti Date: Mon, 21 Feb 2022 12:19:55 +0100 Subject: [PATCH] *: Improve error handling * Create an APIError that should only be used for api returned errors. It'll wrap an error and can have different Kinds and optional code and message. * The http handlers will use the first APIError available in the error chain and generate a json response body containing the code and the user message. The wrapped error is internal and is not sent in the response. If no api error is available in the chain a generic internal server error will be returned. * Add a RemoteError type that will be created from remote services calls (runservice, configstore). It's similar to the APIError but a different type to not propagate to the caller response and it'll not contain any wrapped error. * Gateway: when we call a remote service, by default, we'll create a APIError using the RemoteError Kind (omitting the code and the message that usually must not be propagated). This is done for all the remote service calls as a starting point, in future, if this default behavior is not the right one for a specific remote service call, a new api error with a different kind and/or augmented with the calling service error codes and user messages could be created. * datamanager: Use a dedicated ErrNotExist (and converting objectstorage ErrNotExist). --- internal/datamanager/data.go | 35 ++-- internal/datamanager/datamanager.go | 29 +++ internal/datamanager/datamanager_test.go | 9 +- internal/datamanager/wal.go | 30 +-- internal/gitsources/agolagit/agolagit.go | 18 +- .../services/configstore/action/action.go | 31 +++ .../configstore/action/maintenance.go | 6 +- internal/services/configstore/action/org.go | 26 +-- .../services/configstore/action/project.go | 50 ++--- .../configstore/action/projectgroup.go | 42 ++-- .../configstore/action/remotesource.go | 26 +-- .../services/configstore/action/secret.go | 32 +-- internal/services/configstore/action/user.go | 60 +++--- .../services/configstore/action/variable.go | 28 +-- internal/services/configstore/api/api.go | 93 +-------- .../services/configstore/api/maintenance.go | 9 +- internal/services/configstore/api/org.go | 38 ++-- internal/services/configstore/api/project.go | 32 +-- .../services/configstore/api/projectgroup.go | 48 ++--- .../services/configstore/api/remotesource.go | 30 +-- internal/services/configstore/api/secret.go | 34 ++-- internal/services/configstore/api/user.go | 72 +++---- internal/services/configstore/api/variable.go | 30 +-- .../services/configstore/configstore_test.go | 4 +- .../services/configstore/readdb/resolve.go | 29 +-- .../services/executor/driver/docker_test.go | 2 +- internal/services/gateway/action/action.go | 20 -- internal/services/gateway/action/auth.go | 29 +-- internal/services/gateway/action/badge.go | 9 +- internal/services/gateway/action/org.go | 60 +++--- internal/services/gateway/action/project.go | 128 ++++++------ .../services/gateway/action/projectgroup.go | 49 +++-- .../services/gateway/action/remotesource.go | 41 ++-- internal/services/gateway/action/run.go | 84 ++++---- internal/services/gateway/action/secret.go | 39 ++-- internal/services/gateway/action/user.go | 149 +++++++------- internal/services/gateway/action/variable.go | 76 ++++---- internal/services/gateway/api/api.go | 120 +----------- internal/services/gateway/api/badge.go | 5 +- internal/services/gateway/api/oauth2.go | 4 +- internal/services/gateway/api/org.go | 36 ++-- internal/services/gateway/api/project.go | 46 ++--- internal/services/gateway/api/projectgroup.go | 40 ++-- internal/services/gateway/api/remoterepo.go | 22 +-- internal/services/gateway/api/remotesource.go | 28 +-- internal/services/gateway/api/repos.go | 11 +- internal/services/gateway/api/run.go | 54 ++--- internal/services/gateway/api/secret.go | 28 +-- internal/services/gateway/api/user.go | 78 ++++---- internal/services/gateway/api/variable.go | 28 +-- internal/services/gateway/api/version.go | 5 +- internal/services/gateway/api/webhook.go | 20 +- internal/services/gateway/handlers/auth.go | 15 +- internal/services/runservice/action/action.go | 24 +-- .../services/runservice/action/maintenance.go | 6 +- internal/services/runservice/api/api.go | 152 ++++----------- internal/services/runservice/api/executor.go | 14 +- .../services/runservice/api/maintenance.go | 9 +- internal/services/runservice/store/store.go | 3 +- internal/services/scheduler/scheduler.go | 2 +- internal/util/errors.go | 184 ++++++++++-------- internal/util/http.go | 124 ++++++++++++ services/configstore/client/client.go | 47 ++--- services/gateway/client/client.go | 18 +- services/runservice/client/client.go | 17 +- tests/setup_test.go | 4 +- 66 files changed, 1232 insertions(+), 1439 deletions(-) create mode 100644 internal/util/http.go diff --git a/internal/datamanager/data.go b/internal/datamanager/data.go index 37a341d..e81d221 100644 --- a/internal/datamanager/data.go +++ b/internal/datamanager/data.go @@ -28,7 +28,6 @@ import ( "agola.io/agola/internal/objectstorage" "agola.io/agola/internal/sequence" - "agola.io/agola/internal/util" "github.com/gofrs/uuid" errors "golang.org/x/xerrors" @@ -205,7 +204,7 @@ func (d *DataManager) writeDataSnapshot(ctx context.Context, wals []*WalData) er return err } if err := d.ost.WriteObject(d.dataStatusPath(dataSequence), bytes.NewReader(dataStatusj), int64(len(dataStatusj)), true); err != nil { - return err + return fromOSTError(err) } return nil @@ -217,7 +216,7 @@ func (d *DataManager) writeDataFile(ctx context.Context, buf *bytes.Buffer, size } if err := d.ost.WriteObject(d.DataFilePath(dataType, dataFileID), buf, size, true); err != nil { - return err + return fromOSTError(err) } dataFileIndexj, err := json.Marshal(dataFileIndex) @@ -225,7 +224,7 @@ func (d *DataManager) writeDataFile(ctx context.Context, buf *bytes.Buffer, size return err } if err := d.ost.WriteObject(d.DataFileIndexPath(dataType, dataFileID), bytes.NewReader(dataFileIndexj), int64(len(dataFileIndexj)), true); err != nil { - return err + return fromOSTError(err) } return nil @@ -341,7 +340,7 @@ func (d *DataManager) writeDataType(ctx context.Context, wi walIndex, dataType s // 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)) if err != nil && !objectstorage.IsNotExist(err) { - return nil, err + return nil, fromOSTError(err) } if !objectstorage.IsNotExist(err) { dec := json.NewDecoder(oldDataf) @@ -500,7 +499,7 @@ func (d *DataManager) Read(dataType, id string) (io.Reader, error) { var matchingDataFileID string // get the matching data file for the action entry ID if len(curFiles[dataType]) == 0 { - return nil, util.NewErrNotExist(errors.Errorf("datatype %q doesn't exists", dataType)) + return nil, newErrNotExist(errors.Errorf("datatype %q doesn't exists", dataType)) } matchingDataFileID = curFiles[dataType][0].ID @@ -513,7 +512,7 @@ func (d *DataManager) Read(dataType, id string) (io.Reader, error) { dataFileIndexf, err := d.ost.ReadObject(d.DataFileIndexPath(dataType, matchingDataFileID)) if err != nil { - return nil, err + return nil, fromOSTError(err) } var dataFileIndex *DataFileIndex dec := json.NewDecoder(dataFileIndexf) @@ -526,12 +525,12 @@ func (d *DataManager) Read(dataType, id string) (io.Reader, error) { pos, ok := dataFileIndex.Index[id] if !ok { - return nil, util.NewErrNotExist(errors.Errorf("datatype %q, id %q doesn't exists", dataType, id)) + return nil, newErrNotExist(errors.Errorf("datatype %q, id %q doesn't exists", dataType, id)) } dataf, err := d.ost.ReadObject(d.DataFilePath(dataType, matchingDataFileID)) if err != nil { - return nil, err + return nil, fromOSTError(err) } if _, err := dataf.Seek(int64(pos), io.SeekStart); err != nil { dataf.Close() @@ -560,7 +559,7 @@ func (d *DataManager) GetFirstDataStatusSequences(n int) ([]*sequence.Sequence, defer close(doneCh) for object := range d.ost.List(d.storageDataDir()+"/", "", false, doneCh) { if object.Err != nil { - return nil, object.Err + return nil, fromOSTError(object.Err) } if m := DataStatusFileRegexp.FindStringSubmatch(path.Base(object.Path)); m != nil { seq, err := sequence.Parse(m[1]) @@ -597,7 +596,7 @@ func (d *DataManager) GetLastDataStatusSequences(n int) ([]*sequence.Sequence, e for object := range d.ost.List(d.storageDataDir()+"/", "", false, doneCh) { if object.Err != nil { - return nil, object.Err + return nil, fromOSTError(object.Err) } if m := DataStatusFileRegexp.FindStringSubmatch(path.Base(object.Path)); m != nil { seq, err := sequence.Parse(m[1]) @@ -629,7 +628,7 @@ func (d *DataManager) GetLastDataStatusSequences(n int) ([]*sequence.Sequence, e func (d *DataManager) GetDataStatus(dataSequence *sequence.Sequence) (*DataStatus, error) { dataStatusf, err := d.ost.ReadObject(d.dataStatusPath(dataSequence)) if err != nil { - return nil, err + return nil, fromOSTError(err) } defer dataStatusf.Close() var dataStatus *DataStatus @@ -692,7 +691,7 @@ func (d *DataManager) Export(ctx context.Context, w io.Writer) error { for _, dsf := range curDataStatusFiles { dataf, err := d.ost.ReadObject(d.DataFilePath(dataType, dsf.ID)) if err != nil { - return err + return fromOSTError(err) } if _, err := io.Copy(w, dataf); err != nil { dataf.Close() @@ -825,7 +824,7 @@ func (d *DataManager) Import(ctx context.Context, r io.Reader) error { return err } if err := d.ost.WriteObject(d.dataStatusPath(dataSequence), bytes.NewReader(dataStatusj), int64(len(dataStatusj)), true); err != nil { - return err + return fromOSTError(err) } // initialize etcd providing the specific datastatus @@ -863,7 +862,7 @@ func (d *DataManager) cleanOldCheckpoints(ctx context.Context, dataStatusSequenc defer close(doneCh) for object := range d.ost.List(d.storageDataDir()+"/", "", false, doneCh) { if object.Err != nil { - return object.Err + return fromOSTError(object.Err) } skip := false @@ -882,7 +881,7 @@ func (d *DataManager) cleanOldCheckpoints(ctx context.Context, dataStatusSequenc d.log.Infof("removing %q", object.Path) if err := d.ost.DeleteObject(object.Path); err != nil { if !objectstorage.IsNotExist(err) { - return err + return fromOSTError(err) } } } @@ -910,7 +909,7 @@ func (d *DataManager) cleanOldCheckpoints(ctx context.Context, dataStatusSequenc for object := range d.ost.List(d.storageDataDir()+"/", "", true, doneCh) { if object.Err != nil { - return object.Err + return fromOSTError(object.Err) } p := object.Path @@ -950,7 +949,7 @@ func (d *DataManager) cleanOldCheckpoints(ctx context.Context, dataStatusSequenc d.log.Infof("removing %q", object.Path) if err := d.ost.DeleteObject(object.Path); err != nil { if !objectstorage.IsNotExist(err) { - return err + return fromOSTError(err) } } } diff --git a/internal/datamanager/datamanager.go b/internal/datamanager/datamanager.go index 2ff994d..2745c99 100644 --- a/internal/datamanager/datamanager.go +++ b/internal/datamanager/datamanager.go @@ -50,6 +50,35 @@ var ( ErrConcurrency = errors.New("wal concurrency error: change groups already updated") ) +type ErrNotExist struct { + err error +} + +func newErrNotExist(err error) error { + return &ErrNotExist{err: err} +} + +func (e *ErrNotExist) Error() string { + return e.err.Error() +} + +func (e *ErrNotExist) Unwrap() error { + return e.err +} + +func IsNotExist(err error) bool { + var e *ErrNotExist + return errors.As(err, &e) +} + +func fromOSTError(err error) error { + if objectstorage.IsNotExist(err) { + return newErrNotExist(err) + } + + return err +} + var ( // Storage paths. Always use path (not filepath) to use the "/" separator storageDataDir = "data" diff --git a/internal/datamanager/datamanager_test.go b/internal/datamanager/datamanager_test.go index 163f633..740a6cf 100644 --- a/internal/datamanager/datamanager_test.go +++ b/internal/datamanager/datamanager_test.go @@ -31,7 +31,6 @@ import ( "agola.io/agola/internal/objectstorage" "agola.io/agola/internal/testutil" - "agola.io/agola/internal/util" "github.com/google/go-cmp/cmp" "go.uber.org/zap" @@ -559,8 +558,8 @@ func TestReadObject(t *testing.T) { // should not exists _, _, err = dm.ReadObject("datatype01", "object1", nil) - if !util.IsNotExist(err) { - t.Fatalf("expected err %v, got: %v", &util.ErrNotExist{}, err) + if !IsNotExist(err) { + t.Fatalf("expected not exist error, got: %v", err) } // should exist _, _, err = dm.ReadObject("datatype01", "object19", nil) @@ -583,8 +582,8 @@ func TestReadObject(t *testing.T) { // should not exists _, _, err = dm.ReadObject("datatype01", "object1", nil) - if !util.IsNotExist(err) { - t.Fatalf("expected err %v, got: %v", &util.ErrNotExist{}, err) + if !IsNotExist(err) { + t.Fatalf("expected not exist error, got: %v", err) } // should exist _, _, err = dm.ReadObject("datatype01", "object19", nil) diff --git a/internal/datamanager/wal.go b/internal/datamanager/wal.go index d898a82..775cbcd 100644 --- a/internal/datamanager/wal.go +++ b/internal/datamanager/wal.go @@ -28,7 +28,6 @@ import ( "agola.io/agola/internal/etcd" "agola.io/agola/internal/objectstorage" "agola.io/agola/internal/sequence" - "agola.io/agola/internal/util" "github.com/gofrs/uuid" etcdclientv3 "go.etcd.io/etcd/clientv3" @@ -124,7 +123,7 @@ func (d *DataManager) ReadObject(dataType, id string, cgNames []string) (io.Read } } } - return nil, nil, util.NewErrNotExist(errors.Errorf("no datatype %q, id %q in wal %s", dataType, id, walseq)) + return nil, nil, newErrNotExist(errors.Errorf("no datatype %q, id %q in wal %s", dataType, id, walseq)) } f, err := d.Read(dataType, id) @@ -137,7 +136,7 @@ func (d *DataManager) HasOSTWal(walseq string) (bool, error) { return false, nil } if err != nil { - return false, err + return false, fromOSTError(err) } return true, nil } @@ -145,7 +144,7 @@ func (d *DataManager) HasOSTWal(walseq string) (bool, error) { func (d *DataManager) ReadWal(walseq string) (*WalHeader, error) { walFilef, err := d.ost.ReadObject(d.storageWalStatusFile(walseq) + ".committed") if err != nil { - return nil, err + return nil, fromOSTError(err) } defer walFilef.Close() dec := json.NewDecoder(walFilef) @@ -158,7 +157,8 @@ func (d *DataManager) ReadWal(walseq string) (*WalHeader, error) { } func (d *DataManager) ReadWalData(walFileID string) (io.ReadCloser, error) { - return d.ost.ReadObject(d.storageWalDataFile(walFileID)) + r, err := d.ost.ReadObject(d.storageWalDataFile(walFileID)) + return r, fromOSTError(err) } type WalFile struct { @@ -183,7 +183,7 @@ func (d *DataManager) ListOSTWals(start string) <-chan *WalFile { for object := range d.ost.List(d.storageWalStatusDir()+"/", startPath, true, doneCh) { if object.Err != nil { walCh <- &WalFile{ - Err: object.Err, + Err: fromOSTError(object.Err), } return } @@ -453,7 +453,7 @@ func (d *DataManager) WriteWalAdditionalOps(ctx context.Context, actions []*Acti } } if err := d.ost.WriteObject(walDataFilePath, bytes.NewReader(buf.Bytes()), int64(buf.Len()), true); err != nil { - return nil, err + return nil, fromOSTError(err) } d.log.Debugf("wrote wal file: %s", walDataFilePath) @@ -599,7 +599,7 @@ func (d *DataManager) sync(ctx context.Context) error { walFileCommittedPath := walFilePath + ".committed" if err := d.ost.WriteObject(walFileCommittedPath, bytes.NewReader(headerj), int64(len(headerj)), true); err != nil { - return err + return fromOSTError(err) } d.log.Debugf("updating wal to state %q", WalStatusCommittedStorage) @@ -888,7 +888,7 @@ func (d *DataManager) storageWalCleaner(ctx context.Context) error { for object := range d.ost.List(d.storageWalStatusDir()+"/", "", true, doneCh) { if object.Err != nil { - return err + return fromOSTError(err) } name := path.Base(object.Path) ext := path.Ext(name) @@ -910,7 +910,7 @@ func (d *DataManager) storageWalCleaner(ctx context.Context) error { d.log.Infof("removing %q", walStatusFilePath) if err := d.ost.DeleteObject(walStatusFilePath); err != nil { if !objectstorage.IsNotExist(err) { - return err + return fromOSTError(err) } } @@ -918,7 +918,7 @@ func (d *DataManager) storageWalCleaner(ctx context.Context) error { d.log.Infof("removing %q", object.Path) if err := d.ost.DeleteObject(object.Path); err != nil { if !objectstorage.IsNotExist(err) { - return err + return fromOSTError(err) } } } @@ -929,7 +929,7 @@ func (d *DataManager) storageWalCleaner(ctx context.Context) error { d.log.Infof("removing %q", object.Path) if err := d.ost.DeleteObject(object.Path); err != nil { if !objectstorage.IsNotExist(err) { - return err + return fromOSTError(err) } } } @@ -1049,7 +1049,7 @@ func (d *DataManager) InitEtcd(ctx context.Context, dataStatus *DataStatus) erro writeWal := func(wal *WalFile, prevWalSequence string) error { walFile, err := d.ost.ReadObject(d.storageWalStatusFile(wal.WalSequence) + ".committed") if err != nil { - return err + return fromOSTError(err) } dec := json.NewDecoder(walFile) var header *WalHeader @@ -1200,7 +1200,7 @@ func (d *DataManager) InitEtcd(ctx context.Context, dataStatus *DataStatus) erro walKey := etcdWalKey(walSequence.String()) if err := d.ost.WriteObject(walDataFilePath, bytes.NewReader([]byte{}), 0, true); err != nil { - return err + return fromOSTError(err) } d.log.Debugf("wrote wal file: %s", walDataFilePath) @@ -1216,7 +1216,7 @@ func (d *DataManager) InitEtcd(ctx context.Context, dataStatus *DataStatus) erro } walFileCommittedPath := walFilePath + ".committed" if err := d.ost.WriteObject(walFileCommittedPath, bytes.NewReader(headerj), int64(len(headerj)), true); err != nil { - return err + return fromOSTError(err) } walData := &WalData{ diff --git a/internal/gitsources/agolagit/agolagit.go b/internal/gitsources/agolagit/agolagit.go index f51f998..815aaa8 100644 --- a/internal/gitsources/agolagit/agolagit.go +++ b/internal/gitsources/agolagit/agolagit.go @@ -28,7 +28,7 @@ import ( gitsource "agola.io/agola/internal/gitsources" "agola.io/agola/internal/services/types" - errors "golang.org/x/xerrors" + "agola.io/agola/internal/util" ) var ( @@ -96,20 +96,8 @@ func (c *Client) getResponse(method, path string, query url.Values, header http. return nil, err } - if resp.StatusCode/100 != 2 { - defer resp.Body.Close() - data, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, err - } - - if len(data) <= 1 { - return resp, errors.New(resp.Status) - } - - // TODO(sgotti) use a json error response - - return resp, errors.New(string(data)) + if err := util.ErrFromRemote(resp); err != nil { + return resp, err } return resp, nil diff --git a/internal/services/configstore/action/action.go b/internal/services/configstore/action/action.go index ae6bd59..e8c497b 100644 --- a/internal/services/configstore/action/action.go +++ b/internal/services/configstore/action/action.go @@ -16,10 +16,14 @@ package action import ( "agola.io/agola/internal/datamanager" + "agola.io/agola/internal/db" "agola.io/agola/internal/etcd" "agola.io/agola/internal/services/configstore/readdb" + "agola.io/agola/internal/util" + "agola.io/agola/services/configstore/types" "go.uber.org/zap" + errors "golang.org/x/xerrors" ) type ActionHandler struct { @@ -43,3 +47,30 @@ func NewActionHandler(logger *zap.Logger, readDB *readdb.ReadDB, dm *datamanager func (h *ActionHandler) SetMaintenanceMode(maintenanceMode bool) { h.maintenanceMode = maintenanceMode } + +func (h *ActionHandler) ResolveConfigID(tx *db.Tx, configType types.ConfigType, ref string) (string, error) { + switch configType { + case types.ConfigTypeProjectGroup: + group, err := h.readDB.GetProjectGroup(tx, ref) + if err != nil { + return "", err + } + if group == nil { + return "", util.NewAPIError(util.ErrBadRequest, errors.Errorf("group with ref %q doesn't exists", ref)) + } + return group.ID, nil + + case types.ConfigTypeProject: + project, err := h.readDB.GetProject(tx, ref) + if err != nil { + return "", err + } + if project == nil { + return "", util.NewAPIError(util.ErrBadRequest, errors.Errorf("project with ref %q doesn't exists", ref)) + } + return project.ID, nil + + default: + return "", util.NewAPIError(util.ErrBadRequest, errors.Errorf("unknown config type %q", configType)) + } +} diff --git a/internal/services/configstore/action/maintenance.go b/internal/services/configstore/action/maintenance.go index f71e107..bb66996 100644 --- a/internal/services/configstore/action/maintenance.go +++ b/internal/services/configstore/action/maintenance.go @@ -32,10 +32,10 @@ func (h *ActionHandler) MaintenanceMode(ctx context.Context, enable bool) error } if enable && len(resp.Kvs) > 0 { - return util.NewErrBadRequest(errors.Errorf("maintenance mode already enabled")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("maintenance mode already enabled")) } if !enable && len(resp.Kvs) == 0 { - return util.NewErrBadRequest(errors.Errorf("maintenance mode already disabled")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("maintenance mode already disabled")) } if enable { @@ -67,7 +67,7 @@ func (h *ActionHandler) Export(ctx context.Context, w io.Writer) error { func (h *ActionHandler) Import(ctx context.Context, r io.Reader) error { if !h.maintenanceMode { - return util.NewErrBadRequest(errors.Errorf("not in maintenance mode")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("not in maintenance mode")) } return h.dm.Import(ctx, r) } diff --git a/internal/services/configstore/action/org.go b/internal/services/configstore/action/org.go index 514f405..fdf290d 100644 --- a/internal/services/configstore/action/org.go +++ b/internal/services/configstore/action/org.go @@ -51,7 +51,7 @@ func (h *ActionHandler) GetOrgMembers(ctx context.Context, orgRef string) ([]*Or return err } if org == nil { - return util.NewErrNotExist(errors.Errorf("org %q doesn't exist", orgRef)) + return util.NewAPIError(util.ErrNotExist, errors.Errorf("org %q doesn't exist", orgRef)) } orgUsers, err = h.readDB.GetOrgUsers(tx, org.ID) @@ -71,13 +71,13 @@ func (h *ActionHandler) GetOrgMembers(ctx context.Context, orgRef string) ([]*Or func (h *ActionHandler) CreateOrg(ctx context.Context, org *types.Organization) (*types.Organization, error) { if org.Name == "" { - return nil, util.NewErrBadRequest(errors.Errorf("organization name required")) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("organization name required")) } if !util.ValidateName(org.Name) { - return nil, util.NewErrBadRequest(errors.Errorf("invalid organization name %q", org.Name)) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("invalid organization name %q", org.Name)) } if !types.IsValidVisibility(org.Visibility) { - return nil, util.NewErrBadRequest(errors.Errorf("invalid organization visibility")) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("invalid organization visibility")) } var cgt *datamanager.ChangeGroupsUpdateToken @@ -98,7 +98,7 @@ func (h *ActionHandler) CreateOrg(ctx context.Context, org *types.Organization) return err } if o != nil { - return util.NewErrBadRequest(errors.Errorf("org %q already exists", o.Name)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("org %q already exists", o.Name)) } if org.CreatorUserID != "" { @@ -107,7 +107,7 @@ func (h *ActionHandler) CreateOrg(ctx context.Context, org *types.Organization) return err } if user == nil { - return util.NewErrBadRequest(errors.Errorf("creator user %q doesn't exist", org.CreatorUserID)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("creator user %q doesn't exist", org.CreatorUserID)) } } @@ -190,7 +190,7 @@ func (h *ActionHandler) DeleteOrg(ctx context.Context, orgRef string) error { return err } if org == nil { - return util.NewErrBadRequest(errors.Errorf("org %q doesn't exist", orgRef)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("org %q doesn't exist", orgRef)) } // changegroup is the org id @@ -223,7 +223,7 @@ func (h *ActionHandler) DeleteOrg(ctx context.Context, orgRef string) error { // TODO(sgotti) handle invitation when implemented func (h *ActionHandler) AddOrgMember(ctx context.Context, orgRef, userRef string, role types.MemberRole) (*types.OrganizationMember, error) { if !types.IsValidMemberRole(role) { - return nil, util.NewErrBadRequest(errors.Errorf("invalid role %q", role)) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("invalid role %q", role)) } var org *types.Organization @@ -240,7 +240,7 @@ func (h *ActionHandler) AddOrgMember(ctx context.Context, orgRef, userRef string return err } if org == nil { - return util.NewErrBadRequest(errors.Errorf("org %q doesn't exists", orgRef)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("org %q doesn't exists", orgRef)) } // check existing user user, err = h.readDB.GetUser(tx, userRef) @@ -248,7 +248,7 @@ func (h *ActionHandler) AddOrgMember(ctx context.Context, orgRef, userRef string return err } if user == nil { - return util.NewErrBadRequest(errors.Errorf("user %q doesn't exists", userRef)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user %q doesn't exists", userRef)) } // fetch org member if it already exist @@ -316,7 +316,7 @@ func (h *ActionHandler) RemoveOrgMember(ctx context.Context, orgRef, userRef str return err } if org == nil { - return util.NewErrBadRequest(errors.Errorf("org %q doesn't exists", orgRef)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("org %q doesn't exists", orgRef)) } // check existing user user, err = h.readDB.GetUser(tx, userRef) @@ -324,7 +324,7 @@ func (h *ActionHandler) RemoveOrgMember(ctx context.Context, orgRef, userRef str return err } if user == nil { - return util.NewErrBadRequest(errors.Errorf("user %q doesn't exists", userRef)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user %q doesn't exists", userRef)) } // check that org member exists @@ -333,7 +333,7 @@ func (h *ActionHandler) RemoveOrgMember(ctx context.Context, orgRef, userRef str return err } if orgmember == nil { - return util.NewErrBadRequest(errors.Errorf("orgmember for org %q, user %q doesn't exists", orgRef, userRef)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("orgmember for org %q, user %q doesn't exists", orgRef, userRef)) } cgNames := []string{util.EncodeSha256Hex(fmt.Sprintf("orgmember-%s-%s", org.ID, user.ID))} diff --git a/internal/services/configstore/action/project.go b/internal/services/configstore/action/project.go index 723e5f8..d569703 100644 --- a/internal/services/configstore/action/project.go +++ b/internal/services/configstore/action/project.go @@ -30,35 +30,35 @@ import ( func (h *ActionHandler) ValidateProject(ctx context.Context, project *types.Project) error { if project.Name == "" { - return util.NewErrBadRequest(errors.Errorf("project name required")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project name required")) } if !util.ValidateName(project.Name) { - return util.NewErrBadRequest(errors.Errorf("invalid project name %q", project.Name)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("invalid project name %q", project.Name)) } if project.Parent.ID == "" { - return util.NewErrBadRequest(errors.Errorf("project parent id required")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project parent id required")) } if project.Parent.Type != types.ConfigTypeProjectGroup { - return util.NewErrBadRequest(errors.Errorf("invalid project parent type %q", project.Parent.Type)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("invalid project parent type %q", project.Parent.Type)) } if !types.IsValidVisibility(project.Visibility) { - return util.NewErrBadRequest(errors.Errorf("invalid project visibility")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("invalid project visibility")) } if !types.IsValidRemoteRepositoryConfigType(project.RemoteRepositoryConfigType) { - return util.NewErrBadRequest(errors.Errorf("invalid project remote repository config type %q", project.RemoteRepositoryConfigType)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("invalid project remote repository config type %q", project.RemoteRepositoryConfigType)) } if project.RemoteRepositoryConfigType == types.RemoteRepositoryConfigTypeRemoteSource { if project.RemoteSourceID == "" { - return util.NewErrBadRequest(errors.Errorf("empty remote source id")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("empty remote source id")) } if project.LinkedAccountID == "" { - return util.NewErrBadRequest(errors.Errorf("empty linked account id")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("empty linked account id")) } if project.RepositoryID == "" { - return util.NewErrBadRequest(errors.Errorf("empty remote repository id")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("empty remote repository id")) } if project.RepositoryPath == "" { - return util.NewErrBadRequest(errors.Errorf("empty remote repository path")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("empty remote repository path")) } } return nil @@ -76,7 +76,7 @@ func (h *ActionHandler) GetProject(ctx context.Context, projectRef string) (*typ } if project == nil { - return nil, util.NewErrNotExist(errors.Errorf("project %q doesn't exist", projectRef)) + return nil, util.NewAPIError(util.ErrNotExist, errors.Errorf("project %q doesn't exist", projectRef)) } return project, nil @@ -97,7 +97,7 @@ func (h *ActionHandler) CreateProject(ctx context.Context, project *types.Projec return err } if group == nil { - return util.NewErrBadRequest(errors.Errorf("project group with id %q doesn't exist", project.Parent.ID)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project group with id %q doesn't exist", project.Parent.ID)) } project.Parent.ID = group.ID @@ -121,7 +121,7 @@ func (h *ActionHandler) CreateProject(ctx context.Context, project *types.Projec return err } if p != nil { - return util.NewErrBadRequest(errors.Errorf("project with name %q, path %q already exists", p.Name, pp)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project with name %q, path %q already exists", p.Name, pp)) } if project.RemoteRepositoryConfigType == types.RemoteRepositoryConfigTypeRemoteSource { @@ -131,14 +131,14 @@ func (h *ActionHandler) CreateProject(ctx context.Context, project *types.Projec return errors.Errorf("failed to get user with linked account id %q: %w", project.LinkedAccountID, err) } if user == nil { - return util.NewErrBadRequest(errors.Errorf("user for linked account %q doesn't exist", project.LinkedAccountID)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user for linked account %q doesn't exist", project.LinkedAccountID)) } la, ok := user.LinkedAccounts[project.LinkedAccountID] if !ok { - return util.NewErrBadRequest(errors.Errorf("linked account id %q for user %q doesn't exist", project.LinkedAccountID, user.Name)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("linked account id %q for user %q doesn't exist", project.LinkedAccountID, user.Name)) } if la.RemoteSourceID != project.RemoteSourceID { - return util.NewErrBadRequest(errors.Errorf("linked account id %q remote source %q different than project remote source %q", project.LinkedAccountID, la.RemoteSourceID, project.RemoteSourceID)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("linked account id %q remote source %q different than project remote source %q", project.LinkedAccountID, la.RemoteSourceID, project.RemoteSourceID)) } } @@ -193,11 +193,11 @@ func (h *ActionHandler) UpdateProject(ctx context.Context, req *UpdateProjectReq return err } if p == nil { - return util.NewErrBadRequest(errors.Errorf("project with ref %q doesn't exist", req.ProjectRef)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project with ref %q doesn't exist", req.ProjectRef)) } // check that the project.ID matches if p.ID != req.Project.ID { - return util.NewErrBadRequest(errors.Errorf("project with ref %q has a different id", req.ProjectRef)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project with ref %q has a different id", req.ProjectRef)) } // check parent project group exists @@ -206,7 +206,7 @@ func (h *ActionHandler) UpdateProject(ctx context.Context, req *UpdateProjectReq return err } if group == nil { - return util.NewErrBadRequest(errors.Errorf("project group with id %q doesn't exist", req.Project.Parent.ID)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project group with id %q doesn't exist", req.Project.Parent.ID)) } req.Project.Parent.ID = group.ID @@ -223,7 +223,7 @@ func (h *ActionHandler) UpdateProject(ctx context.Context, req *UpdateProjectReq return err } if ap != nil { - return util.NewErrBadRequest(errors.Errorf("project with name %q, path %q already exists", req.Project.Name, pp)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project with name %q, path %q already exists", req.Project.Name, pp)) } } @@ -239,7 +239,7 @@ func (h *ActionHandler) UpdateProject(ctx context.Context, req *UpdateProjectReq return err } if curGroup == nil { - return util.NewErrBadRequest(errors.Errorf("project group with id %q doesn't exist", p.Parent.ID)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project group with id %q doesn't exist", p.Parent.ID)) } curGroupPath, err := h.readDB.GetProjectGroupPath(tx, curGroup) if err != nil { @@ -262,14 +262,14 @@ func (h *ActionHandler) UpdateProject(ctx context.Context, req *UpdateProjectReq return errors.Errorf("failed to get user with linked account id %q: %w", req.Project.LinkedAccountID, err) } if user == nil { - return util.NewErrBadRequest(errors.Errorf("user for linked account %q doesn't exist", req.Project.LinkedAccountID)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user for linked account %q doesn't exist", req.Project.LinkedAccountID)) } la, ok := user.LinkedAccounts[req.Project.LinkedAccountID] if !ok { - return util.NewErrBadRequest(errors.Errorf("linked account id %q for user %q doesn't exist", req.Project.LinkedAccountID, user.Name)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("linked account id %q for user %q doesn't exist", req.Project.LinkedAccountID, user.Name)) } if la.RemoteSourceID != req.Project.RemoteSourceID { - return util.NewErrBadRequest(errors.Errorf("linked account id %q remote source %q different than project remote source %q", req.Project.LinkedAccountID, la.RemoteSourceID, req.Project.RemoteSourceID)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("linked account id %q remote source %q different than project remote source %q", req.Project.LinkedAccountID, la.RemoteSourceID, req.Project.RemoteSourceID)) } } @@ -311,7 +311,7 @@ func (h *ActionHandler) DeleteProject(ctx context.Context, projectRef string) er return err } if project == nil { - return util.NewErrBadRequest(errors.Errorf("project %q doesn't exist", projectRef)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project %q doesn't exist", projectRef)) } // changegroup is the project id. diff --git a/internal/services/configstore/action/projectgroup.go b/internal/services/configstore/action/projectgroup.go index ef7f8a3..14a919a 100644 --- a/internal/services/configstore/action/projectgroup.go +++ b/internal/services/configstore/action/projectgroup.go @@ -41,7 +41,7 @@ func (h *ActionHandler) GetProjectGroup(ctx context.Context, projectGroupRef str } if projectGroup == nil { - return nil, util.NewErrNotExist(errors.Errorf("project group %q doesn't exist", projectGroupRef)) + return nil, util.NewAPIError(util.ErrNotExist, errors.Errorf("project group %q doesn't exist", projectGroupRef)) } return projectGroup, nil @@ -57,7 +57,7 @@ func (h *ActionHandler) GetProjectGroupSubgroups(ctx context.Context, projectGro } if projectGroup == nil { - return util.NewErrNotExist(errors.Errorf("project group %q doesn't exist", projectGroupRef)) + return util.NewAPIError(util.ErrNotExist, errors.Errorf("project group %q doesn't exist", projectGroupRef)) } projectGroups, err = h.readDB.GetProjectGroupSubgroups(tx, projectGroup.ID) @@ -80,7 +80,7 @@ func (h *ActionHandler) GetProjectGroupProjects(ctx context.Context, projectGrou } if projectGroup == nil { - return util.NewErrNotExist(errors.Errorf("project group %q doesn't exist", projectGroupRef)) + return util.NewAPIError(util.ErrNotExist, errors.Errorf("project group %q doesn't exist", projectGroupRef)) } projects, err = h.readDB.GetProjectGroupProjects(tx, projectGroup.ID) @@ -96,28 +96,28 @@ func (h *ActionHandler) ValidateProjectGroup(ctx context.Context, projectGroup * if projectGroup.Parent.Type != types.ConfigTypeProjectGroup && projectGroup.Parent.Type != types.ConfigTypeOrg && projectGroup.Parent.Type != types.ConfigTypeUser { - return util.NewErrBadRequest(errors.Errorf("invalid project group parent type %q", projectGroup.Parent.Type)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("invalid project group parent type %q", projectGroup.Parent.Type)) } if projectGroup.Parent.ID == "" { - return util.NewErrBadRequest(errors.Errorf("project group parent id required")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project group parent id required")) } // if the project group is a root project group the name must be empty if projectGroup.Parent.Type == types.ConfigTypeOrg || projectGroup.Parent.Type == types.ConfigTypeUser { if projectGroup.Name != "" { - return util.NewErrBadRequest(errors.Errorf("project group name for root project group must be empty")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project group name for root project group must be empty")) } } else { if projectGroup.Name == "" { - return util.NewErrBadRequest(errors.Errorf("project group name required")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project group name required")) } if !util.ValidateName(projectGroup.Name) { - return util.NewErrBadRequest(errors.Errorf("invalid project group name %q", projectGroup.Name)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("invalid project group name %q", projectGroup.Name)) } } if !types.IsValidVisibility(projectGroup.Visibility) { - return util.NewErrBadRequest(errors.Errorf("invalid project group visibility")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("invalid project group visibility")) } return nil @@ -129,7 +129,7 @@ func (h *ActionHandler) CreateProjectGroup(ctx context.Context, projectGroup *ty } if projectGroup.Parent.Type != types.ConfigTypeProjectGroup { - return nil, util.NewErrBadRequest(errors.Errorf("wrong project group parent type %q", projectGroup.Parent.Type)) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("wrong project group parent type %q", projectGroup.Parent.Type)) } var cgt *datamanager.ChangeGroupsUpdateToken @@ -141,7 +141,7 @@ func (h *ActionHandler) CreateProjectGroup(ctx context.Context, projectGroup *ty return err } if parentProjectGroup == nil { - return util.NewErrBadRequest(errors.Errorf("project group with id %q doesn't exist", projectGroup.Parent.ID)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project group with id %q doesn't exist", projectGroup.Parent.ID)) } // TODO(sgotti) now we are doing a very ugly thing setting the request // projectgroup parent ID that can be both an ID or a ref. Then we are fixing @@ -168,7 +168,7 @@ func (h *ActionHandler) CreateProjectGroup(ctx context.Context, projectGroup *ty return err } if pg != nil { - return util.NewErrBadRequest(errors.Errorf("project group with name %q, path %q already exists", pg.Name, pp)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project group with name %q, path %q already exists", pg.Name, pp)) } return nil }) @@ -218,15 +218,15 @@ func (h *ActionHandler) UpdateProjectGroup(ctx context.Context, req *UpdateProje return err } if pg == nil { - return util.NewErrBadRequest(errors.Errorf("project group with ref %q doesn't exist", req.ProjectGroupRef)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project group with ref %q doesn't exist", req.ProjectGroupRef)) } // check that the project group ID matches if pg.ID != req.ProjectGroup.ID { - return util.NewErrBadRequest(errors.Errorf("project group with ref %q has a different id", req.ProjectGroupRef)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project group with ref %q has a different id", req.ProjectGroupRef)) } if pg.Parent.Type != req.ProjectGroup.Parent.Type { - return util.NewErrBadRequest(errors.Errorf("changing project group parent type isn't supported")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("changing project group parent type isn't supported")) } switch req.ProjectGroup.Parent.Type { @@ -235,7 +235,7 @@ func (h *ActionHandler) UpdateProjectGroup(ctx context.Context, req *UpdateProje case types.ConfigTypeUser: // Cannot update root project group parent if pg.Parent.Type != req.ProjectGroup.Parent.Type || pg.Parent.ID != req.ProjectGroup.Parent.ID { - return util.NewErrBadRequest(errors.Errorf("cannot change root project group parent type or id")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("cannot change root project group parent type or id")) } // if the project group is a root project group force the name to be empty req.ProjectGroup.Name = "" @@ -247,7 +247,7 @@ func (h *ActionHandler) UpdateProjectGroup(ctx context.Context, req *UpdateProje return err } if group == nil { - return util.NewErrBadRequest(errors.Errorf("project group with id %q doesn't exist", req.ProjectGroup.Parent.ID)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project group with id %q doesn't exist", req.ProjectGroup.Parent.ID)) } // TODO(sgotti) now we are doing a very ugly thing setting the request // projectgroup parent ID that can be both an ID or a ref. Then we are fixing @@ -274,11 +274,11 @@ func (h *ActionHandler) UpdateProjectGroup(ctx context.Context, req *UpdateProje return err } if ap != nil { - return util.NewErrBadRequest(errors.Errorf("project group with name %q, path %q already exists", req.ProjectGroup.Name, pgp)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project group with name %q, path %q already exists", req.ProjectGroup.Name, pgp)) } // Cannot move inside itself or a child project group if strings.HasPrefix(pgp, curPGP+"/") { - return util.NewErrBadRequest(errors.Errorf("cannot move project group inside itself or child project group")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("cannot move project group inside itself or child project group")) } } @@ -334,13 +334,13 @@ func (h *ActionHandler) DeleteProjectGroup(ctx context.Context, projectGroupRef return err } if projectGroup == nil { - return util.NewErrBadRequest(errors.Errorf("project group %q doesn't exist", projectGroupRef)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("project group %q doesn't exist", projectGroupRef)) } // cannot delete root project group if projectGroup.Parent.Type == types.ConfigTypeOrg || projectGroup.Parent.Type == types.ConfigTypeUser { - return util.NewErrBadRequest(errors.Errorf("cannot delete root project group")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("cannot delete root project group")) } // changegroup is the project group id. diff --git a/internal/services/configstore/action/remotesource.go b/internal/services/configstore/action/remotesource.go index 8091d0e..0957a7b 100644 --- a/internal/services/configstore/action/remotesource.go +++ b/internal/services/configstore/action/remotesource.go @@ -29,35 +29,35 @@ import ( func (h *ActionHandler) ValidateRemoteSource(ctx context.Context, remoteSource *types.RemoteSource) error { if remoteSource.Name == "" { - return util.NewErrBadRequest(errors.Errorf("remotesource name required")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("remotesource name required")) } if !util.ValidateName(remoteSource.Name) { - return util.NewErrBadRequest(errors.Errorf("invalid remotesource name %q", remoteSource.Name)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("invalid remotesource name %q", remoteSource.Name)) } if remoteSource.Name == "" { - return util.NewErrBadRequest(errors.Errorf("remotesource name required")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("remotesource name required")) } if remoteSource.APIURL == "" { - return util.NewErrBadRequest(errors.Errorf("remotesource api url required")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("remotesource api url required")) } if remoteSource.Type == "" { - return util.NewErrBadRequest(errors.Errorf("remotesource type required")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("remotesource type required")) } if remoteSource.AuthType == "" { - return util.NewErrBadRequest(errors.Errorf("remotesource auth type required")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("remotesource auth type required")) } // validate if the remotesource type supports the required auth type if !types.SourceSupportsAuthType(types.RemoteSourceType(remoteSource.Type), types.RemoteSourceAuthType(remoteSource.AuthType)) { - return util.NewErrBadRequest(errors.Errorf("remotesource type %q doesn't support auth type %q", remoteSource.Type, remoteSource.AuthType)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("remotesource type %q doesn't support auth type %q", remoteSource.Type, remoteSource.AuthType)) } if remoteSource.AuthType == types.RemoteSourceAuthTypeOauth2 { if remoteSource.Oauth2ClientID == "" { - return util.NewErrBadRequest(errors.Errorf("remotesource oauth2clientid required for auth type %q", types.RemoteSourceAuthTypeOauth2)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("remotesource oauth2clientid required for auth type %q", types.RemoteSourceAuthTypeOauth2)) } if remoteSource.Oauth2ClientSecret == "" { - return util.NewErrBadRequest(errors.Errorf("remotesource oauth2clientsecret required for auth type %q", types.RemoteSourceAuthTypeOauth2)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("remotesource oauth2clientsecret required for auth type %q", types.RemoteSourceAuthTypeOauth2)) } } @@ -87,7 +87,7 @@ func (h *ActionHandler) CreateRemoteSource(ctx context.Context, remoteSource *ty return err } if u != nil { - return util.NewErrBadRequest(errors.Errorf("remotesource %q already exists", u.Name)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("remotesource %q already exists", u.Name)) } return nil }) @@ -138,7 +138,7 @@ func (h *ActionHandler) UpdateRemoteSource(ctx context.Context, req *UpdateRemot return err } if curRemoteSource == nil { - return util.NewErrBadRequest(errors.Errorf("remotesource with ref %q doesn't exist", req.RemoteSourceRef)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("remotesource with ref %q doesn't exist", req.RemoteSourceRef)) } if curRemoteSource.Name != req.RemoteSource.Name { @@ -148,7 +148,7 @@ func (h *ActionHandler) UpdateRemoteSource(ctx context.Context, req *UpdateRemot return err } if u != nil { - return util.NewErrBadRequest(errors.Errorf("remotesource %q already exists", u.Name)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("remotesource %q already exists", u.Name)) } } @@ -199,7 +199,7 @@ func (h *ActionHandler) DeleteRemoteSource(ctx context.Context, remoteSourceName return err } if remoteSource == nil { - return util.NewErrBadRequest(errors.Errorf("remotesource %q doesn't exist", remoteSourceName)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("remotesource %q doesn't exist", remoteSourceName)) } // changegroup is the remotesource id diff --git a/internal/services/configstore/action/secret.go b/internal/services/configstore/action/secret.go index 4b236ea..8c805cb 100644 --- a/internal/services/configstore/action/secret.go +++ b/internal/services/configstore/action/secret.go @@ -39,7 +39,7 @@ func (h *ActionHandler) GetSecret(ctx context.Context, secretID string) (*types. } if secret == nil { - return nil, util.NewErrNotExist(errors.Errorf("secret %q doesn't exist", secretID)) + return nil, util.NewAPIError(util.ErrNotExist, errors.Errorf("secret %q doesn't exist", secretID)) } return secret, nil @@ -48,7 +48,7 @@ func (h *ActionHandler) GetSecret(ctx context.Context, secretID string) (*types. func (h *ActionHandler) GetSecrets(ctx context.Context, parentType types.ConfigType, parentRef string, tree bool) ([]*types.Secret, error) { var secrets []*types.Secret err := h.readDB.Do(ctx, func(tx *db.Tx) error { - parentID, err := h.readDB.ResolveConfigID(tx, parentType, parentRef) + parentID, err := h.ResolveConfigID(tx, parentType, parentRef) if err != nil { return err } @@ -68,28 +68,28 @@ func (h *ActionHandler) GetSecrets(ctx context.Context, parentType types.ConfigT func (h *ActionHandler) ValidateSecret(ctx context.Context, secret *types.Secret) error { if secret.Name == "" { - return util.NewErrBadRequest(errors.Errorf("secret name required")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("secret name required")) } if !util.ValidateName(secret.Name) { - return util.NewErrBadRequest(errors.Errorf("invalid secret name %q", secret.Name)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("invalid secret name %q", secret.Name)) } if secret.Type != types.SecretTypeInternal { - return util.NewErrBadRequest(errors.Errorf("invalid secret type %q", secret.Type)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("invalid secret type %q", secret.Type)) } switch secret.Type { case types.SecretTypeInternal: if len(secret.Data) == 0 { - return util.NewErrBadRequest(errors.Errorf("empty secret data")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("empty secret data")) } } if secret.Parent.Type == "" { - return util.NewErrBadRequest(errors.Errorf("secret parent type required")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("secret parent type required")) } if secret.Parent.ID == "" { - return util.NewErrBadRequest(errors.Errorf("secret parentid required")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("secret parentid required")) } if secret.Parent.Type != types.ConfigTypeProject && secret.Parent.Type != types.ConfigTypeProjectGroup { - return util.NewErrBadRequest(errors.Errorf("invalid secret parent type %q", secret.Parent.Type)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("invalid secret parent type %q", secret.Parent.Type)) } return nil @@ -112,7 +112,7 @@ func (h *ActionHandler) CreateSecret(ctx context.Context, secret *types.Secret) return err } - parentID, err := h.readDB.ResolveConfigID(tx, secret.Parent.Type, secret.Parent.ID) + parentID, err := h.ResolveConfigID(tx, secret.Parent.Type, secret.Parent.ID) if err != nil { return err } @@ -124,7 +124,7 @@ func (h *ActionHandler) CreateSecret(ctx context.Context, secret *types.Secret) return err } if s != nil { - return util.NewErrBadRequest(errors.Errorf("secret with name %q for %s with id %q already exists", secret.Name, secret.Parent.Type, secret.Parent.ID)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("secret with name %q for %s with id %q already exists", secret.Name, secret.Parent.Type, secret.Parent.ID)) } return nil @@ -171,7 +171,7 @@ func (h *ActionHandler) UpdateSecret(ctx context.Context, req *UpdateSecretReque err := h.readDB.Do(ctx, func(tx *db.Tx) error { var err error - parentID, err := h.readDB.ResolveConfigID(tx, req.Secret.Parent.Type, req.Secret.Parent.ID) + parentID, err := h.ResolveConfigID(tx, req.Secret.Parent.Type, req.Secret.Parent.ID) if err != nil { return err } @@ -183,7 +183,7 @@ func (h *ActionHandler) UpdateSecret(ctx context.Context, req *UpdateSecretReque return err } if curSecret == nil { - return util.NewErrBadRequest(errors.Errorf("secret with name %q for %s with id %q doesn't exists", req.SecretName, req.Secret.Parent.Type, req.Secret.Parent.ID)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("secret with name %q for %s with id %q doesn't exists", req.SecretName, req.Secret.Parent.Type, req.Secret.Parent.ID)) } if curSecret.Name != req.Secret.Name { @@ -193,7 +193,7 @@ func (h *ActionHandler) UpdateSecret(ctx context.Context, req *UpdateSecretReque return err } if u != nil { - return util.NewErrBadRequest(errors.Errorf("secret with name %q for %s with id %q already exists", req.Secret.Name, req.Secret.Parent.Type, req.Secret.Parent.ID)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("secret with name %q for %s with id %q already exists", req.Secret.Name, req.Secret.Parent.Type, req.Secret.Parent.ID)) } } @@ -240,7 +240,7 @@ func (h *ActionHandler) DeleteSecret(ctx context.Context, parentType types.Confi // must do all the checks in a single transaction to avoid concurrent changes err := h.readDB.Do(ctx, func(tx *db.Tx) error { var err error - parentID, err := h.readDB.ResolveConfigID(tx, parentType, parentRef) + parentID, err := h.ResolveConfigID(tx, parentType, parentRef) if err != nil { return err } @@ -251,7 +251,7 @@ func (h *ActionHandler) DeleteSecret(ctx context.Context, parentType types.Confi return err } if secret == nil { - return util.NewErrBadRequest(errors.Errorf("secret with name %q doesn't exist", secretName)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("secret with name %q doesn't exist", secretName)) } // changegroup is the secret id diff --git a/internal/services/configstore/action/user.go b/internal/services/configstore/action/user.go index c6962fb..f6eeccf 100644 --- a/internal/services/configstore/action/user.go +++ b/internal/services/configstore/action/user.go @@ -37,10 +37,10 @@ type CreateUserRequest struct { func (h *ActionHandler) CreateUser(ctx context.Context, req *CreateUserRequest) (*types.User, error) { if req.UserName == "" { - return nil, util.NewErrBadRequest(errors.Errorf("user name required")) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("user name required")) } if !util.ValidateName(req.UserName) { - return nil, util.NewErrBadRequest(errors.Errorf("invalid user name %q", req.UserName)) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("invalid user name %q", req.UserName)) } var cgt *datamanager.ChangeGroupsUpdateToken @@ -63,7 +63,7 @@ func (h *ActionHandler) CreateUser(ctx context.Context, req *CreateUserRequest) return err } if u != nil { - return util.NewErrBadRequest(errors.Errorf("user with name %q already exists", u.Name)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user with name %q already exists", u.Name)) } if req.CreateUserLARequest != nil { @@ -72,14 +72,14 @@ func (h *ActionHandler) CreateUser(ctx context.Context, req *CreateUserRequest) return err } if rs == nil { - return util.NewErrBadRequest(errors.Errorf("remote source %q doesn't exist", req.CreateUserLARequest.RemoteSourceName)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("remote source %q doesn't exist", req.CreateUserLARequest.RemoteSourceName)) } user, err := h.readDB.GetUserByLinkedAccountRemoteUserIDandSource(tx, req.CreateUserLARequest.RemoteUserID, rs.ID) if err != nil { return errors.Errorf("failed to get user for remote user id %q and remote source %q: %w", req.CreateUserLARequest.RemoteUserID, rs.ID, err) } if user != nil { - return util.NewErrBadRequest(errors.Errorf("user for remote user id %q for remote source %q already exists", req.CreateUserLARequest.RemoteUserID, req.CreateUserLARequest.RemoteSourceName)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user for remote user id %q for remote source %q already exists", req.CreateUserLARequest.RemoteUserID, req.CreateUserLARequest.RemoteSourceName)) } } return nil @@ -165,7 +165,7 @@ func (h *ActionHandler) DeleteUser(ctx context.Context, userRef string) error { return err } if user == nil { - return util.NewErrBadRequest(errors.Errorf("user %q doesn't exist", userRef)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user %q doesn't exist", userRef)) } // changegroup is the userid @@ -213,7 +213,7 @@ func (h *ActionHandler) UpdateUser(ctx context.Context, req *UpdateUserRequest) return err } if user == nil { - return util.NewErrBadRequest(errors.Errorf("user %q doesn't exist", req.UserRef)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user %q doesn't exist", req.UserRef)) } cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames) @@ -228,7 +228,7 @@ func (h *ActionHandler) UpdateUser(ctx context.Context, req *UpdateUserRequest) return err } if u != nil { - return util.NewErrBadRequest(errors.Errorf("user with name %q already exists", u.Name)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user with name %q already exists", u.Name)) } // changegroup is the username (and in future the email) to ensure no // concurrent user creation/modification using the same name @@ -277,10 +277,10 @@ type CreateUserLARequest struct { func (h *ActionHandler) CreateUserLA(ctx context.Context, req *CreateUserLARequest) (*types.LinkedAccount, error) { if req.UserRef == "" { - return nil, util.NewErrBadRequest(errors.Errorf("user ref required")) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("user ref required")) } if req.RemoteSourceName == "" { - return nil, util.NewErrBadRequest(errors.Errorf("remote source name required")) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("remote source name required")) } var user *types.User @@ -296,7 +296,7 @@ func (h *ActionHandler) CreateUserLA(ctx context.Context, req *CreateUserLAReque return err } if user == nil { - return util.NewErrBadRequest(errors.Errorf("user %q doesn't exist", req.UserRef)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user %q doesn't exist", req.UserRef)) } // changegroup is the userid @@ -311,7 +311,7 @@ func (h *ActionHandler) CreateUserLA(ctx context.Context, req *CreateUserLAReque return err } if rs == nil { - return util.NewErrBadRequest(errors.Errorf("remote source %q doesn't exist", req.RemoteSourceName)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("remote source %q doesn't exist", req.RemoteSourceName)) } user, err := h.readDB.GetUserByLinkedAccountRemoteUserIDandSource(tx, req.RemoteUserID, rs.ID) @@ -319,7 +319,7 @@ func (h *ActionHandler) CreateUserLA(ctx context.Context, req *CreateUserLAReque return errors.Errorf("failed to get user for remote user id %q and remote source %q: %w", req.RemoteUserID, rs.ID, err) } if user != nil { - return util.NewErrBadRequest(errors.Errorf("user for remote user id %q for remote source %q already exists", req.RemoteUserID, req.RemoteSourceName)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user for remote user id %q for remote source %q already exists", req.RemoteUserID, req.RemoteSourceName)) } return nil }) @@ -363,10 +363,10 @@ func (h *ActionHandler) CreateUserLA(ctx context.Context, req *CreateUserLAReque func (h *ActionHandler) DeleteUserLA(ctx context.Context, userRef, laID string) error { if userRef == "" { - return util.NewErrBadRequest(errors.Errorf("user ref required")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user ref required")) } if laID == "" { - return util.NewErrBadRequest(errors.Errorf("user linked account id required")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user linked account id required")) } var user *types.User @@ -381,7 +381,7 @@ func (h *ActionHandler) DeleteUserLA(ctx context.Context, userRef, laID string) return err } if user == nil { - return util.NewErrBadRequest(errors.Errorf("user %q doesn't exist", userRef)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user %q doesn't exist", userRef)) } // changegroup is the userid @@ -399,7 +399,7 @@ func (h *ActionHandler) DeleteUserLA(ctx context.Context, userRef, laID string) _, ok := user.LinkedAccounts[laID] if !ok { - return util.NewErrBadRequest(errors.Errorf("linked account id %q for user %q doesn't exist", laID, userRef)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("linked account id %q for user %q doesn't exist", laID, userRef)) } delete(user.LinkedAccounts, laID) @@ -435,7 +435,7 @@ type UpdateUserLARequest struct { func (h *ActionHandler) UpdateUserLA(ctx context.Context, req *UpdateUserLARequest) (*types.LinkedAccount, error) { if req.UserRef == "" { - return nil, util.NewErrBadRequest(errors.Errorf("user ref required")) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("user ref required")) } var user *types.User @@ -451,7 +451,7 @@ func (h *ActionHandler) UpdateUserLA(ctx context.Context, req *UpdateUserLAReque return err } if user == nil { - return util.NewErrBadRequest(errors.Errorf("user %q doesn't exist", req.UserRef)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user %q doesn't exist", req.UserRef)) } // changegroup is the userid @@ -463,7 +463,7 @@ func (h *ActionHandler) UpdateUserLA(ctx context.Context, req *UpdateUserLAReque la, ok := user.LinkedAccounts[req.LinkedAccountID] if !ok { - return util.NewErrBadRequest(errors.Errorf("linked account id %q for user %q doesn't exist", req.LinkedAccountID, user.Name)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("linked account id %q for user %q doesn't exist", req.LinkedAccountID, user.Name)) } rs, err = h.readDB.GetRemoteSource(tx, la.RemoteSourceID) @@ -471,7 +471,7 @@ func (h *ActionHandler) UpdateUserLA(ctx context.Context, req *UpdateUserLAReque return err } if rs == nil { - return util.NewErrBadRequest(errors.Errorf("remote source with id %q doesn't exist", la.RemoteSourceID)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("remote source with id %q doesn't exist", la.RemoteSourceID)) } return nil }) @@ -507,10 +507,10 @@ func (h *ActionHandler) UpdateUserLA(ctx context.Context, req *UpdateUserLAReque func (h *ActionHandler) CreateUserToken(ctx context.Context, userRef, tokenName string) (string, error) { if userRef == "" { - return "", util.NewErrBadRequest(errors.Errorf("user ref required")) + return "", util.NewAPIError(util.ErrBadRequest, errors.Errorf("user ref required")) } if tokenName == "" { - return "", util.NewErrBadRequest(errors.Errorf("token name required")) + return "", util.NewAPIError(util.ErrBadRequest, errors.Errorf("token name required")) } var user *types.User @@ -525,7 +525,7 @@ func (h *ActionHandler) CreateUserToken(ctx context.Context, userRef, tokenName return err } if user == nil { - return util.NewErrBadRequest(errors.Errorf("user %q doesn't exist", userRef)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user %q doesn't exist", userRef)) } // changegroup is the userid @@ -542,7 +542,7 @@ func (h *ActionHandler) CreateUserToken(ctx context.Context, userRef, tokenName } if user.Tokens != nil { if _, ok := user.Tokens[tokenName]; ok { - return "", util.NewErrBadRequest(errors.Errorf("token %q for user %q already exists", tokenName, userRef)) + return "", util.NewAPIError(util.ErrBadRequest, errors.Errorf("token %q for user %q already exists", tokenName, userRef)) } } @@ -572,10 +572,10 @@ func (h *ActionHandler) CreateUserToken(ctx context.Context, userRef, tokenName func (h *ActionHandler) DeleteUserToken(ctx context.Context, userRef, tokenName string) error { if userRef == "" { - return util.NewErrBadRequest(errors.Errorf("user ref required")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user ref required")) } if tokenName == "" { - return util.NewErrBadRequest(errors.Errorf("token name required")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("token name required")) } var user *types.User @@ -590,7 +590,7 @@ func (h *ActionHandler) DeleteUserToken(ctx context.Context, userRef, tokenName return err } if user == nil { - return util.NewErrBadRequest(errors.Errorf("user %q doesn't exist", userRef)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user %q doesn't exist", userRef)) } // changegroup is the userid @@ -608,7 +608,7 @@ func (h *ActionHandler) DeleteUserToken(ctx context.Context, userRef, tokenName _, ok := user.Tokens[tokenName] if !ok { - return util.NewErrBadRequest(errors.Errorf("token %q for user %q doesn't exist", tokenName, userRef)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("token %q for user %q doesn't exist", tokenName, userRef)) } delete(user.Tokens, tokenName) @@ -651,7 +651,7 @@ func (h *ActionHandler) GetUserOrgs(ctx context.Context, userRef string) ([]*Use return err } if user == nil { - return util.NewErrNotExist(errors.Errorf("user %q doesn't exist", userRef)) + return util.NewAPIError(util.ErrNotExist, errors.Errorf("user %q doesn't exist", userRef)) } userOrgs, err = h.readDB.GetUserOrgs(tx, user.ID) diff --git a/internal/services/configstore/action/variable.go b/internal/services/configstore/action/variable.go index 5b911fd..fee92e1 100644 --- a/internal/services/configstore/action/variable.go +++ b/internal/services/configstore/action/variable.go @@ -30,7 +30,7 @@ import ( func (h *ActionHandler) GetVariables(ctx context.Context, parentType types.ConfigType, parentRef string, tree bool) ([]*types.Variable, error) { var variables []*types.Variable err := h.readDB.Do(ctx, func(tx *db.Tx) error { - parentID, err := h.readDB.ResolveConfigID(tx, parentType, parentRef) + parentID, err := h.ResolveConfigID(tx, parentType, parentRef) if err != nil { return err } @@ -50,22 +50,22 @@ func (h *ActionHandler) GetVariables(ctx context.Context, parentType types.Confi func (h *ActionHandler) ValidateVariable(ctx context.Context, variable *types.Variable) error { if variable.Name == "" { - return util.NewErrBadRequest(errors.Errorf("variable name required")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("variable name required")) } if !util.ValidateName(variable.Name) { - return util.NewErrBadRequest(errors.Errorf("invalid variable name %q", variable.Name)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("invalid variable name %q", variable.Name)) } if len(variable.Values) == 0 { - return util.NewErrBadRequest(errors.Errorf("variable values required")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("variable values required")) } if variable.Parent.Type == "" { - return util.NewErrBadRequest(errors.Errorf("variable parent type required")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("variable parent type required")) } if variable.Parent.ID == "" { - return util.NewErrBadRequest(errors.Errorf("variable parent id required")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("variable parent id required")) } if variable.Parent.Type != types.ConfigTypeProject && variable.Parent.Type != types.ConfigTypeProjectGroup { - return util.NewErrBadRequest(errors.Errorf("invalid variable parent type %q", variable.Parent.Type)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("invalid variable parent type %q", variable.Parent.Type)) } return nil @@ -88,7 +88,7 @@ func (h *ActionHandler) CreateVariable(ctx context.Context, variable *types.Vari return err } - parentID, err := h.readDB.ResolveConfigID(tx, variable.Parent.Type, variable.Parent.ID) + parentID, err := h.ResolveConfigID(tx, variable.Parent.Type, variable.Parent.ID) if err != nil { return err } @@ -100,7 +100,7 @@ func (h *ActionHandler) CreateVariable(ctx context.Context, variable *types.Vari return err } if s != nil { - return util.NewErrBadRequest(errors.Errorf("variable with name %q for %s with id %q already exists", variable.Name, variable.Parent.Type, variable.Parent.ID)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("variable with name %q for %s with id %q already exists", variable.Name, variable.Parent.Type, variable.Parent.ID)) } return nil @@ -147,7 +147,7 @@ func (h *ActionHandler) UpdateVariable(ctx context.Context, req *UpdateVariableR err := h.readDB.Do(ctx, func(tx *db.Tx) error { var err error - parentID, err := h.readDB.ResolveConfigID(tx, req.Variable.Parent.Type, req.Variable.Parent.ID) + parentID, err := h.ResolveConfigID(tx, req.Variable.Parent.Type, req.Variable.Parent.ID) if err != nil { return err } @@ -159,7 +159,7 @@ func (h *ActionHandler) UpdateVariable(ctx context.Context, req *UpdateVariableR return err } if curVariable == nil { - return util.NewErrBadRequest(errors.Errorf("variable with name %q for %s with id %q doesn't exists", req.VariableName, req.Variable.Parent.Type, req.Variable.Parent.ID)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("variable with name %q for %s with id %q doesn't exists", req.VariableName, req.Variable.Parent.Type, req.Variable.Parent.ID)) } if curVariable.Name != req.Variable.Name { @@ -169,7 +169,7 @@ func (h *ActionHandler) UpdateVariable(ctx context.Context, req *UpdateVariableR return err } if u != nil { - return util.NewErrBadRequest(errors.Errorf("variable with name %q for %s with id %q already exists", req.Variable.Name, req.Variable.Parent.Type, req.Variable.Parent.ID)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("variable with name %q for %s with id %q already exists", req.Variable.Name, req.Variable.Parent.Type, req.Variable.Parent.ID)) } } @@ -216,7 +216,7 @@ func (h *ActionHandler) DeleteVariable(ctx context.Context, parentType types.Con // must do all the checks in a single transaction to avoid concurrent changes err := h.readDB.Do(ctx, func(tx *db.Tx) error { var err error - parentID, err := h.readDB.ResolveConfigID(tx, parentType, parentRef) + parentID, err := h.ResolveConfigID(tx, parentType, parentRef) if err != nil { return err } @@ -227,7 +227,7 @@ func (h *ActionHandler) DeleteVariable(ctx context.Context, parentType types.Con return err } if variable == nil { - return util.NewErrBadRequest(errors.Errorf("variable with name %q doesn't exist", variableName)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("variable with name %q doesn't exist", variableName)) } // changegroup is the variable id diff --git a/internal/services/configstore/api/api.go b/internal/services/configstore/api/api.go index 825ef17..fe1ee05 100644 --- a/internal/services/configstore/api/api.go +++ b/internal/services/configstore/api/api.go @@ -15,7 +15,6 @@ package api import ( - "encoding/json" "net/http" "net/url" @@ -30,97 +29,11 @@ type ErrorResponse struct { Message string `json:"message"` } -func ErrorResponseFromError(err error) *ErrorResponse { - var aerr error - // use inner errors if of these types - switch { - case util.IsBadRequest(err): - var cerr *util.ErrBadRequest - errors.As(err, &cerr) - aerr = cerr - case util.IsNotExist(err): - var cerr *util.ErrNotExist - errors.As(err, &cerr) - aerr = cerr - case util.IsForbidden(err): - var cerr *util.ErrForbidden - errors.As(err, &cerr) - aerr = cerr - case util.IsUnauthorized(err): - var cerr *util.ErrUnauthorized - errors.As(err, &cerr) - aerr = cerr - case util.IsInternal(err): - var cerr *util.ErrInternal - errors.As(err, &cerr) - aerr = cerr - } - - if aerr != nil { - return &ErrorResponse{Message: aerr.Error()} - } - - // on generic error return an generic message to not leak the real error - return &ErrorResponse{Message: "internal server error"} -} - -func httpError(w http.ResponseWriter, err error) bool { - if err == nil { - return false - } - - response := ErrorResponseFromError(err) - resj, merr := json.Marshal(response) - if merr != nil { - w.WriteHeader(http.StatusInternalServerError) - return true - } - switch { - case util.IsBadRequest(err): - w.WriteHeader(http.StatusBadRequest) - _, _ = w.Write(resj) - case util.IsNotExist(err): - w.WriteHeader(http.StatusNotFound) - _, _ = w.Write(resj) - case util.IsForbidden(err): - w.WriteHeader(http.StatusForbidden) - _, _ = w.Write(resj) - case util.IsUnauthorized(err): - w.WriteHeader(http.StatusUnauthorized) - _, _ = w.Write(resj) - case util.IsInternal(err): - w.WriteHeader(http.StatusInternalServerError) - _, _ = w.Write(resj) - default: - w.WriteHeader(http.StatusInternalServerError) - _, _ = w.Write(resj) - } - return true -} - -func httpResponse(w http.ResponseWriter, code int, res interface{}) error { - w.Header().Set("Content-Type", "application/json") - - if res != nil { - resj, err := json.Marshal(res) - if err != nil { - httpError(w, err) - return err - } - w.WriteHeader(code) - _, err = w.Write(resj) - return err - } - - w.WriteHeader(code) - return nil -} - func GetConfigTypeRef(r *http.Request) (types.ConfigType, string, error) { vars := mux.Vars(r) projectRef, err := url.PathUnescape(vars["projectref"]) if err != nil { - return "", "", util.NewErrBadRequest(errors.Errorf("wrong projectref %q: %w", vars["projectref"], err)) + return "", "", util.NewAPIError(util.ErrBadRequest, errors.Errorf("wrong projectref %q: %w", vars["projectref"], err)) } if projectRef != "" { return types.ConfigTypeProject, projectRef, nil @@ -128,11 +41,11 @@ func GetConfigTypeRef(r *http.Request) (types.ConfigType, string, error) { projectGroupRef, err := url.PathUnescape(vars["projectgroupref"]) if err != nil { - return "", "", util.NewErrBadRequest(errors.Errorf("wrong projectgroupref %q: %w", vars["projectgroupref"], err)) + return "", "", util.NewAPIError(util.ErrBadRequest, errors.Errorf("wrong projectgroupref %q: %w", vars["projectgroupref"], err)) } if projectGroupRef != "" { return types.ConfigTypeProjectGroup, projectGroupRef, nil } - return "", "", util.NewErrBadRequest(errors.Errorf("cannot get project or projectgroup ref")) + return "", "", util.NewAPIError(util.ErrBadRequest, errors.Errorf("cannot get project or projectgroup ref")) } diff --git a/internal/services/configstore/api/maintenance.go b/internal/services/configstore/api/maintenance.go index 3b2e467..fd6a7bb 100644 --- a/internal/services/configstore/api/maintenance.go +++ b/internal/services/configstore/api/maintenance.go @@ -19,6 +19,7 @@ import ( "agola.io/agola/internal/etcd" "agola.io/agola/internal/services/configstore/action" + "agola.io/agola/internal/util" "go.uber.org/zap" ) @@ -47,11 +48,11 @@ func (h *MaintenanceModeHandler) ServeHTTP(w http.ResponseWriter, r *http.Reques err := h.ah.MaintenanceMode(ctx, enable) if err != nil { h.log.Errorf("err: %+v", err) - httpError(w, err) + util.HTTPError(w, err) return } - if err := httpResponse(w, http.StatusOK, nil); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, nil); err != nil { h.log.Errorf("err: %+v", err) } @@ -96,11 +97,11 @@ func (h *ImportHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { err := h.ah.Import(ctx, r.Body) if err != nil { h.log.Errorf("err: %+v", err) - httpError(w, err) + util.HTTPError(w, err) return } - if err := httpResponse(w, http.StatusOK, nil); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, nil); err != nil { h.log.Errorf("err: %+v", err) } diff --git a/internal/services/configstore/api/org.go b/internal/services/configstore/api/org.go index 3d427b7..6108bb0 100644 --- a/internal/services/configstore/api/org.go +++ b/internal/services/configstore/api/org.go @@ -53,16 +53,16 @@ func (h *OrgHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { }) if err != nil { h.log.Errorf("err: %+v", err) - httpError(w, err) + util.HTTPError(w, err) return } if org == nil { - httpError(w, util.NewErrNotExist(errors.Errorf("org %q doesn't exist", orgRef))) + util.HTTPError(w, util.NewAPIError(util.ErrNotExist, errors.Errorf("org %q doesn't exist", orgRef))) return } - if err := httpResponse(w, http.StatusOK, org); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, org); err != nil { h.log.Errorf("err: %+v", err) } } @@ -82,17 +82,17 @@ func (h *CreateOrgHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { var req types.Organization d := json.NewDecoder(r.Body) if err := d.Decode(&req); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } org, err := h.ah.CreateOrg(ctx, &req) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusCreated, org); err != nil { + if err := util.HTTPResponse(w, http.StatusCreated, org); err != nil { h.log.Errorf("err: %+v", err) } } @@ -113,11 +113,11 @@ func (h *DeleteOrgHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { orgRef := vars["orgref"] err := h.ah.DeleteOrg(ctx, orgRef) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusNoContent, nil); err != nil { + if err := util.HTTPResponse(w, http.StatusNoContent, nil); err != nil { h.log.Errorf("err: %+v", err) } } @@ -146,12 +146,12 @@ func (h *OrgsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { var err error limit, err = strconv.Atoi(limitS) if err != nil { - httpError(w, util.NewErrBadRequest(errors.Errorf("cannot parse limit: %w", err))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("cannot parse limit: %w", err))) return } } if limit < 0 { - httpError(w, util.NewErrBadRequest(errors.Errorf("limit must be greater or equal than 0"))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("limit must be greater or equal than 0"))) return } if limit > MaxOrgsLimit { @@ -172,11 +172,11 @@ func (h *OrgsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { }) if err != nil { h.log.Errorf("err: %+v", err) - httpError(w, err) + util.HTTPError(w, err) return } - if err := httpResponse(w, http.StatusOK, orgs); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, orgs); err != nil { h.log.Errorf("err: %+v", err) } } @@ -200,17 +200,17 @@ func (h *AddOrgMemberHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) var req csapitypes.AddOrgMemberRequest d := json.NewDecoder(r.Body) if err := d.Decode(&req); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } org, err := h.ah.AddOrgMember(ctx, orgRef, userRef, req.Role) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusCreated, org); err != nil { + if err := util.HTTPResponse(w, http.StatusCreated, org); err != nil { h.log.Errorf("err: %+v", err) } } @@ -232,12 +232,12 @@ func (h *RemoveOrgMemberHandler) ServeHTTP(w http.ResponseWriter, r *http.Reques userRef := vars["userref"] err := h.ah.RemoveOrgMember(ctx, orgRef, userRef) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusNoContent, nil); err != nil { + if err := util.HTTPResponse(w, http.StatusNoContent, nil); err != nil { h.log.Errorf("err: %+v", err) } } @@ -264,7 +264,7 @@ func (h *OrgMembersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { orgRef := vars["orgref"] orgUsers, err := h.ah.GetOrgMembers(ctx, orgRef) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } @@ -274,7 +274,7 @@ func (h *OrgMembersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { res[i] = orgMemberResponse(orgUser) } - if err := httpResponse(w, http.StatusOK, res); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, res); err != nil { h.log.Errorf("err: %+v", err) } } diff --git a/internal/services/configstore/api/project.go b/internal/services/configstore/api/project.go index 91e0042..0dba1b3 100644 --- a/internal/services/configstore/api/project.go +++ b/internal/services/configstore/api/project.go @@ -126,23 +126,23 @@ func (h *ProjectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) projectRef, err := url.PathUnescape(vars["projectref"]) if err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } project, err := h.ah.GetProject(ctx, projectRef) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } resProject, err := projectResponse(ctx, h.readDB, project) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusOK, resProject); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, resProject); err != nil { h.log.Errorf("err: %+v", err) } } @@ -163,23 +163,23 @@ func (h *CreateProjectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) var req types.Project d := json.NewDecoder(r.Body) if err := d.Decode(&req); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } project, err := h.ah.CreateProject(ctx, &req) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } resProject, err := projectResponse(ctx, h.readDB, project) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusCreated, resProject); err != nil { + if err := util.HTTPResponse(w, http.StatusCreated, resProject); err != nil { h.log.Errorf("err: %+v", err) } } @@ -200,14 +200,14 @@ func (h *UpdateProjectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) vars := mux.Vars(r) projectRef, err := url.PathUnescape(vars["projectref"]) if err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } var project *types.Project d := json.NewDecoder(r.Body) if err := d.Decode(&project); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } @@ -216,18 +216,18 @@ func (h *UpdateProjectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) Project: project, } project, err = h.ah.UpdateProject(ctx, areq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } resProject, err := projectResponse(ctx, h.readDB, project) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusCreated, resProject); err != nil { + if err := util.HTTPResponse(w, http.StatusCreated, resProject); err != nil { h.log.Errorf("err: %+v", err) } } @@ -247,15 +247,15 @@ func (h *DeleteProjectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) vars := mux.Vars(r) projectRef, err := url.PathUnescape(vars["projectref"]) if err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } err = h.ah.DeleteProject(ctx, projectRef) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) } - if err := httpResponse(w, http.StatusNoContent, nil); err != nil { + if err := util.HTTPResponse(w, http.StatusNoContent, nil); err != nil { h.log.Errorf("err: %+v", err) } } diff --git a/internal/services/configstore/api/projectgroup.go b/internal/services/configstore/api/projectgroup.go index 264dfd1..8c3df36 100644 --- a/internal/services/configstore/api/projectgroup.go +++ b/internal/services/configstore/api/projectgroup.go @@ -95,23 +95,23 @@ func (h *ProjectGroupHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) projectGroupRef, err := url.PathUnescape(vars["projectgroupref"]) if err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } projectGroup, err := h.ah.GetProjectGroup(ctx, projectGroupRef) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } resProjectGroup, err := projectGroupResponse(ctx, h.readDB, projectGroup) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusOK, resProjectGroup); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, resProjectGroup); err != nil { h.log.Errorf("err: %+v", err) } } @@ -132,23 +132,23 @@ func (h *ProjectGroupProjectsHandler) ServeHTTP(w http.ResponseWriter, r *http.R projectGroupRef, err := url.PathUnescape(vars["projectgroupref"]) if err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } projects, err := h.ah.GetProjectGroupProjects(ctx, projectGroupRef) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } resProjects, err := projectsResponse(ctx, h.readDB, projects) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusOK, resProjects); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, resProjects); err != nil { h.log.Errorf("err: %+v", err) } } @@ -168,23 +168,23 @@ func (h *ProjectGroupSubgroupsHandler) ServeHTTP(w http.ResponseWriter, r *http. vars := mux.Vars(r) projectGroupRef, err := url.PathUnescape(vars["projectgroupref"]) if err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } projectGroups, err := h.ah.GetProjectGroupSubgroups(ctx, projectGroupRef) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } resProjectGroups, err := projectGroupsResponse(ctx, h.readDB, projectGroups) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusOK, resProjectGroups); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, resProjectGroups); err != nil { h.log.Errorf("err: %+v", err) } } @@ -205,23 +205,23 @@ func (h *CreateProjectGroupHandler) ServeHTTP(w http.ResponseWriter, r *http.Req var req types.ProjectGroup d := json.NewDecoder(r.Body) if err := d.Decode(&req); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } projectGroup, err := h.ah.CreateProjectGroup(ctx, &req) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } resProjectGroup, err := projectGroupResponse(ctx, h.readDB, projectGroup) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusCreated, resProjectGroup); err != nil { + if err := util.HTTPResponse(w, http.StatusCreated, resProjectGroup); err != nil { h.log.Errorf("err: %+v", err) } } @@ -242,14 +242,14 @@ func (h *UpdateProjectGroupHandler) ServeHTTP(w http.ResponseWriter, r *http.Req vars := mux.Vars(r) projectGroupRef, err := url.PathUnescape(vars["projectgroupref"]) if err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } var projectGroup *types.ProjectGroup d := json.NewDecoder(r.Body) if err := d.Decode(&projectGroup); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } @@ -258,18 +258,18 @@ func (h *UpdateProjectGroupHandler) ServeHTTP(w http.ResponseWriter, r *http.Req ProjectGroup: projectGroup, } projectGroup, err = h.ah.UpdateProjectGroup(ctx, areq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } resProjectGroup, err := projectGroupResponse(ctx, h.readDB, projectGroup) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusCreated, resProjectGroup); err != nil { + if err := util.HTTPResponse(w, http.StatusCreated, resProjectGroup); err != nil { h.log.Errorf("err: %+v", err) } } @@ -289,15 +289,15 @@ func (h *DeleteProjectGroupHandler) ServeHTTP(w http.ResponseWriter, r *http.Req vars := mux.Vars(r) projectGroupRef, err := url.PathUnescape(vars["projectgroupref"]) if err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } err = h.ah.DeleteProjectGroup(ctx, projectGroupRef) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) } - if err := httpResponse(w, http.StatusNoContent, nil); err != nil { + if err := util.HTTPResponse(w, http.StatusNoContent, nil); err != nil { h.log.Errorf("err: %+v", err) } } diff --git a/internal/services/configstore/api/remotesource.go b/internal/services/configstore/api/remotesource.go index d24dcfd..f892e3f 100644 --- a/internal/services/configstore/api/remotesource.go +++ b/internal/services/configstore/api/remotesource.go @@ -52,16 +52,16 @@ func (h *RemoteSourceHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) }) if err != nil { h.log.Errorf("err: %+v", err) - httpError(w, err) + util.HTTPError(w, err) return } if remoteSource == nil { - httpError(w, util.NewErrNotExist(errors.Errorf("remote source %q doesn't exist", rsRef))) + util.HTTPError(w, util.NewAPIError(util.ErrNotExist, errors.Errorf("remote source %q doesn't exist", rsRef))) return } - if err := httpResponse(w, http.StatusOK, remoteSource); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, remoteSource); err != nil { h.log.Errorf("err: %+v", err) } } @@ -81,17 +81,17 @@ func (h *CreateRemoteSourceHandler) ServeHTTP(w http.ResponseWriter, r *http.Req var req types.RemoteSource d := json.NewDecoder(r.Body) if err := d.Decode(&req); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } remoteSource, err := h.ah.CreateRemoteSource(ctx, &req) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusCreated, remoteSource); err != nil { + if err := util.HTTPResponse(w, http.StatusCreated, remoteSource); err != nil { h.log.Errorf("err: %+v", err) } } @@ -114,7 +114,7 @@ func (h *UpdateRemoteSourceHandler) ServeHTTP(w http.ResponseWriter, r *http.Req var remoteSource *types.RemoteSource d := json.NewDecoder(r.Body) if err := d.Decode(&remoteSource); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } @@ -123,12 +123,12 @@ func (h *UpdateRemoteSourceHandler) ServeHTTP(w http.ResponseWriter, r *http.Req RemoteSource: remoteSource, } remoteSource, err := h.ah.UpdateRemoteSource(ctx, areq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusCreated, remoteSource); err != nil { + if err := util.HTTPResponse(w, http.StatusCreated, remoteSource); err != nil { h.log.Errorf("err: %+v", err) } } @@ -149,10 +149,10 @@ func (h *DeleteRemoteSourceHandler) ServeHTTP(w http.ResponseWriter, r *http.Req rsRef := vars["remotesourceref"] err := h.ah.DeleteRemoteSource(ctx, rsRef) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) } - if err := httpResponse(w, http.StatusNoContent, nil); err != nil { + if err := util.HTTPResponse(w, http.StatusNoContent, nil); err != nil { h.log.Errorf("err: %+v", err) } } @@ -181,12 +181,12 @@ func (h *RemoteSourcesHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) var err error limit, err = strconv.Atoi(limitS) if err != nil { - httpError(w, util.NewErrBadRequest(errors.Errorf("cannot parse limit: %w", err))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("cannot parse limit: %w", err))) return } } if limit < 0 { - httpError(w, util.NewErrBadRequest(errors.Errorf("limit must be greater or equal than 0"))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("limit must be greater or equal than 0"))) return } if limit > MaxRemoteSourcesLimit { @@ -202,11 +202,11 @@ func (h *RemoteSourcesHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) remoteSources, err := h.readDB.GetRemoteSources(ctx, start, limit, asc) if err != nil { h.log.Errorf("err: %+v", err) - httpError(w, err) + util.HTTPError(w, err) return } - if err := httpResponse(w, http.StatusOK, remoteSources); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, remoteSources); err != nil { h.log.Errorf("err: %+v", err) } } diff --git a/internal/services/configstore/api/secret.go b/internal/services/configstore/api/secret.go index d974eb9..37c36dd 100644 --- a/internal/services/configstore/api/secret.go +++ b/internal/services/configstore/api/secret.go @@ -45,12 +45,12 @@ func (h *SecretHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { secretID := vars["secretid"] secret, err := h.ah.GetSecret(ctx, secretID) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusOK, secret); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, secret); err != nil { h.log.Errorf("err: %+v", err) } } @@ -71,13 +71,13 @@ func (h *SecretsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { _, tree := query["tree"] parentType, parentRef, err := GetConfigTypeRef(r) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } secrets, err := h.ah.GetSecrets(ctx, parentType, parentRef, tree) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } @@ -100,11 +100,11 @@ func (h *SecretsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { }) if err != nil { h.log.Errorf("err: %+v", err) - httpError(w, err) + util.HTTPError(w, err) return } - if err := httpResponse(w, http.StatusOK, resSecrets); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, resSecrets); err != nil { h.log.Errorf("err: %+v", err) } } @@ -121,7 +121,7 @@ func NewCreateSecretHandler(logger *zap.Logger, ah *action.ActionHandler) *Creat func (h *CreateSecretHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { ctx := r.Context() parentType, parentRef, err := GetConfigTypeRef(r) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } @@ -129,7 +129,7 @@ func (h *CreateSecretHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) var secret *types.Secret d := json.NewDecoder(r.Body) if err := d.Decode(&secret); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } @@ -137,12 +137,12 @@ func (h *CreateSecretHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) secret.Parent.ID = parentRef secret, err = h.ah.CreateSecret(ctx, secret) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusCreated, secret); err != nil { + if err := util.HTTPResponse(w, http.StatusCreated, secret); err != nil { h.log.Errorf("err: %+v", err) } } @@ -162,7 +162,7 @@ func (h *UpdateSecretHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) secretName := vars["secretname"] parentType, parentRef, err := GetConfigTypeRef(r) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } @@ -170,7 +170,7 @@ func (h *UpdateSecretHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) var secret *types.Secret d := json.NewDecoder(r.Body) if err := d.Decode(&secret); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } @@ -182,12 +182,12 @@ func (h *UpdateSecretHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) Secret: secret, } secret, err = h.ah.UpdateSecret(ctx, areq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusOK, secret); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, secret); err != nil { h.log.Errorf("err: %+v", err) } } @@ -207,16 +207,16 @@ func (h *DeleteSecretHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) secretName := vars["secretname"] parentType, parentRef, err := GetConfigTypeRef(r) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } err = h.ah.DeleteSecret(ctx, parentType, parentRef, secretName) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) } - if err := httpResponse(w, http.StatusNoContent, nil); err != nil { + if err := util.HTTPResponse(w, http.StatusNoContent, nil); err != nil { h.log.Errorf("err: %+v", err) } } diff --git a/internal/services/configstore/api/user.go b/internal/services/configstore/api/user.go index 6485856..bea13d3 100644 --- a/internal/services/configstore/api/user.go +++ b/internal/services/configstore/api/user.go @@ -53,16 +53,16 @@ func (h *UserHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { }) if err != nil { h.log.Errorf("err: %+v", err) - httpError(w, err) + util.HTTPError(w, err) return } if user == nil { - httpError(w, util.NewErrNotExist(errors.Errorf("user %q doesn't exist", userRef))) + util.HTTPError(w, util.NewAPIError(util.ErrNotExist, errors.Errorf("user %q doesn't exist", userRef))) return } - if err := httpResponse(w, http.StatusOK, user); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, user); err != nil { h.log.Errorf("err: %+v", err) } } @@ -82,7 +82,7 @@ func (h *CreateUserHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { var req *csapitypes.CreateUserRequest d := json.NewDecoder(r.Body) if err := d.Decode(&req); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } @@ -102,12 +102,12 @@ func (h *CreateUserHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } user, err := h.ah.CreateUser(ctx, creq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusCreated, user); err != nil { + if err := util.HTTPResponse(w, http.StatusCreated, user); err != nil { h.log.Errorf("err: %+v", err) } } @@ -130,7 +130,7 @@ func (h *UpdateUserHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { var req *csapitypes.UpdateUserRequest d := json.NewDecoder(r.Body) if err := d.Decode(&req); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } @@ -140,12 +140,12 @@ func (h *UpdateUserHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } user, err := h.ah.UpdateUser(ctx, creq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusCreated, user); err != nil { + if err := util.HTTPResponse(w, http.StatusCreated, user); err != nil { h.log.Errorf("err: %+v", err) } } @@ -166,10 +166,10 @@ func (h *DeleteUserHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { userRef := vars["userref"] err := h.ah.DeleteUser(ctx, userRef) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) } - if err := httpResponse(w, http.StatusNoContent, nil); err != nil { + if err := util.HTTPResponse(w, http.StatusNoContent, nil); err != nil { h.log.Errorf("err: %+v", err) } } @@ -198,12 +198,12 @@ func (h *UsersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { var err error limit, err = strconv.Atoi(limitS) if err != nil { - httpError(w, util.NewErrBadRequest(errors.Errorf("cannot parse limit: %w", err))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("cannot parse limit: %w", err))) return } } if limit < 0 { - httpError(w, util.NewErrBadRequest(errors.Errorf("limit must be greater or equal than 0"))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("limit must be greater or equal than 0"))) return } if limit > MaxUsersLimit { @@ -231,11 +231,11 @@ func (h *UsersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { }) if err != nil { h.log.Errorf("err: %+v", err) - httpError(w, err) + util.HTTPError(w, err) return } if user == nil { - httpError(w, util.NewErrNotExist(errors.Errorf("user with required token doesn't exist"))) + util.HTTPError(w, util.NewAPIError(util.ErrNotExist, errors.Errorf("user with required token doesn't exist"))) return } users = []*types.User{user} @@ -249,11 +249,11 @@ func (h *UsersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { }) if err != nil { h.log.Errorf("err: %+v", err) - httpError(w, err) + util.HTTPError(w, err) return } if user == nil { - httpError(w, util.NewErrNotExist(errors.Errorf("user with linked account %q token doesn't exist", linkedAccountID))) + util.HTTPError(w, util.NewAPIError(util.ErrNotExist, errors.Errorf("user with linked account %q token doesn't exist", linkedAccountID))) return } users = []*types.User{user} @@ -268,11 +268,11 @@ func (h *UsersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { }) if err != nil { h.log.Errorf("err: %+v", err) - httpError(w, err) + util.HTTPError(w, err) return } if user == nil { - httpError(w, util.NewErrNotExist(errors.Errorf("user with remote user %q for remote source %q token doesn't exist", remoteUserID, remoteSourceID))) + util.HTTPError(w, util.NewAPIError(util.ErrNotExist, errors.Errorf("user with remote user %q for remote source %q token doesn't exist", remoteUserID, remoteSourceID))) return } users = []*types.User{user} @@ -285,12 +285,12 @@ func (h *UsersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { }) if err != nil { h.log.Errorf("err: %+v", err) - httpError(w, err) + util.HTTPError(w, err) return } } - if err := httpResponse(w, http.StatusOK, users); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, users); err != nil { h.log.Errorf("err: %+v", err) } } @@ -312,7 +312,7 @@ func (h *CreateUserLAHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) var req csapitypes.CreateUserLARequest d := json.NewDecoder(r.Body) if err := d.Decode(&req); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } @@ -327,12 +327,12 @@ func (h *CreateUserLAHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) Oauth2AccessTokenExpiresAt: req.Oauth2AccessTokenExpiresAt, } user, err := h.ah.CreateUserLA(ctx, creq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusCreated, user); err != nil { + if err := util.HTTPResponse(w, http.StatusCreated, user); err != nil { h.log.Errorf("err: %+v", err) } } @@ -353,10 +353,10 @@ func (h *DeleteUserLAHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) laID := vars["laid"] err := h.ah.DeleteUserLA(ctx, userRef, laID) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) } - if err := httpResponse(w, http.StatusNoContent, nil); err != nil { + if err := util.HTTPResponse(w, http.StatusNoContent, nil); err != nil { h.log.Errorf("err: %+v", err) } } @@ -379,7 +379,7 @@ func (h *UpdateUserLAHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) var req csapitypes.UpdateUserLARequest d := json.NewDecoder(r.Body) if err := d.Decode(&req); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } @@ -394,12 +394,12 @@ func (h *UpdateUserLAHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) Oauth2AccessTokenExpiresAt: req.Oauth2AccessTokenExpiresAt, } user, err := h.ah.UpdateUserLA(ctx, creq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusOK, user); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, user); err != nil { h.log.Errorf("err: %+v", err) } } @@ -421,12 +421,12 @@ func (h *CreateUserTokenHandler) ServeHTTP(w http.ResponseWriter, r *http.Reques var req csapitypes.CreateUserTokenRequest d := json.NewDecoder(r.Body) if err := d.Decode(&req); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } token, err := h.ah.CreateUserToken(ctx, userRef, req.TokenName) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } @@ -434,7 +434,7 @@ func (h *CreateUserTokenHandler) ServeHTTP(w http.ResponseWriter, r *http.Reques resp := &csapitypes.CreateUserTokenResponse{ Token: token, } - if err := httpResponse(w, http.StatusCreated, resp); err != nil { + if err := util.HTTPResponse(w, http.StatusCreated, resp); err != nil { h.log.Errorf("err: %+v", err) } } @@ -455,11 +455,11 @@ func (h *DeleteUserTokenHandler) ServeHTTP(w http.ResponseWriter, r *http.Reques tokenName := vars["tokenname"] err := h.ah.DeleteUserToken(ctx, userRef, tokenName) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusNoContent, nil); err != nil { + if err := util.HTTPResponse(w, http.StatusNoContent, nil); err != nil { h.log.Errorf("err: %+v", err) } } @@ -486,7 +486,7 @@ func (h *UserOrgsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { userRef := vars["userref"] userOrgs, err := h.ah.GetUserOrgs(ctx, userRef) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } @@ -496,7 +496,7 @@ func (h *UserOrgsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { res[i] = userOrgsResponse(userOrg) } - if err := httpResponse(w, http.StatusOK, res); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, res); err != nil { h.log.Errorf("err: %+v", err) } } diff --git a/internal/services/configstore/api/variable.go b/internal/services/configstore/api/variable.go index 88e8b98..1e2073a 100644 --- a/internal/services/configstore/api/variable.go +++ b/internal/services/configstore/api/variable.go @@ -45,13 +45,13 @@ func (h *VariablesHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { _, tree := query["tree"] parentType, parentRef, err := GetConfigTypeRef(r) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } variables, err := h.ah.GetVariables(ctx, parentType, parentRef, tree) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } @@ -73,11 +73,11 @@ func (h *VariablesHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { }) if err != nil { h.log.Errorf("err: %+v", err) - httpError(w, err) + util.HTTPError(w, err) return } - if err := httpResponse(w, http.StatusOK, resVariables); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, resVariables); err != nil { h.log.Errorf("err: %+v", err) } } @@ -94,7 +94,7 @@ func NewCreateVariableHandler(logger *zap.Logger, ah *action.ActionHandler) *Cre func (h *CreateVariableHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { ctx := r.Context() parentType, parentRef, err := GetConfigTypeRef(r) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } @@ -102,7 +102,7 @@ func (h *CreateVariableHandler) ServeHTTP(w http.ResponseWriter, r *http.Request var variable *types.Variable d := json.NewDecoder(r.Body) if err := d.Decode(&variable); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } @@ -110,12 +110,12 @@ func (h *CreateVariableHandler) ServeHTTP(w http.ResponseWriter, r *http.Request variable.Parent.ID = parentRef variable, err = h.ah.CreateVariable(ctx, variable) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusCreated, variable); err != nil { + if err := util.HTTPResponse(w, http.StatusCreated, variable); err != nil { h.log.Errorf("err: %+v", err) } } @@ -135,7 +135,7 @@ func (h *UpdateVariableHandler) ServeHTTP(w http.ResponseWriter, r *http.Request variableName := vars["variablename"] parentType, parentRef, err := GetConfigTypeRef(r) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } @@ -143,7 +143,7 @@ func (h *UpdateVariableHandler) ServeHTTP(w http.ResponseWriter, r *http.Request var variable *types.Variable d := json.NewDecoder(r.Body) if err := d.Decode(&variable); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } @@ -155,12 +155,12 @@ func (h *UpdateVariableHandler) ServeHTTP(w http.ResponseWriter, r *http.Request Variable: variable, } variable, err = h.ah.UpdateVariable(ctx, areq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusOK, variable); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, variable); err != nil { h.log.Errorf("err: %+v", err) } } @@ -180,16 +180,16 @@ func (h *DeleteVariableHandler) ServeHTTP(w http.ResponseWriter, r *http.Request variableName := vars["variablename"] parentType, parentRef, err := GetConfigTypeRef(r) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } err = h.ah.DeleteVariable(ctx, parentType, parentRef, variableName) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) } - if err := httpResponse(w, http.StatusNoContent, nil); err != nil { + if err := util.HTTPResponse(w, http.StatusNoContent, nil); err != nil { h.log.Errorf("err: %+v", err) } } diff --git a/internal/services/configstore/configstore_test.go b/internal/services/configstore/configstore_test.go index 675682f..ddf556a 100644 --- a/internal/services/configstore/configstore_test.go +++ b/internal/services/configstore/configstore_test.go @@ -1321,7 +1321,7 @@ func TestRemoteSource(t *testing.T) { t.Fatalf("unexpected err: %v", err) } - expectedError := util.NewErrBadRequest(fmt.Errorf(`remotesource "rs01" already exists`)) + expectedError := util.NewAPIError(util.ErrBadRequest, fmt.Errorf(`remotesource "rs01" already exists`)) _, err = cs.ah.CreateRemoteSource(ctx, rs) if err.Error() != expectedError.Error() { t.Fatalf("expected err: %v, got err: %v", expectedError.Error(), err.Error()) @@ -1410,7 +1410,7 @@ func TestRemoteSource(t *testing.T) { t.Fatalf("unexpected err: %v", err) } - expectedError := util.NewErrBadRequest(fmt.Errorf(`remotesource "rs02" already exists`)) + expectedError := util.NewAPIError(util.ErrBadRequest, fmt.Errorf(`remotesource "rs02" already exists`)) rs01.Name = "rs02" req := &action.UpdateRemoteSourceRequest{ RemoteSourceRef: "rs01", diff --git a/internal/services/configstore/readdb/resolve.go b/internal/services/configstore/readdb/resolve.go index 8959a13..5fd3ef3 100644 --- a/internal/services/configstore/readdb/resolve.go +++ b/internal/services/configstore/readdb/resolve.go @@ -18,38 +18,11 @@ import ( "path" "agola.io/agola/internal/db" - "agola.io/agola/internal/util" "agola.io/agola/services/configstore/types" + errors "golang.org/x/xerrors" ) -func (r *ReadDB) ResolveConfigID(tx *db.Tx, configType types.ConfigType, ref string) (string, error) { - switch configType { - case types.ConfigTypeProjectGroup: - group, err := r.GetProjectGroup(tx, ref) - if err != nil { - return "", err - } - if group == nil { - return "", util.NewErrBadRequest(errors.Errorf("group with ref %q doesn't exists", ref)) - } - return group.ID, nil - - case types.ConfigTypeProject: - project, err := r.GetProject(tx, ref) - if err != nil { - return "", err - } - if project == nil { - return "", util.NewErrBadRequest(errors.Errorf("project with ref %q doesn't exists", ref)) - } - return project.ID, nil - - default: - return "", util.NewErrBadRequest(errors.Errorf("unknown config type %q", configType)) - } -} - func (r *ReadDB) GetPath(tx *db.Tx, configType types.ConfigType, id string) (string, error) { var p string switch configType { diff --git a/internal/services/executor/driver/docker_test.go b/internal/services/executor/driver/docker_test.go index af47952..92a5387 100644 --- a/internal/services/executor/driver/docker_test.go +++ b/internal/services/executor/driver/docker_test.go @@ -25,8 +25,8 @@ import ( "agola.io/agola/internal/testutil" "github.com/docker/docker/api/types" - "github.com/google/go-cmp/cmp" "github.com/gofrs/uuid" + "github.com/google/go-cmp/cmp" "go.uber.org/zap" "go.uber.org/zap/zaptest" ) diff --git a/internal/services/gateway/action/action.go b/internal/services/gateway/action/action.go index 4749098..4d13742 100644 --- a/internal/services/gateway/action/action.go +++ b/internal/services/gateway/action/action.go @@ -15,10 +15,7 @@ package action import ( - "net/http" - "agola.io/agola/internal/services/common" - "agola.io/agola/internal/util" csclient "agola.io/agola/services/configstore/client" rsclient "agola.io/agola/services/runservice/client" @@ -46,20 +43,3 @@ func NewActionHandler(logger *zap.Logger, sd *common.TokenSigningData, configsto webExposedURL: webExposedURL, } } - -func ErrFromRemote(resp *http.Response, err error) error { - if err == nil { - return nil - } - - if resp != nil { - switch resp.StatusCode { - case http.StatusBadRequest: - return util.NewErrBadRequest(err) - case http.StatusNotFound: - return util.NewErrNotExist(err) - } - } - - return err -} diff --git a/internal/services/gateway/action/auth.go b/internal/services/gateway/action/auth.go index 1bbbd36..66de2d2 100644 --- a/internal/services/gateway/action/auth.go +++ b/internal/services/gateway/action/auth.go @@ -19,6 +19,7 @@ import ( scommon "agola.io/agola/internal/services/common" "agola.io/agola/internal/services/gateway/common" + "agola.io/agola/internal/util" cstypes "agola.io/agola/services/configstore/types" errors "golang.org/x/xerrors" @@ -35,9 +36,9 @@ func (h *ActionHandler) IsOrgOwner(ctx context.Context, orgID string) (bool, err return false, nil } - userOrgs, resp, err := h.configstoreClient.GetUserOrgs(ctx, userID) + userOrgs, _, err := h.configstoreClient.GetUserOrgs(ctx, userID) if err != nil { - return false, errors.Errorf("failed to get user orgs: %w", ErrFromRemote(resp, err)) + return false, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get user orgs: %w", err)) } for _, userOrg := range userOrgs { @@ -70,9 +71,9 @@ func (h *ActionHandler) IsProjectOwner(ctx context.Context, ownerType cstypes.Co } if ownerType == cstypes.ConfigTypeOrg { - userOrgs, resp, err := h.configstoreClient.GetUserOrgs(ctx, userID) + userOrgs, _, err := h.configstoreClient.GetUserOrgs(ctx, userID) if err != nil { - return false, errors.Errorf("failed to get user orgs: %w", ErrFromRemote(resp, err)) + return false, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get user orgs: %w", err)) } for _, userOrg := range userOrgs { @@ -106,9 +107,9 @@ func (h *ActionHandler) IsProjectMember(ctx context.Context, ownerType cstypes.C } if ownerType == cstypes.ConfigTypeOrg { - userOrgs, resp, err := h.configstoreClient.GetUserOrgs(ctx, userID) + userOrgs, _, err := h.configstoreClient.GetUserOrgs(ctx, userID) if err != nil { - return false, errors.Errorf("failed to get user orgs: %w", ErrFromRemote(resp, err)) + return false, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get user orgs: %w", err)) } for _, userOrg := range userOrgs { @@ -127,16 +128,16 @@ func (h *ActionHandler) IsVariableOwner(ctx context.Context, parentType cstypes. var ownerID string switch parentType { case cstypes.ConfigTypeProjectGroup: - pg, resp, err := h.configstoreClient.GetProjectGroup(ctx, parentRef) + pg, _, err := h.configstoreClient.GetProjectGroup(ctx, parentRef) if err != nil { - return false, errors.Errorf("failed to get project group %q: %w", parentRef, ErrFromRemote(resp, err)) + return false, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get project group %q: %w", parentRef, err)) } ownerType = pg.OwnerType ownerID = pg.OwnerID case cstypes.ConfigTypeProject: - p, resp, err := h.configstoreClient.GetProject(ctx, parentRef) + p, _, err := h.configstoreClient.GetProject(ctx, parentRef) if err != nil { - return false, errors.Errorf("failed to get project %q: %w", parentRef, ErrFromRemote(resp, err)) + return false, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get project %q: %w", parentRef, err)) } ownerType = p.OwnerType ownerID = p.OwnerID @@ -156,9 +157,9 @@ func (h *ActionHandler) CanGetRun(ctx context.Context, runGroup string) (bool, e var ownerID string switch groupType { case scommon.GroupTypeProject: - p, resp, err := h.configstoreClient.GetProject(ctx, groupID) + p, _, err := h.configstoreClient.GetProject(ctx, groupID) if err != nil { - return false, ErrFromRemote(resp, err) + return false, util.NewAPIError(util.KindFromRemoteError(err), err) } ownerType = p.OwnerType ownerID = p.OwnerID @@ -193,9 +194,9 @@ func (h *ActionHandler) CanDoRunActions(ctx context.Context, runGroup string) (b var ownerID string switch groupType { case scommon.GroupTypeProject: - p, resp, err := h.configstoreClient.GetProject(ctx, groupID) + p, _, err := h.configstoreClient.GetProject(ctx, groupID) if err != nil { - return false, ErrFromRemote(resp, err) + return false, util.NewAPIError(util.KindFromRemoteError(err), err) } ownerType = p.OwnerType ownerID = p.OwnerID diff --git a/internal/services/gateway/action/badge.go b/internal/services/gateway/action/badge.go index cab1059..211a3b2 100644 --- a/internal/services/gateway/action/badge.go +++ b/internal/services/gateway/action/badge.go @@ -20,22 +20,23 @@ import ( "path" "agola.io/agola/internal/services/common" + "agola.io/agola/internal/util" rstypes "agola.io/agola/services/runservice/types" ) // GetBadge return a badge for a project branch // TODO(sgotti) also handle tags and PRs func (h *ActionHandler) GetBadge(ctx context.Context, projectRef, branch string) (string, error) { - project, resp, err := h.configstoreClient.GetProject(ctx, projectRef) + project, _, err := h.configstoreClient.GetProject(ctx, projectRef) if err != nil { - return "", ErrFromRemote(resp, err) + return "", util.NewAPIError(util.KindFromRemoteError(err), err) } // if branch is empty we get the latest run for every branch. group := path.Join("/", string(common.GroupTypeProject), project.ID, string(common.GroupTypeBranch), url.PathEscape(branch)) - runResp, resp, err := h.runserviceClient.GetGroupLastRun(ctx, group, nil) + runResp, _, err := h.runserviceClient.GetGroupLastRun(ctx, group, nil) if err != nil { - return "", ErrFromRemote(resp, err) + return "", util.NewAPIError(util.KindFromRemoteError(err), err) } if len(runResp.Runs) == 0 { return badgeUnknown, nil diff --git a/internal/services/gateway/action/org.go b/internal/services/gateway/action/org.go index 4faaf4f..f9ce8cd 100644 --- a/internal/services/gateway/action/org.go +++ b/internal/services/gateway/action/org.go @@ -25,9 +25,9 @@ import ( ) func (h *ActionHandler) GetOrg(ctx context.Context, orgRef string) (*cstypes.Organization, error) { - org, resp, err := h.configstoreClient.GetOrg(ctx, orgRef) + org, _, err := h.configstoreClient.GetOrg(ctx, orgRef) if err != nil { - return nil, ErrFromRemote(resp, err) + return nil, util.NewAPIError(util.KindFromRemoteError(err), err) } return org, nil } @@ -39,9 +39,9 @@ type GetOrgsRequest struct { } func (h *ActionHandler) GetOrgs(ctx context.Context, req *GetOrgsRequest) ([]*cstypes.Organization, error) { - orgs, resp, err := h.configstoreClient.GetOrgs(ctx, req.Start, req.Limit, req.Asc) + orgs, _, err := h.configstoreClient.GetOrgs(ctx, req.Start, req.Limit, req.Asc) if err != nil { - return nil, ErrFromRemote(resp, err) + return nil, util.NewAPIError(util.KindFromRemoteError(err), err) } return orgs, nil } @@ -57,14 +57,14 @@ type OrgMemberResponse struct { } func (h *ActionHandler) GetOrgMembers(ctx context.Context, orgRef string) (*OrgMembersResponse, error) { - org, resp, err := h.configstoreClient.GetOrg(ctx, orgRef) + org, _, err := h.configstoreClient.GetOrg(ctx, orgRef) if err != nil { - return nil, ErrFromRemote(resp, err) + return nil, util.NewAPIError(util.KindFromRemoteError(err), err) } - orgMembers, resp, err := h.configstoreClient.GetOrgMembers(ctx, orgRef) + orgMembers, _, err := h.configstoreClient.GetOrgMembers(ctx, orgRef) if err != nil { - return nil, ErrFromRemote(resp, err) + return nil, util.NewAPIError(util.KindFromRemoteError(err), err) } res := &OrgMembersResponse{ @@ -93,10 +93,10 @@ func (h *ActionHandler) CreateOrg(ctx context.Context, req *CreateOrgRequest) (* } if req.Name == "" { - return nil, util.NewErrBadRequest(errors.Errorf("organization name required")) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("organization name required")) } if !util.ValidateName(req.Name) { - return nil, util.NewErrBadRequest(errors.Errorf("invalid organization name %q", req.Name)) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("invalid organization name %q", req.Name)) } org := &cstypes.Organization{ @@ -108,9 +108,9 @@ func (h *ActionHandler) CreateOrg(ctx context.Context, req *CreateOrgRequest) (* } h.log.Infof("creating organization") - org, resp, err := h.configstoreClient.CreateOrg(ctx, org) + org, _, err := h.configstoreClient.CreateOrg(ctx, org) if err != nil { - return nil, errors.Errorf("failed to create organization: %w", ErrFromRemote(resp, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to create organization: %w", err)) } h.log.Infof("organization %s created, ID: %s", org.Name, org.ID) @@ -118,9 +118,9 @@ func (h *ActionHandler) CreateOrg(ctx context.Context, req *CreateOrgRequest) (* } func (h *ActionHandler) DeleteOrg(ctx context.Context, orgRef string) error { - org, resp, err := h.configstoreClient.GetOrg(ctx, orgRef) + org, _, err := h.configstoreClient.GetOrg(ctx, orgRef) if err != nil { - return ErrFromRemote(resp, err) + return util.NewAPIError(util.KindFromRemoteError(err), err) } isOrgOwner, err := h.IsOrgOwner(ctx, org.ID) @@ -128,12 +128,11 @@ func (h *ActionHandler) DeleteOrg(ctx context.Context, orgRef string) error { return errors.Errorf("failed to determine ownership: %w", err) } if !isOrgOwner { - return util.NewErrForbidden(errors.Errorf("user not authorized")) + return util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) } - resp, err = h.configstoreClient.DeleteOrg(ctx, orgRef) - if err != nil { - return errors.Errorf("failed to delete org: %w", ErrFromRemote(resp, err)) + if _, err := h.configstoreClient.DeleteOrg(ctx, orgRef); err != nil { + return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to delete org: %w", err)) } return nil } @@ -145,13 +144,13 @@ type AddOrgMemberResponse struct { } func (h *ActionHandler) AddOrgMember(ctx context.Context, orgRef, userRef string, role cstypes.MemberRole) (*AddOrgMemberResponse, error) { - org, resp, err := h.configstoreClient.GetOrg(ctx, orgRef) + org, _, err := h.configstoreClient.GetOrg(ctx, orgRef) if err != nil { - return nil, ErrFromRemote(resp, err) + return nil, util.NewAPIError(util.KindFromRemoteError(err), err) } - user, resp, err := h.configstoreClient.GetUser(ctx, userRef) + user, _, err := h.configstoreClient.GetUser(ctx, userRef) if err != nil { - return nil, ErrFromRemote(resp, err) + return nil, util.NewAPIError(util.KindFromRemoteError(err), err) } isOrgOwner, err := h.IsOrgOwner(ctx, org.ID) @@ -159,12 +158,12 @@ func (h *ActionHandler) AddOrgMember(ctx context.Context, orgRef, userRef string return nil, errors.Errorf("failed to determine ownership: %w", err) } if !isOrgOwner { - return nil, util.NewErrForbidden(errors.Errorf("user not authorized")) + return nil, util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) } - orgmember, resp, err := h.configstoreClient.AddOrgMember(ctx, orgRef, userRef, role) + orgmember, _, err := h.configstoreClient.AddOrgMember(ctx, orgRef, userRef, role) if err != nil { - return nil, errors.Errorf("failed to add/update organization member: %w", ErrFromRemote(resp, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to add/update organization member: %w", err)) } return &AddOrgMemberResponse{ @@ -175,9 +174,9 @@ func (h *ActionHandler) AddOrgMember(ctx context.Context, orgRef, userRef string } func (h *ActionHandler) RemoveOrgMember(ctx context.Context, orgRef, userRef string) error { - org, resp, err := h.configstoreClient.GetOrg(ctx, orgRef) + org, _, err := h.configstoreClient.GetOrg(ctx, orgRef) if err != nil { - return ErrFromRemote(resp, err) + return util.NewAPIError(util.KindFromRemoteError(err), err) } isOrgOwner, err := h.IsOrgOwner(ctx, org.ID) @@ -185,12 +184,11 @@ func (h *ActionHandler) RemoveOrgMember(ctx context.Context, orgRef, userRef str return errors.Errorf("failed to determine ownership: %w", err) } if !isOrgOwner { - return util.NewErrForbidden(errors.Errorf("user not authorized")) + return util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) } - resp, err = h.configstoreClient.RemoveOrgMember(ctx, orgRef, userRef) - if err != nil { - return errors.Errorf("failed to remove organization member: %w", ErrFromRemote(resp, err)) + if _, err = h.configstoreClient.RemoveOrgMember(ctx, orgRef, userRef); err != nil { + return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to remove organization member: %w", err)) } return nil diff --git a/internal/services/gateway/action/project.go b/internal/services/gateway/action/project.go index 7f4be86..303f0f5 100644 --- a/internal/services/gateway/action/project.go +++ b/internal/services/gateway/action/project.go @@ -17,7 +17,6 @@ package action import ( "context" "fmt" - "net/http" "net/url" "path" @@ -32,9 +31,9 @@ import ( ) func (h *ActionHandler) GetProject(ctx context.Context, projectRef string) (*csapitypes.Project, error) { - project, resp, err := h.configstoreClient.GetProject(ctx, projectRef) + project, _, err := h.configstoreClient.GetProject(ctx, projectRef) if err != nil { - return nil, ErrFromRemote(resp, err) + return nil, err } isProjectMember, err := h.IsProjectMember(ctx, project.OwnerType, project.OwnerID) @@ -45,7 +44,7 @@ func (h *ActionHandler) GetProject(ctx context.Context, projectRef string) (*csa return project, nil } if !isProjectMember { - return nil, util.NewErrForbidden(errors.Errorf("user not authorized")) + return nil, util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) } return project, nil @@ -64,9 +63,9 @@ type CreateProjectRequest struct { func (h *ActionHandler) CreateProject(ctx context.Context, req *CreateProjectRequest) (*csapitypes.Project, error) { curUserID := common.CurrentUserID(ctx) - user, resp, err := h.configstoreClient.GetUser(ctx, curUserID) + user, _, err := h.configstoreClient.GetUser(ctx, curUserID) if err != nil { - return nil, errors.Errorf("failed to get user %q: %w", curUserID, ErrFromRemote(resp, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get user %q: %w", curUserID, err)) } parentRef := req.ParentRef if parentRef == "" { @@ -74,9 +73,9 @@ func (h *ActionHandler) CreateProject(ctx context.Context, req *CreateProjectReq parentRef = path.Join("user", user.Name) } - pg, resp, err := h.configstoreClient.GetProjectGroup(ctx, parentRef) + pg, _, err := h.configstoreClient.GetProjectGroup(ctx, parentRef) if err != nil { - return nil, errors.Errorf("failed to get project group %q: %w", parentRef, ErrFromRemote(resp, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get project group %q: %w", parentRef, err)) } isProjectOwner, err := h.IsProjectOwner(ctx, pg.OwnerType, pg.OwnerID) @@ -84,32 +83,31 @@ func (h *ActionHandler) CreateProject(ctx context.Context, req *CreateProjectReq return nil, errors.Errorf("failed to determine ownership: %w", err) } if !isProjectOwner { - return nil, util.NewErrForbidden(errors.Errorf("user not authorized")) + return nil, util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) } if !util.ValidateName(req.Name) { - return nil, util.NewErrBadRequest(errors.Errorf("invalid project name %q", req.Name)) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("invalid project name %q", req.Name)) } if req.RemoteSourceName == "" { - return nil, util.NewErrBadRequest(errors.Errorf("empty remote source name")) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("empty remote source name")) } if req.RepoPath == "" { - return nil, util.NewErrBadRequest(errors.Errorf("empty remote repo path")) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("empty remote repo path")) } projectPath := path.Join(pg.Path, req.Name) - _, resp, err = h.configstoreClient.GetProject(ctx, projectPath) - if err != nil { - if resp != nil && resp.StatusCode != http.StatusNotFound { - return nil, errors.Errorf("failed to get project %q: %w", req.Name, ErrFromRemote(resp, err)) + if _, _, err = h.configstoreClient.GetProject(ctx, projectPath); err != nil { + if !util.RemoteErrorIs(err, util.ErrNotExist) { + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get project %q: %w", req.Name, err)) } } else { - return nil, util.NewErrBadRequest(errors.Errorf("project %q already exists", projectPath)) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("project %q already exists", projectPath)) } - rs, resp, err := h.configstoreClient.GetRemoteSource(ctx, req.RemoteSourceName) + rs, _, err := h.configstoreClient.GetRemoteSource(ctx, req.RemoteSourceName) if err != nil { - return nil, errors.Errorf("failed to get remote source %q: %w", req.RemoteSourceName, ErrFromRemote(resp, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get remote source %q: %w", req.RemoteSourceName, err)) } var la *cstypes.LinkedAccount for _, v := range user.LinkedAccounts { @@ -156,25 +154,24 @@ func (h *ActionHandler) CreateProject(ctx context.Context, req *CreateProjectReq } h.log.Infof("creating project") - rp, resp, err := h.configstoreClient.CreateProject(ctx, p) + rp, _, err := h.configstoreClient.CreateProject(ctx, p) if err != nil { - return nil, errors.Errorf("failed to create project: %w", ErrFromRemote(resp, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to create project: %w", err)) } h.log.Infof("project %s created, ID: %s", rp.Name, rp.ID) if serr := h.setupGitSourceRepo(ctx, rs, user, la, rp); serr != nil { var err error - h.log.Errorf("failed to setup git source repo, trying to cleanup: %+v", ErrFromRemote(resp, err)) + h.log.Errorf("failed to setup git source repo, trying to cleanup: %+v", err) // try to cleanup gitsource configs and remove project // we'll log but ignore errors h.log.Infof("deleting project with ID: %q", rp.ID) - resp, err := h.configstoreClient.DeleteProject(ctx, rp.ID) - if err != nil { - h.log.Errorf("failed to delete project: %+v", ErrFromRemote(resp, err)) + if _, err := h.configstoreClient.DeleteProject(ctx, rp.ID); err != nil { + h.log.Errorf("failed to delete project: %+v", err) } h.log.Infof("cleanup git source repo") if err := h.cleanupGitSourceRepo(ctx, rs, user, la, rp); err != nil { - h.log.Errorf("failed to cleanup git source repo: %+v", ErrFromRemote(resp, err)) + h.log.Errorf("failed to cleanup git source repo: %+v", err) } return nil, errors.Errorf("failed to setup git source repo: %w", serr) } @@ -191,9 +188,9 @@ type UpdateProjectRequest struct { } func (h *ActionHandler) UpdateProject(ctx context.Context, projectRef string, req *UpdateProjectRequest) (*csapitypes.Project, error) { - p, resp, err := h.configstoreClient.GetProject(ctx, projectRef) + p, _, err := h.configstoreClient.GetProject(ctx, projectRef) if err != nil { - return nil, errors.Errorf("failed to get project %q: %w", projectRef, ErrFromRemote(resp, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get project %q: %w", projectRef, err)) } isProjectOwner, err := h.IsProjectOwner(ctx, p.OwnerType, p.OwnerID) @@ -201,7 +198,7 @@ func (h *ActionHandler) UpdateProject(ctx context.Context, projectRef string, re return nil, errors.Errorf("failed to determine ownership: %w", err) } if !isProjectOwner { - return nil, util.NewErrForbidden(errors.Errorf("user not authorized")) + return nil, util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) } if req.Name != nil { @@ -218,9 +215,9 @@ func (h *ActionHandler) UpdateProject(ctx context.Context, projectRef string, re } h.log.Infof("updating project") - rp, resp, err := h.configstoreClient.UpdateProject(ctx, p.ID, p.Project) + rp, _, err := h.configstoreClient.UpdateProject(ctx, p.ID, p.Project) if err != nil { - return nil, errors.Errorf("failed to update project: %w", ErrFromRemote(resp, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to update project: %w", err)) } h.log.Infof("project %s updated, ID: %s", p.Name, p.ID) @@ -230,14 +227,14 @@ func (h *ActionHandler) UpdateProject(ctx context.Context, projectRef string, re func (h *ActionHandler) ProjectUpdateRepoLinkedAccount(ctx context.Context, projectRef string) (*csapitypes.Project, error) { curUserID := common.CurrentUserID(ctx) - user, resp, err := h.configstoreClient.GetUser(ctx, curUserID) + user, _, err := h.configstoreClient.GetUser(ctx, curUserID) if err != nil { - return nil, errors.Errorf("failed to get user %q: %w", curUserID, ErrFromRemote(resp, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get user %q: %w", curUserID, err)) } - p, resp, err := h.configstoreClient.GetProject(ctx, projectRef) + p, _, err := h.configstoreClient.GetProject(ctx, projectRef) if err != nil { - return nil, errors.Errorf("failed to get project %q: %w", projectRef, ErrFromRemote(resp, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get project %q: %w", projectRef, err)) } isProjectOwner, err := h.IsProjectOwner(ctx, p.OwnerType, p.OwnerID) @@ -245,12 +242,12 @@ func (h *ActionHandler) ProjectUpdateRepoLinkedAccount(ctx context.Context, proj return nil, errors.Errorf("failed to determine ownership: %w", err) } if !isProjectOwner { - return nil, util.NewErrForbidden(errors.Errorf("user not authorized")) + return nil, util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) } - rs, resp, err := h.configstoreClient.GetRemoteSource(ctx, p.RemoteSourceID) + rs, _, err := h.configstoreClient.GetRemoteSource(ctx, p.RemoteSourceID) if err != nil { - return nil, errors.Errorf("failed to get remote source %q: %w", p.RemoteSourceID, ErrFromRemote(resp, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get remote source %q: %w", p.RemoteSourceID, err)) } var la *cstypes.LinkedAccount for _, v := range user.LinkedAccounts { @@ -260,7 +257,7 @@ func (h *ActionHandler) ProjectUpdateRepoLinkedAccount(ctx context.Context, proj } } if la == nil { - return nil, util.NewErrBadRequest(errors.Errorf("user doesn't have a linked account for remote source %q", rs.Name)) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("user doesn't have a linked account for remote source %q", rs.Name)) } gitsource, err := h.GetGitSource(ctx, rs, user.Name, la) @@ -277,9 +274,9 @@ func (h *ActionHandler) ProjectUpdateRepoLinkedAccount(ctx context.Context, proj p.LinkedAccountID = la.ID h.log.Infof("updating project") - rp, resp, err := h.configstoreClient.UpdateProject(ctx, p.ID, p.Project) + rp, _, err := h.configstoreClient.UpdateProject(ctx, p.ID, p.Project) if err != nil { - return nil, errors.Errorf("failed to update project: %w", ErrFromRemote(resp, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to update project: %w", err)) } h.log.Infof("project %s updated, ID: %s", p.Name, p.ID) @@ -364,9 +361,9 @@ func (h *ActionHandler) genWebhookURL(project *csapitypes.Project) (string, erro } func (h *ActionHandler) ReconfigProject(ctx context.Context, projectRef string) error { - p, resp, err := h.configstoreClient.GetProject(ctx, projectRef) + p, _, err := h.configstoreClient.GetProject(ctx, projectRef) if err != nil { - return errors.Errorf("failed to get project %q: %w", projectRef, ErrFromRemote(resp, err)) + return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get project %q: %w", projectRef, err)) } isProjectOwner, err := h.IsProjectOwner(ctx, p.OwnerType, p.OwnerID) @@ -374,7 +371,7 @@ func (h *ActionHandler) ReconfigProject(ctx context.Context, projectRef string) return errors.Errorf("failed to determine ownership: %w", err) } if !isProjectOwner { - return util.NewErrForbidden(errors.Errorf("user not authorized")) + return util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) } user, rs, la, err := h.getRemoteRepoAccessData(ctx, p.LinkedAccountID) @@ -388,9 +385,9 @@ func (h *ActionHandler) ReconfigProject(ctx context.Context, projectRef string) } func (h *ActionHandler) DeleteProject(ctx context.Context, projectRef string) error { - p, resp, err := h.configstoreClient.GetProject(ctx, projectRef) + p, _, err := h.configstoreClient.GetProject(ctx, projectRef) if err != nil { - return errors.Errorf("failed to get project %q: %w", projectRef, ErrFromRemote(resp, err)) + return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get project %q: %w", projectRef, err)) } isProjectOwner, err := h.IsProjectOwner(ctx, p.OwnerType, p.OwnerID) @@ -398,7 +395,7 @@ func (h *ActionHandler) DeleteProject(ctx context.Context, projectRef string) er return errors.Errorf("failed to determine ownership: %w", err) } if !isProjectOwner { - return util.NewErrForbidden(errors.Errorf("user not authorized")) + return util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) } // get data needed for repo cleanup @@ -411,9 +408,8 @@ func (h *ActionHandler) DeleteProject(ctx context.Context, projectRef string) er } h.log.Infof("deleting project with ID: %q", p.ID) - resp, err = h.configstoreClient.DeleteProject(ctx, projectRef) - if err != nil { - return ErrFromRemote(resp, err) + if _, err = h.configstoreClient.DeleteProject(ctx, projectRef); err != nil { + return util.NewAPIError(util.KindFromRemoteError(err), err) } // try to cleanup gitsource configs @@ -421,7 +417,7 @@ func (h *ActionHandler) DeleteProject(ctx context.Context, projectRef string) er if canDoRepCleanup { h.log.Infof("cleanup git source repo") if err := h.cleanupGitSourceRepo(ctx, rs, user, la, p); err != nil { - h.log.Errorf("failed to cleanup git source repo: %+v", ErrFromRemote(resp, err)) + h.log.Errorf("failed to cleanup git source repo: %+v", err) } } @@ -431,14 +427,14 @@ func (h *ActionHandler) DeleteProject(ctx context.Context, projectRef string) er func (h *ActionHandler) ProjectCreateRun(ctx context.Context, projectRef, branch, tag, refName, commitSHA string) error { curUserID := common.CurrentUserID(ctx) - user, resp, err := h.configstoreClient.GetUser(ctx, curUserID) + user, _, err := h.configstoreClient.GetUser(ctx, curUserID) if err != nil { - return errors.Errorf("failed to get user %q: %w", curUserID, ErrFromRemote(resp, err)) + return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get user %q: %w", curUserID, err)) } - p, resp, err := h.configstoreClient.GetProject(ctx, projectRef) + p, _, err := h.configstoreClient.GetProject(ctx, projectRef) if err != nil { - return errors.Errorf("failed to get project %q: %w", projectRef, ErrFromRemote(resp, err)) + return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get project %q: %w", projectRef, err)) } isProjectOwner, err := h.IsProjectOwner(ctx, p.OwnerType, p.OwnerID) @@ -446,12 +442,12 @@ func (h *ActionHandler) ProjectCreateRun(ctx context.Context, projectRef, branch return errors.Errorf("failed to determine ownership: %w", err) } if !isProjectOwner { - return util.NewErrForbidden(errors.Errorf("user not authorized")) + return util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) } - rs, resp, err := h.configstoreClient.GetRemoteSource(ctx, p.RemoteSourceID) + rs, _, err := h.configstoreClient.GetRemoteSource(ctx, p.RemoteSourceID) if err != nil { - return errors.Errorf("failed to get remote source %q: %w", p.RemoteSourceID, ErrFromRemote(resp, err)) + return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get remote source %q: %w", p.RemoteSourceID, err)) } var la *cstypes.LinkedAccount for _, v := range user.LinkedAccounts { @@ -461,7 +457,7 @@ func (h *ActionHandler) ProjectCreateRun(ctx context.Context, projectRef, branch } } if la == nil { - return util.NewErrBadRequest(errors.Errorf("user doesn't have a linked account for remote source %q", rs.Name)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user doesn't have a linked account for remote source %q", rs.Name)) } gitSource, err := h.GetGitSource(ctx, rs, user.Name, la) @@ -486,10 +482,10 @@ func (h *ActionHandler) ProjectCreateRun(ctx context.Context, projectRef, branch set++ } if set == 0 { - return util.NewErrBadRequest(errors.Errorf("one of branch, tag or ref is required")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("one of branch, tag or ref is required")) } if set > 1 { - return util.NewErrBadRequest(errors.Errorf("only one of branch, tag or ref can be provided")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("only one of branch, tag or ref can be provided")) } var refType types.RunRefType @@ -508,7 +504,7 @@ func (h *ActionHandler) ProjectCreateRun(ctx context.Context, projectRef, branch gitRefType, name, err := gitSource.RefType(refName) if err != nil { - return util.NewErrBadRequest(errors.Errorf("failed to get refType for ref %q: %w", refName, err)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("failed to get refType for ref %q: %w", refName, err)) } ref, err := gitSource.GetRef(p.RepositoryPath, refName) if err != nil { @@ -587,9 +583,9 @@ func (h *ActionHandler) ProjectCreateRun(ctx context.Context, projectRef, branch } func (h *ActionHandler) getRemoteRepoAccessData(ctx context.Context, linkedAccountID string) (*cstypes.User, *cstypes.RemoteSource, *cstypes.LinkedAccount, error) { - user, resp, err := h.configstoreClient.GetUserByLinkedAccount(ctx, linkedAccountID) + user, _, err := h.configstoreClient.GetUserByLinkedAccount(ctx, linkedAccountID) if err != nil { - return nil, nil, nil, errors.Errorf("failed to get user with linked account id %q: %w", linkedAccountID, ErrFromRemote(resp, err)) + return nil, nil, nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get user with linked account id %q: %w", linkedAccountID, err)) } la := user.LinkedAccounts[linkedAccountID] @@ -597,9 +593,9 @@ func (h *ActionHandler) getRemoteRepoAccessData(ctx context.Context, linkedAccou return nil, nil, nil, errors.Errorf("linked account %q in user %q doesn't exist", linkedAccountID, user.Name) } - rs, resp, err := h.configstoreClient.GetRemoteSource(ctx, la.RemoteSourceID) + rs, _, err := h.configstoreClient.GetRemoteSource(ctx, la.RemoteSourceID) if err != nil { - return nil, nil, nil, errors.Errorf("failed to get remote source %q: %w", la.RemoteSourceID, ErrFromRemote(resp, err)) + return nil, nil, nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get remote source %q: %w", la.RemoteSourceID, err)) } return user, rs, la, nil diff --git a/internal/services/gateway/action/projectgroup.go b/internal/services/gateway/action/projectgroup.go index 350b9f6..5e9a72d 100644 --- a/internal/services/gateway/action/projectgroup.go +++ b/internal/services/gateway/action/projectgroup.go @@ -26,25 +26,25 @@ import ( ) func (h *ActionHandler) GetProjectGroup(ctx context.Context, projectGroupRef string) (*csapitypes.ProjectGroup, error) { - projectGroup, resp, err := h.configstoreClient.GetProjectGroup(ctx, projectGroupRef) + projectGroup, _, err := h.configstoreClient.GetProjectGroup(ctx, projectGroupRef) if err != nil { - return nil, ErrFromRemote(resp, err) + return nil, util.NewAPIError(util.KindFromRemoteError(err), err) } return projectGroup, nil } func (h *ActionHandler) GetProjectGroupSubgroups(ctx context.Context, projectGroupRef string) ([]*csapitypes.ProjectGroup, error) { - projectGroups, resp, err := h.configstoreClient.GetProjectGroupSubgroups(ctx, projectGroupRef) + projectGroups, _, err := h.configstoreClient.GetProjectGroupSubgroups(ctx, projectGroupRef) if err != nil { - return nil, ErrFromRemote(resp, err) + return nil, util.NewAPIError(util.KindFromRemoteError(err), err) } return projectGroups, nil } func (h *ActionHandler) GetProjectGroupProjects(ctx context.Context, projectGroupRef string) ([]*csapitypes.Project, error) { - projects, resp, err := h.configstoreClient.GetProjectGroupProjects(ctx, projectGroupRef) + projects, _, err := h.configstoreClient.GetProjectGroupProjects(ctx, projectGroupRef) if err != nil { - return nil, ErrFromRemote(resp, err) + return nil, util.NewAPIError(util.KindFromRemoteError(err), err) } return projects, nil } @@ -58,12 +58,12 @@ type CreateProjectGroupRequest struct { func (h *ActionHandler) CreateProjectGroup(ctx context.Context, req *CreateProjectGroupRequest) (*csapitypes.ProjectGroup, error) { if !util.ValidateName(req.Name) { - return nil, util.NewErrBadRequest(errors.Errorf("invalid projectGroup name %q", req.Name)) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("invalid projectGroup name %q", req.Name)) } - pg, resp, err := h.configstoreClient.GetProjectGroup(ctx, req.ParentRef) + pg, _, err := h.configstoreClient.GetProjectGroup(ctx, req.ParentRef) if err != nil { - return nil, errors.Errorf("failed to get project group %q: %w", req.ParentRef, ErrFromRemote(resp, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get project group %q: %w", req.ParentRef, err)) } isProjectOwner, err := h.IsProjectOwner(ctx, pg.OwnerType, pg.OwnerID) @@ -71,12 +71,12 @@ func (h *ActionHandler) CreateProjectGroup(ctx context.Context, req *CreateProje return nil, errors.Errorf("failed to determine ownership: %w", err) } if !isProjectOwner { - return nil, util.NewErrForbidden(errors.Errorf("user not authorized")) + return nil, util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) } - user, resp, err := h.configstoreClient.GetUser(ctx, req.CurrentUserID) + user, _, err := h.configstoreClient.GetUser(ctx, req.CurrentUserID) if err != nil { - return nil, errors.Errorf("failed to get user %q: %w", req.CurrentUserID, ErrFromRemote(resp, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get user %q: %w", req.CurrentUserID, err)) } parentRef := req.ParentRef @@ -95,9 +95,9 @@ func (h *ActionHandler) CreateProjectGroup(ctx context.Context, req *CreateProje } h.log.Infof("creating projectGroup") - rp, resp, err := h.configstoreClient.CreateProjectGroup(ctx, p) + rp, _, err := h.configstoreClient.CreateProjectGroup(ctx, p) if err != nil { - return nil, errors.Errorf("failed to create projectGroup: %w", ErrFromRemote(resp, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to create projectGroup: %w", err)) } h.log.Infof("projectGroup %s created, ID: %s", rp.Name, rp.ID) @@ -112,9 +112,9 @@ type UpdateProjectGroupRequest struct { } func (h *ActionHandler) UpdateProjectGroup(ctx context.Context, projectGroupRef string, req *UpdateProjectGroupRequest) (*csapitypes.ProjectGroup, error) { - pg, resp, err := h.configstoreClient.GetProjectGroup(ctx, projectGroupRef) + pg, _, err := h.configstoreClient.GetProjectGroup(ctx, projectGroupRef) if err != nil { - return nil, errors.Errorf("failed to get project group %q: %w", projectGroupRef, ErrFromRemote(resp, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get project group %q: %w", projectGroupRef, err)) } isProjectOwner, err := h.IsProjectOwner(ctx, pg.OwnerType, pg.OwnerID) @@ -122,7 +122,7 @@ func (h *ActionHandler) UpdateProjectGroup(ctx context.Context, projectGroupRef return nil, errors.Errorf("failed to determine ownership: %w", err) } if !isProjectOwner { - return nil, util.NewErrForbidden(errors.Errorf("user not authorized")) + return nil, util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) } if req.Name != nil { @@ -136,9 +136,9 @@ func (h *ActionHandler) UpdateProjectGroup(ctx context.Context, projectGroupRef } h.log.Infof("updating project group") - rp, resp, err := h.configstoreClient.UpdateProjectGroup(ctx, pg.ID, pg.ProjectGroup) + rp, _, err := h.configstoreClient.UpdateProjectGroup(ctx, pg.ID, pg.ProjectGroup) if err != nil { - return nil, errors.Errorf("failed to update project group: %w", ErrFromRemote(resp, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to update project group: %w", err)) } h.log.Infof("project group %q updated, ID: %s", pg.Name, pg.ID) @@ -146,9 +146,9 @@ func (h *ActionHandler) UpdateProjectGroup(ctx context.Context, projectGroupRef } func (h *ActionHandler) DeleteProjectGroup(ctx context.Context, projectRef string) error { - p, resp, err := h.configstoreClient.GetProjectGroup(ctx, projectRef) + p, _, err := h.configstoreClient.GetProjectGroup(ctx, projectRef) if err != nil { - return errors.Errorf("failed to get project %q: %w", projectRef, ErrFromRemote(resp, err)) + return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get project %q: %w", projectRef, err)) } isProjectOwner, err := h.IsProjectOwner(ctx, p.OwnerType, p.OwnerID) @@ -156,12 +156,11 @@ func (h *ActionHandler) DeleteProjectGroup(ctx context.Context, projectRef strin return errors.Errorf("failed to determine ownership: %w", err) } if !isProjectOwner { - return util.NewErrForbidden(errors.Errorf("user not authorized")) + return util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) } - resp, err = h.configstoreClient.DeleteProjectGroup(ctx, projectRef) - if err != nil { - return ErrFromRemote(resp, err) + if _, err = h.configstoreClient.DeleteProjectGroup(ctx, projectRef); err != nil { + return util.NewAPIError(util.KindFromRemoteError(err), err) } return nil } diff --git a/internal/services/gateway/action/remotesource.go b/internal/services/gateway/action/remotesource.go index 4f2cbc0..eebd8d0 100644 --- a/internal/services/gateway/action/remotesource.go +++ b/internal/services/gateway/action/remotesource.go @@ -25,9 +25,9 @@ import ( ) func (h *ActionHandler) GetRemoteSource(ctx context.Context, rsRef string) (*cstypes.RemoteSource, error) { - rs, resp, err := h.configstoreClient.GetRemoteSource(ctx, rsRef) + rs, _, err := h.configstoreClient.GetRemoteSource(ctx, rsRef) if err != nil { - return nil, ErrFromRemote(resp, err) + return nil, err } return rs, nil } @@ -39,9 +39,9 @@ type GetRemoteSourcesRequest struct { } func (h *ActionHandler) GetRemoteSources(ctx context.Context, req *GetRemoteSourcesRequest) ([]*cstypes.RemoteSource, error) { - remoteSources, resp, err := h.configstoreClient.GetRemoteSources(ctx, req.Start, req.Limit, req.Asc) + remoteSources, _, err := h.configstoreClient.GetRemoteSources(ctx, req.Start, req.Limit, req.Asc) if err != nil { - return nil, ErrFromRemote(resp, err) + return nil, err } return remoteSources, nil } @@ -66,33 +66,33 @@ func (h *ActionHandler) CreateRemoteSource(ctx context.Context, req *CreateRemot } if !util.ValidateName(req.Name) { - return nil, util.NewErrBadRequest(errors.Errorf("invalid remotesource name %q", req.Name)) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("invalid remotesource name %q", req.Name)) } if req.Name == "" { - return nil, util.NewErrBadRequest(errors.Errorf("remotesource name required")) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("remotesource name required")) } if req.APIURL == "" { - return nil, util.NewErrBadRequest(errors.Errorf("remotesource api url required")) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("remotesource api url required")) } if req.Type == "" { - return nil, util.NewErrBadRequest(errors.Errorf("remotesource type required")) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("remotesource type required")) } if req.AuthType == "" { - return nil, util.NewErrBadRequest(errors.Errorf("remotesource auth type required")) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("remotesource auth type required")) } // validate if the remote source type supports the required auth type if !cstypes.SourceSupportsAuthType(cstypes.RemoteSourceType(req.Type), cstypes.RemoteSourceAuthType(req.AuthType)) { - return nil, util.NewErrBadRequest(errors.Errorf("remotesource type %q doesn't support auth type %q", req.Type, req.AuthType)) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("remotesource type %q doesn't support auth type %q", req.Type, req.AuthType)) } if req.AuthType == string(cstypes.RemoteSourceAuthTypeOauth2) { if req.Oauth2ClientID == "" { - return nil, util.NewErrBadRequest(errors.Errorf("remotesource oauth2 clientid required")) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("remotesource oauth2 clientid required")) } if req.Oauth2ClientSecret == "" { - return nil, util.NewErrBadRequest(errors.Errorf("remotesource oauth2 client secret required")) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("remotesource oauth2 client secret required")) } } @@ -111,9 +111,9 @@ func (h *ActionHandler) CreateRemoteSource(ctx context.Context, req *CreateRemot } h.log.Infof("creating remotesource") - rs, resp, err := h.configstoreClient.CreateRemoteSource(ctx, rs) + rs, _, err := h.configstoreClient.CreateRemoteSource(ctx, rs) if err != nil { - return nil, errors.Errorf("failed to create remotesource: %w", ErrFromRemote(resp, err)) + return nil, errors.Errorf("failed to create remotesource: %w", err) } h.log.Infof("remotesource %s created, ID: %s", rs.Name, rs.ID) @@ -139,9 +139,9 @@ func (h *ActionHandler) UpdateRemoteSource(ctx context.Context, req *UpdateRemot return nil, errors.Errorf("user not admin") } - rs, resp, err := h.configstoreClient.GetRemoteSource(ctx, req.RemoteSourceRef) + rs, _, err := h.configstoreClient.GetRemoteSource(ctx, req.RemoteSourceRef) if err != nil { - return nil, ErrFromRemote(resp, err) + return nil, err } if req.Name != nil { @@ -173,9 +173,9 @@ func (h *ActionHandler) UpdateRemoteSource(ctx context.Context, req *UpdateRemot } h.log.Infof("updating remotesource") - rs, resp, err = h.configstoreClient.UpdateRemoteSource(ctx, req.RemoteSourceRef, rs) + rs, _, err = h.configstoreClient.UpdateRemoteSource(ctx, req.RemoteSourceRef, rs) if err != nil { - return nil, errors.Errorf("failed to update remotesource: %w", ErrFromRemote(resp, err)) + return nil, errors.Errorf("failed to update remotesource: %w", err) } h.log.Infof("remotesource %s updated", rs.Name) @@ -187,9 +187,8 @@ func (h *ActionHandler) DeleteRemoteSource(ctx context.Context, rsRef string) er return errors.Errorf("user not admin") } - resp, err := h.configstoreClient.DeleteRemoteSource(ctx, rsRef) - if err != nil { - return errors.Errorf("failed to delete remote source: %w", ErrFromRemote(resp, err)) + if _, err := h.configstoreClient.DeleteRemoteSource(ctx, rsRef); err != nil { + return errors.Errorf("failed to delete remote source: %w", err) } return nil } diff --git a/internal/services/gateway/action/run.go b/internal/services/gateway/action/run.go index de0cadb..44b7f30 100644 --- a/internal/services/gateway/action/run.go +++ b/internal/services/gateway/action/run.go @@ -74,16 +74,16 @@ var ( ) func (h *ActionHandler) GetRun(ctx context.Context, runID string) (*rsapitypes.RunResponse, error) { - runResp, resp, err := h.runserviceClient.GetRun(ctx, runID, nil) + runResp, _, err := h.runserviceClient.GetRun(ctx, runID, nil) if err != nil { - return nil, ErrFromRemote(resp, err) + return nil, util.NewAPIError(util.KindFromRemoteError(err), err) } canGetRun, err := h.CanGetRun(ctx, runResp.RunConfig.Group) if err != nil { return nil, errors.Errorf("failed to determine permissions: %w", err) } if !canGetRun { - return nil, util.NewErrForbidden(errors.Errorf("user not authorized")) + return nil, util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) } return runResp, nil @@ -106,13 +106,13 @@ func (h *ActionHandler) GetRuns(ctx context.Context, req *GetRunsRequest) (*rsap return nil, errors.Errorf("failed to determine permissions: %w", err) } if !canGetRun { - return nil, util.NewErrForbidden(errors.Errorf("user not authorized")) + return nil, util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) } groups := []string{req.Group} - runsResp, resp, err := h.runserviceClient.GetRuns(ctx, req.PhaseFilter, req.ResultFilter, groups, req.LastRun, req.ChangeGroups, req.StartRunID, req.Limit, req.Asc) + runsResp, _, err := h.runserviceClient.GetRuns(ctx, req.PhaseFilter, req.ResultFilter, groups, req.LastRun, req.ChangeGroups, req.StartRunID, req.Limit, req.Asc) if err != nil { - return nil, ErrFromRemote(resp, err) + return nil, util.NewAPIError(util.KindFromRemoteError(err), err) } return runsResp, nil @@ -127,21 +127,21 @@ type GetLogsRequest struct { } func (h *ActionHandler) GetLogs(ctx context.Context, req *GetLogsRequest) (*http.Response, error) { - runResp, resp, err := h.runserviceClient.GetRun(ctx, req.RunID, nil) + runResp, _, err := h.runserviceClient.GetRun(ctx, req.RunID, nil) if err != nil { - return nil, ErrFromRemote(resp, err) + return nil, util.NewAPIError(util.KindFromRemoteError(err), err) } canGetRun, err := h.CanGetRun(ctx, runResp.RunConfig.Group) if err != nil { return nil, errors.Errorf("failed to determine permissions: %w", err) } if !canGetRun { - return nil, util.NewErrForbidden(errors.Errorf("user not authorized")) + return nil, util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) } - resp, err = h.runserviceClient.GetLogs(ctx, req.RunID, req.TaskID, req.Setup, req.Step, req.Follow) + resp, err := h.runserviceClient.GetLogs(ctx, req.RunID, req.TaskID, req.Setup, req.Step, req.Follow) if err != nil { - return nil, ErrFromRemote(resp, err) + return nil, util.NewAPIError(util.KindFromRemoteError(err), err) } return resp, nil @@ -155,21 +155,20 @@ type DeleteLogsRequest struct { } func (h *ActionHandler) DeleteLogs(ctx context.Context, req *DeleteLogsRequest) error { - runResp, resp, err := h.runserviceClient.GetRun(ctx, req.RunID, nil) + runResp, _, err := h.runserviceClient.GetRun(ctx, req.RunID, nil) if err != nil { - return ErrFromRemote(resp, err) + return util.NewAPIError(util.KindFromRemoteError(err), err) } canDoRunActions, err := h.CanDoRunActions(ctx, runResp.RunConfig.Group) if err != nil { return errors.Errorf("failed to determine permissions: %w", err) } if !canDoRunActions { - return util.NewErrForbidden(errors.Errorf("user not authorized")) + return util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) } - resp, err = h.runserviceClient.DeleteLogs(ctx, req.RunID, req.TaskID, req.Setup, req.Step) - if err != nil { - return ErrFromRemote(resp, err) + if _, err = h.runserviceClient.DeleteLogs(ctx, req.RunID, req.TaskID, req.Setup, req.Step); err != nil { + return util.NewAPIError(util.KindFromRemoteError(err), err) } return nil @@ -192,16 +191,16 @@ type RunActionsRequest struct { } func (h *ActionHandler) RunAction(ctx context.Context, req *RunActionsRequest) (*rsapitypes.RunResponse, error) { - runResp, resp, err := h.runserviceClient.GetRun(ctx, req.RunID, nil) + runResp, _, err := h.runserviceClient.GetRun(ctx, req.RunID, nil) if err != nil { - return nil, ErrFromRemote(resp, err) + return nil, util.NewAPIError(util.KindFromRemoteError(err), err) } canGetRun, err := h.CanDoRunActions(ctx, runResp.RunConfig.Group) if err != nil { return nil, errors.Errorf("failed to determine permissions: %w", err) } if !canGetRun { - return nil, util.NewErrForbidden(errors.Errorf("user not authorized")) + return nil, util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) } switch req.ActionType { @@ -211,9 +210,9 @@ func (h *ActionHandler) RunAction(ctx context.Context, req *RunActionsRequest) ( FromStart: req.FromStart, } - runResp, resp, err = h.runserviceClient.CreateRun(ctx, rsreq) + runResp, _, err = h.runserviceClient.CreateRun(ctx, rsreq) if err != nil { - return nil, ErrFromRemote(resp, err) + return nil, util.NewAPIError(util.KindFromRemoteError(err), err) } case RunActionTypeCancel: @@ -222,9 +221,8 @@ func (h *ActionHandler) RunAction(ctx context.Context, req *RunActionsRequest) ( Phase: rstypes.RunPhaseCancelled, } - resp, err = h.runserviceClient.RunActions(ctx, req.RunID, rsreq) - if err != nil { - return nil, ErrFromRemote(resp, err) + if _, err = h.runserviceClient.RunActions(ctx, req.RunID, rsreq); err != nil { + return nil, util.NewAPIError(util.KindFromRemoteError(err), err) } case RunActionTypeStop: @@ -232,13 +230,12 @@ func (h *ActionHandler) RunAction(ctx context.Context, req *RunActionsRequest) ( ActionType: rsapitypes.RunActionTypeStop, } - resp, err = h.runserviceClient.RunActions(ctx, req.RunID, rsreq) - if err != nil { - return nil, ErrFromRemote(resp, err) + if _, err = h.runserviceClient.RunActions(ctx, req.RunID, rsreq); err != nil { + return nil, util.NewAPIError(util.KindFromRemoteError(err), err) } default: - return nil, util.NewErrBadRequest(errors.Errorf("wrong run action type %q", req.ActionType)) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("wrong run action type %q", req.ActionType)) } return runResp, nil @@ -258,27 +255,27 @@ type RunTaskActionsRequest struct { } func (h *ActionHandler) RunTaskAction(ctx context.Context, req *RunTaskActionsRequest) error { - runResp, resp, err := h.runserviceClient.GetRun(ctx, req.RunID, nil) + runResp, _, err := h.runserviceClient.GetRun(ctx, req.RunID, nil) if err != nil { - return ErrFromRemote(resp, err) + return util.NewAPIError(util.KindFromRemoteError(err), err) } canDoRunAction, err := h.CanDoRunActions(ctx, runResp.RunConfig.Group) if err != nil { return errors.Errorf("failed to determine permissions: %w", err) } if !canDoRunAction { - return util.NewErrForbidden(errors.Errorf("user not authorized")) + return util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) } curUserID := common.CurrentUserID(ctx) if curUserID == "" { - return util.NewErrBadRequest(errors.Errorf("no logged in user")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("no logged in user")) } switch req.ActionType { case RunTaskActionTypeApprove: rt, ok := runResp.Run.Tasks[req.TaskID] if !ok { - return util.NewErrBadRequest(errors.Errorf("run %q doesn't have task %q", req.RunID, req.TaskID)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("run %q doesn't have task %q", req.RunID, req.TaskID)) } approvers := []string{} @@ -295,7 +292,7 @@ func (h *ActionHandler) RunTaskAction(ctx context.Context, req *RunTaskActionsRe for _, approver := range approvers { if approver == curUserID { - return util.NewErrBadRequest(errors.Errorf("user %q alredy approved the task", approver)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user %q alredy approved the task", approver)) } } approvers = append(approvers, curUserID) @@ -313,13 +310,12 @@ func (h *ActionHandler) RunTaskAction(ctx context.Context, req *RunTaskActionsRe ChangeGroupsUpdateToken: runResp.ChangeGroupsUpdateToken, } - resp, err := h.runserviceClient.RunTaskActions(ctx, req.RunID, req.TaskID, rsreq) - if err != nil { - return ErrFromRemote(resp, err) + if _, err := h.runserviceClient.RunTaskActions(ctx, req.RunID, req.TaskID, rsreq); err != nil { + return util.NewAPIError(util.KindFromRemoteError(err), err) } default: - return util.NewErrBadRequest(errors.Errorf("wrong run task action type %q", req.ActionType)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("wrong run task action type %q", req.ActionType)) } return nil @@ -367,10 +363,10 @@ func (h *ActionHandler) CreateRuns(ctx context.Context, req *CreateRunRequest) e setupErrors := []string{} if req.CommitSHA == "" { - return util.NewErrBadRequest(errors.Errorf("empty commit SHA")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("empty commit SHA")) } if req.Message == "" { - return util.NewErrBadRequest(errors.Errorf("empty message")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("empty message")) } var baseGroupType scommon.GroupType @@ -485,7 +481,7 @@ func (h *ActionHandler) CreateRuns(ctx context.Context, req *CreateRunRequest) e data, filename, err := h.fetchConfigFiles(ctx, req.GitSource, req.RepoPath, req.CommitSHA) if err != nil { - return util.NewErrInternal(errors.Errorf("failed to fetch config file: %w", err)) + return util.NewAPIError(util.ErrInternal, errors.Errorf("failed to fetch config file: %w", err)) } h.log.Debug("data: %s", data) @@ -529,7 +525,7 @@ func (h *ActionHandler) CreateRuns(ctx context.Context, req *CreateRunRequest) e if _, _, err := h.runserviceClient.CreateRun(ctx, createRunReq); err != nil { h.log.Errorf("failed to create run: %+v", err) - return err + return util.NewAPIError(util.KindFromRemoteError(err), err) } return nil } @@ -559,7 +555,7 @@ func (h *ActionHandler) CreateRuns(ctx context.Context, req *CreateRunRequest) e if _, _, err := h.runserviceClient.CreateRun(ctx, createRunReq); err != nil { h.log.Errorf("failed to create run: %+v", err) - return err + return util.NewAPIError(util.KindFromRemoteError(err), err) } } diff --git a/internal/services/gateway/action/secret.go b/internal/services/gateway/action/secret.go index 934257e..1427415 100644 --- a/internal/services/gateway/action/secret.go +++ b/internal/services/gateway/action/secret.go @@ -16,7 +16,6 @@ package action import ( "context" - "net/http" "agola.io/agola/internal/services/common" "agola.io/agola/internal/util" @@ -36,16 +35,15 @@ type GetSecretsRequest struct { func (h *ActionHandler) GetSecrets(ctx context.Context, req *GetSecretsRequest) ([]*csapitypes.Secret, error) { var cssecrets []*csapitypes.Secret - var resp *http.Response var err error switch req.ParentType { case cstypes.ConfigTypeProjectGroup: - cssecrets, resp, err = h.configstoreClient.GetProjectGroupSecrets(ctx, req.ParentRef, req.Tree) + cssecrets, _, err = h.configstoreClient.GetProjectGroupSecrets(ctx, req.ParentRef, req.Tree) case cstypes.ConfigTypeProject: - cssecrets, resp, err = h.configstoreClient.GetProjectSecrets(ctx, req.ParentRef, req.Tree) + cssecrets, _, err = h.configstoreClient.GetProjectSecrets(ctx, req.ParentRef, req.Tree) } if err != nil { - return nil, ErrFromRemote(resp, err) + return nil, util.NewAPIError(util.KindFromRemoteError(err), err) } if req.RemoveOverridden { @@ -78,11 +76,11 @@ func (h *ActionHandler) CreateSecret(ctx context.Context, req *CreateSecretReque return nil, errors.Errorf("failed to determine ownership: %w", err) } if !isVariableOwner { - return nil, util.NewErrForbidden(errors.Errorf("user not authorized")) + return nil, util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) } if !util.ValidateName(req.Name) { - return nil, util.NewErrBadRequest(errors.Errorf("invalid secret name %q", req.Name)) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("invalid secret name %q", req.Name)) } s := &cstypes.Secret{ @@ -91,18 +89,17 @@ func (h *ActionHandler) CreateSecret(ctx context.Context, req *CreateSecretReque Data: req.Data, } - var resp *http.Response var rs *csapitypes.Secret switch req.ParentType { case cstypes.ConfigTypeProjectGroup: h.log.Infof("creating project group secret") - rs, resp, err = h.configstoreClient.CreateProjectGroupSecret(ctx, req.ParentRef, s) + rs, _, err = h.configstoreClient.CreateProjectGroupSecret(ctx, req.ParentRef, s) case cstypes.ConfigTypeProject: h.log.Infof("creating project secret") - rs, resp, err = h.configstoreClient.CreateProjectSecret(ctx, req.ParentRef, s) + rs, _, err = h.configstoreClient.CreateProjectSecret(ctx, req.ParentRef, s) } if err != nil { - return nil, errors.Errorf("failed to create secret: %w", ErrFromRemote(resp, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to create secret: %w", err)) } h.log.Infof("secret %s created, ID: %s", rs.Name, rs.ID) @@ -133,11 +130,11 @@ func (h *ActionHandler) UpdateSecret(ctx context.Context, req *UpdateSecretReque return nil, errors.Errorf("failed to determine ownership: %w", err) } if !isVariableOwner { - return nil, util.NewErrForbidden(errors.Errorf("user not authorized")) + return nil, util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) } if !util.ValidateName(req.Name) { - return nil, util.NewErrBadRequest(errors.Errorf("invalid secret name %q", req.Name)) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("invalid secret name %q", req.Name)) } s := &cstypes.Secret{ @@ -146,18 +143,17 @@ func (h *ActionHandler) UpdateSecret(ctx context.Context, req *UpdateSecretReque Data: req.Data, } - var resp *http.Response var rs *csapitypes.Secret switch req.ParentType { case cstypes.ConfigTypeProjectGroup: h.log.Infof("updating project group secret") - rs, resp, err = h.configstoreClient.UpdateProjectGroupSecret(ctx, req.ParentRef, req.SecretName, s) + rs, _, err = h.configstoreClient.UpdateProjectGroupSecret(ctx, req.ParentRef, req.SecretName, s) case cstypes.ConfigTypeProject: h.log.Infof("updating project secret") - rs, resp, err = h.configstoreClient.UpdateProjectSecret(ctx, req.ParentRef, req.SecretName, s) + rs, _, err = h.configstoreClient.UpdateProjectSecret(ctx, req.ParentRef, req.SecretName, s) } if err != nil { - return nil, errors.Errorf("failed to update secret: %w", ErrFromRemote(resp, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to update secret: %w", err)) } h.log.Infof("secret %s updated, ID: %s", rs.Name, rs.ID) @@ -170,20 +166,19 @@ func (h *ActionHandler) DeleteSecret(ctx context.Context, parentType cstypes.Con return errors.Errorf("failed to determine ownership: %w", err) } if !isVariableOwner { - return util.NewErrForbidden(errors.Errorf("user not authorized")) + return util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) } - var resp *http.Response switch parentType { case cstypes.ConfigTypeProjectGroup: h.log.Infof("deleting project group secret") - resp, err = h.configstoreClient.DeleteProjectGroupSecret(ctx, parentRef, name) + _, err = h.configstoreClient.DeleteProjectGroupSecret(ctx, parentRef, name) case cstypes.ConfigTypeProject: h.log.Infof("deleting project secret") - resp, err = h.configstoreClient.DeleteProjectSecret(ctx, parentRef, name) + _, err = h.configstoreClient.DeleteProjectSecret(ctx, parentRef, name) } if err != nil { - return errors.Errorf("failed to delete secret: %w", ErrFromRemote(resp, err)) + return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to delete secret: %w", err)) } return nil } diff --git a/internal/services/gateway/action/user.go b/internal/services/gateway/action/user.go index ac5cd6b..cf28ab1 100644 --- a/internal/services/gateway/action/user.go +++ b/internal/services/gateway/action/user.go @@ -51,9 +51,9 @@ func (h *ActionHandler) GetUser(ctx context.Context, userRef string) (*cstypes.U return nil, errors.Errorf("user not logged in") } - user, resp, err := h.configstoreClient.GetUser(ctx, userRef) + user, _, err := h.configstoreClient.GetUser(ctx, userRef) if err != nil { - return nil, ErrFromRemote(resp, err) + return nil, util.NewAPIError(util.KindFromRemoteError(err), err) } return user, nil } @@ -63,9 +63,9 @@ func (h *ActionHandler) GetUserOrgs(ctx context.Context, userRef string) ([]*csa return nil, errors.Errorf("user not logged in") } - orgs, resp, err := h.configstoreClient.GetUserOrgs(ctx, userRef) + orgs, _, err := h.configstoreClient.GetUserOrgs(ctx, userRef) if err != nil { - return nil, ErrFromRemote(resp, err) + return nil, util.NewAPIError(util.KindFromRemoteError(err), err) } return orgs, nil } @@ -81,9 +81,9 @@ func (h *ActionHandler) GetUsers(ctx context.Context, req *GetUsersRequest) ([]* return nil, errors.Errorf("user not logged in") } - users, resp, err := h.configstoreClient.GetUsers(ctx, req.Start, req.Limit, req.Asc) + users, _, err := h.configstoreClient.GetUsers(ctx, req.Start, req.Limit, req.Asc) if err != nil { - return nil, ErrFromRemote(resp, err) + return nil, util.NewAPIError(util.KindFromRemoteError(err), err) } return users, nil } @@ -98,10 +98,10 @@ func (h *ActionHandler) CreateUser(ctx context.Context, req *CreateUserRequest) } if req.UserName == "" { - return nil, util.NewErrBadRequest(errors.Errorf("user name required")) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("user name required")) } if !util.ValidateName(req.UserName) { - return nil, util.NewErrBadRequest(errors.Errorf("invalid user name %q", req.UserName)) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("invalid user name %q", req.UserName)) } creq := &csapitypes.CreateUserRequest{ @@ -109,9 +109,9 @@ func (h *ActionHandler) CreateUser(ctx context.Context, req *CreateUserRequest) } h.log.Infof("creating user") - u, resp, err := h.configstoreClient.CreateUser(ctx, creq) + u, _, err := h.configstoreClient.CreateUser(ctx, creq) if err != nil { - return nil, errors.Errorf("failed to create user: %w", ErrFromRemote(resp, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to create user: %w", err)) } h.log.Infof("user %s created, ID: %s", u.Name, u.ID) @@ -128,26 +128,26 @@ func (h *ActionHandler) CreateUserToken(ctx context.Context, req *CreateUserToke userID := common.CurrentUserID(ctx) userRef := req.UserRef - user, resp, err := h.configstoreClient.GetUser(ctx, userRef) + user, _, err := h.configstoreClient.GetUser(ctx, userRef) if err != nil { - return "", errors.Errorf("failed to get user: %w", ErrFromRemote(resp, err)) + return "", util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get user: %w", err)) } // only admin or the same logged user can create a token if !isAdmin && user.ID != userID { - return "", util.NewErrBadRequest(errors.Errorf("logged in user cannot create token for another user")) + return "", util.NewAPIError(util.ErrBadRequest, errors.Errorf("logged in user cannot create token for another user")) } if _, ok := user.Tokens[req.TokenName]; ok { - return "", util.NewErrBadRequest(errors.Errorf("user %q already have a token with name %q", userRef, req.TokenName)) + return "", util.NewAPIError(util.ErrBadRequest, errors.Errorf("user %q already have a token with name %q", userRef, req.TokenName)) } h.log.Infof("creating user token") creq := &csapitypes.CreateUserTokenRequest{ TokenName: req.TokenName, } - res, resp, err := h.configstoreClient.CreateUserToken(ctx, userRef, creq) + res, _, err := h.configstoreClient.CreateUserToken(ctx, userRef, creq) if err != nil { - return "", errors.Errorf("failed to create user token: %w", ErrFromRemote(resp, err)) + return "", util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to create user token: %w", err)) } h.log.Infof("token %q for user %q created", req.TokenName, userRef) @@ -166,13 +166,13 @@ type CreateUserLARequest struct { func (h *ActionHandler) CreateUserLA(ctx context.Context, req *CreateUserLARequest) (*cstypes.LinkedAccount, error) { userRef := req.UserRef - user, resp, err := h.configstoreClient.GetUser(ctx, userRef) + user, _, err := h.configstoreClient.GetUser(ctx, userRef) if err != nil { - return nil, errors.Errorf("failed to get user %q: %w", userRef, ErrFromRemote(resp, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get user %q: %w", userRef, err)) } - rs, resp, err := h.configstoreClient.GetRemoteSource(ctx, req.RemoteSourceName) + rs, _, err := h.configstoreClient.GetRemoteSource(ctx, req.RemoteSourceName) if err != nil { - return nil, errors.Errorf("failed to get remote source %q: %w", req.RemoteSourceName, ErrFromRemote(resp, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get remote source %q: %w", req.RemoteSourceName, err)) } var la *cstypes.LinkedAccount for _, v := range user.LinkedAccounts { @@ -182,7 +182,7 @@ func (h *ActionHandler) CreateUserLA(ctx context.Context, req *CreateUserLAReque } } if la != nil { - return nil, util.NewErrBadRequest(errors.Errorf("user %q already have a linked account for remote source %q", userRef, rs.Name)) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("user %q already have a linked account for remote source %q", userRef, rs.Name)) } accessToken, err := scommon.GetAccessToken(rs, req.UserAccessToken, req.Oauth2AccessToken) @@ -213,9 +213,9 @@ func (h *ActionHandler) CreateUserLA(ctx context.Context, req *CreateUserLAReque } h.log.Infof("creating linked account") - la, resp, err = h.configstoreClient.CreateUserLA(ctx, userRef, creq) + la, _, err = h.configstoreClient.CreateUserLA(ctx, userRef, creq) if err != nil { - return nil, errors.Errorf("failed to create linked account: %w", ErrFromRemote(resp, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to create linked account: %w", err)) } h.log.Infof("linked account %q for user %q created", la.ID, userRef) @@ -223,9 +223,9 @@ func (h *ActionHandler) CreateUserLA(ctx context.Context, req *CreateUserLAReque } func (h *ActionHandler) UpdateUserLA(ctx context.Context, userRef string, la *cstypes.LinkedAccount) error { - user, resp, err := h.configstoreClient.GetUser(ctx, userRef) + user, _, err := h.configstoreClient.GetUser(ctx, userRef) if err != nil { - return errors.Errorf("failed to get user %q: %w", userRef, ErrFromRemote(resp, err)) + return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get user %q: %w", userRef, err)) } laFound := false for _, ula := range user.LinkedAccounts { @@ -235,7 +235,7 @@ func (h *ActionHandler) UpdateUserLA(ctx context.Context, userRef string, la *cs } } if !laFound { - return util.NewErrBadRequest(errors.Errorf("user %q doesn't have a linked account with id %q", userRef, la.ID)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("user %q doesn't have a linked account with id %q", userRef, la.ID)) } creq := &csapitypes.UpdateUserLARequest{ @@ -248,9 +248,9 @@ func (h *ActionHandler) UpdateUserLA(ctx context.Context, userRef string, la *cs } h.log.Infof("updating user %q linked account", userRef) - la, resp, err = h.configstoreClient.UpdateUserLA(ctx, userRef, la.ID, creq) + la, _, err = h.configstoreClient.UpdateUserLA(ctx, userRef, la.ID, creq) if err != nil { - return errors.Errorf("failed to update user: %w", ErrFromRemote(resp, err)) + return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to update user: %w", err)) } h.log.Infof("linked account %q for user %q updated", la.ID, userRef) @@ -307,18 +307,18 @@ type RegisterUserRequest struct { func (h *ActionHandler) RegisterUser(ctx context.Context, req *RegisterUserRequest) (*cstypes.User, error) { if req.UserName == "" { - return nil, util.NewErrBadRequest(errors.Errorf("user name required")) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("user name required")) } if !util.ValidateName(req.UserName) { - return nil, util.NewErrBadRequest(errors.Errorf("invalid user name %q", req.UserName)) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("invalid user name %q", req.UserName)) } - rs, resp, err := h.configstoreClient.GetRemoteSource(ctx, req.RemoteSourceName) + rs, _, err := h.configstoreClient.GetRemoteSource(ctx, req.RemoteSourceName) if err != nil { - return nil, errors.Errorf("failed to get remote source %q: %w", req.RemoteSourceName, ErrFromRemote(resp, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get remote source %q: %w", req.RemoteSourceName, err)) } if !*rs.RegistrationEnabled { - return nil, util.NewErrBadRequest(errors.Errorf("remote source user registration is disabled")) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("remote source user registration is disabled")) } accessToken, err := scommon.GetAccessToken(rs, req.UserAccessToken, req.Oauth2AccessToken) @@ -352,9 +352,9 @@ func (h *ActionHandler) RegisterUser(ctx context.Context, req *RegisterUserReque } h.log.Infof("creating user account") - u, resp, err := h.configstoreClient.CreateUser(ctx, creq) + u, _, err := h.configstoreClient.CreateUser(ctx, creq) if err != nil { - return nil, errors.Errorf("failed to create linked account: %w", ErrFromRemote(resp, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to create linked account: %w", err)) } h.log.Infof("user %q created", req.UserName) @@ -375,12 +375,12 @@ type LoginUserResponse struct { } func (h *ActionHandler) LoginUser(ctx context.Context, req *LoginUserRequest) (*LoginUserResponse, error) { - rs, resp, err := h.configstoreClient.GetRemoteSource(ctx, req.RemoteSourceName) + rs, _, err := h.configstoreClient.GetRemoteSource(ctx, req.RemoteSourceName) if err != nil { - return nil, errors.Errorf("failed to get remote source %q: %w", req.RemoteSourceName, ErrFromRemote(resp, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get remote source %q: %w", req.RemoteSourceName, err)) } if !*rs.LoginEnabled { - return nil, util.NewErrBadRequest(errors.Errorf("remote source user login is disabled")) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("remote source user login is disabled")) } accessToken, err := scommon.GetAccessToken(rs, req.UserAccessToken, req.Oauth2AccessToken) @@ -400,9 +400,9 @@ func (h *ActionHandler) LoginUser(ctx context.Context, req *LoginUserRequest) (* return nil, errors.Errorf("empty remote user id for remote source %q", rs.ID) } - user, resp, err := h.configstoreClient.GetUserByLinkedAccountRemoteUserAndSource(ctx, remoteUserInfo.ID, rs.ID) + user, _, err := h.configstoreClient.GetUserByLinkedAccountRemoteUserAndSource(ctx, remoteUserInfo.ID, rs.ID) if err != nil { - return nil, errors.Errorf("failed to get user for remote user id %q and remote source %q: %w", remoteUserInfo.ID, rs.ID, ErrFromRemote(resp, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get user for remote user id %q and remote source %q: %w", remoteUserInfo.ID, rs.ID, err)) } var la *cstypes.LinkedAccount @@ -435,9 +435,9 @@ func (h *ActionHandler) LoginUser(ctx context.Context, req *LoginUserRequest) (* } h.log.Infof("updating user %q linked account", user.Name) - la, resp, err = h.configstoreClient.UpdateUserLA(ctx, user.Name, la.ID, creq) + la, _, err = h.configstoreClient.UpdateUserLA(ctx, user.Name, la.ID, creq) if err != nil { - return nil, errors.Errorf("failed to update user: %w", ErrFromRemote(resp, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to update user: %w", err)) } h.log.Infof("linked account %q for user %q updated", la.ID, user.Name) } @@ -467,9 +467,9 @@ type AuthorizeResponse struct { } func (h *ActionHandler) Authorize(ctx context.Context, req *AuthorizeRequest) (*AuthorizeResponse, error) { - rs, resp, err := h.configstoreClient.GetRemoteSource(ctx, req.RemoteSourceName) + rs, _, err := h.configstoreClient.GetRemoteSource(ctx, req.RemoteSourceName) if err != nil { - return nil, errors.Errorf("failed to get remote source %q: %w", req.RemoteSourceName, ErrFromRemote(resp, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get remote source %q: %w", req.RemoteSourceName, err)) } accessToken, err := scommon.GetAccessToken(rs, req.UserAccessToken, req.Oauth2AccessToken) @@ -501,18 +501,18 @@ type RemoteSourceAuthResponse struct { } func (h *ActionHandler) HandleRemoteSourceAuth(ctx context.Context, remoteSourceName, loginName, loginPassword string, requestType RemoteSourceRequestType, req interface{}) (*RemoteSourceAuthResponse, error) { - rs, resp, err := h.configstoreClient.GetRemoteSource(ctx, remoteSourceName) + rs, _, err := h.configstoreClient.GetRemoteSource(ctx, remoteSourceName) if err != nil { - return nil, errors.Errorf("failed to get remote source %q: %w", remoteSourceName, ErrFromRemote(resp, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get remote source %q: %w", remoteSourceName, err)) } switch requestType { case RemoteSourceRequestTypeCreateUserLA: req := req.(*CreateUserLARequest) - user, resp, err := h.configstoreClient.GetUser(ctx, req.UserRef) + user, _, err := h.configstoreClient.GetUser(ctx, req.UserRef) if err != nil { - return nil, errors.Errorf("failed to get user %q: %w", req.UserRef, ErrFromRemote(resp, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get user %q: %w", req.UserRef, err)) } curUserID := common.CurrentUserID(ctx) @@ -520,7 +520,7 @@ func (h *ActionHandler) HandleRemoteSourceAuth(ctx context.Context, remoteSource // user must be already logged in the create a linked account and can create a // linked account only on itself. if user.ID != curUserID { - return nil, util.NewErrBadRequest(errors.Errorf("logged in user cannot create linked account for another user")) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("logged in user cannot create linked account for another user")) } var la *cstypes.LinkedAccount @@ -531,7 +531,7 @@ func (h *ActionHandler) HandleRemoteSourceAuth(ctx context.Context, remoteSource } } if la != nil { - return nil, util.NewErrBadRequest(errors.Errorf("user %q already have a linked account for remote source %q", req.UserRef, rs.Name)) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("user %q already have a linked account for remote source %q", req.UserRef, rs.Name)) } case RemoteSourceRequestTypeLoginUser: @@ -572,7 +572,7 @@ func (h *ActionHandler) HandleRemoteSourceAuth(ctx context.Context, remoteSource accessToken, err := passwordSource.LoginPassword(loginName, loginPassword, tokenName) if err != nil { if errors.Is(err, gitsource.ErrUnauthorized) { - return nil, util.NewErrUnauthorized(errors.Errorf("failed to login to remotesource %q: %w", remoteSourceName, err)) + return nil, util.NewAPIError(util.ErrUnauthorized, errors.Errorf("failed to login to remotesource %q: %w", remoteSourceName, err)) } return nil, errors.Errorf("failed to login to remote source %q with login name %q: %w", rs.Name, loginName, err) } @@ -738,9 +738,9 @@ func (h *ActionHandler) HandleOauth2Callback(ctx context.Context, code, state st requestType := RemoteSourceRequestType(claims["request_type"].(string)) requestString := claims["request"].(string) - rs, resp, err := h.configstoreClient.GetRemoteSource(ctx, remoteSourceName) + rs, _, err := h.configstoreClient.GetRemoteSource(ctx, remoteSourceName) if err != nil { - return nil, errors.Errorf("failed to get remote source %q: %w", remoteSourceName, ErrFromRemote(resp, err)) + return nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get remote source %q: %w", remoteSourceName, err)) } oauth2Source, err := scommon.GetOauth2Source(rs, "") @@ -761,9 +761,8 @@ func (h *ActionHandler) DeleteUser(ctx context.Context, userRef string) error { return errors.Errorf("user not logged in") } - resp, err := h.configstoreClient.DeleteUser(ctx, userRef) - if err != nil { - return errors.Errorf("failed to delete user: %w", ErrFromRemote(resp, err)) + if _, err := h.configstoreClient.DeleteUser(ctx, userRef); err != nil { + return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to delete user: %w", err)) } return nil } @@ -776,19 +775,18 @@ func (h *ActionHandler) DeleteUserLA(ctx context.Context, userRef, laID string) isAdmin := common.IsUserAdmin(ctx) curUserID := common.CurrentUserID(ctx) - user, resp, err := h.configstoreClient.GetUser(ctx, userRef) + user, _, err := h.configstoreClient.GetUser(ctx, userRef) if err != nil { - return errors.Errorf("failed to get user %q: %w", userRef, ErrFromRemote(resp, err)) + return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get user %q: %w", userRef, err)) } // only admin or the same logged user can create a token if !isAdmin && user.ID != curUserID { - return util.NewErrBadRequest(errors.Errorf("logged in user cannot create token for another user")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("logged in user cannot create token for another user")) } - resp, err = h.configstoreClient.DeleteUserLA(ctx, userRef, laID) - if err != nil { - return errors.Errorf("failed to delete user linked account: %w", ErrFromRemote(resp, err)) + if _, err = h.configstoreClient.DeleteUserLA(ctx, userRef, laID); err != nil { + return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to delete user linked account: %w", err)) } return nil } @@ -801,19 +799,18 @@ func (h *ActionHandler) DeleteUserToken(ctx context.Context, userRef, tokenName isAdmin := common.IsUserAdmin(ctx) curUserID := common.CurrentUserID(ctx) - user, resp, err := h.configstoreClient.GetUser(ctx, userRef) + user, _, err := h.configstoreClient.GetUser(ctx, userRef) if err != nil { - return errors.Errorf("failed to get user %q: %w", userRef, ErrFromRemote(resp, err)) + return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get user %q: %w", userRef, err)) } // only admin or the same logged user can create a token if !isAdmin && user.ID != curUserID { - return util.NewErrBadRequest(errors.Errorf("logged in user cannot delete token for another user")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("logged in user cannot delete token for another user")) } - resp, err = h.configstoreClient.DeleteUserToken(ctx, userRef, tokenName) - if err != nil { - return errors.Errorf("failed to delete user token: %w", ErrFromRemote(resp, err)) + if _, err = h.configstoreClient.DeleteUserToken(ctx, userRef, tokenName); err != nil { + return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to delete user token: %w", err)) } return nil } @@ -843,21 +840,21 @@ func (h *ActionHandler) UserCreateRun(ctx context.Context, req *UserCreateRunReq curUserID := common.CurrentUserID(ctx) - user, resp, err := h.configstoreClient.GetUser(ctx, curUserID) + user, _, err := h.configstoreClient.GetUser(ctx, curUserID) if err != nil { - return errors.Errorf("failed to get user %q: %w", curUserID, ErrFromRemote(resp, err)) + return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get user %q: %w", curUserID, err)) } // Verify that the repo is owned by the user repoParts := strings.Split(req.RepoPath, "/") if req.RepoUUID == "" { - return util.NewErrBadRequest(errors.Errorf("empty repo uuid")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("empty repo uuid")) } if len(repoParts) != 2 { - return util.NewErrBadRequest(errors.Errorf("wrong repo path: %q", req.RepoPath)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("wrong repo path: %q", req.RepoPath)) } if repoParts[0] != user.ID { - return util.NewErrUnauthorized(errors.Errorf("repo %q not owned", req.RepoPath)) + return util.NewAPIError(util.ErrUnauthorized, errors.Errorf("repo %q not owned", req.RepoPath)) } branch := req.Branch @@ -875,10 +872,10 @@ func (h *ActionHandler) UserCreateRun(ctx context.Context, req *UserCreateRunReq set++ } if set == 0 { - return util.NewErrBadRequest(errors.Errorf("one of branch, tag or ref is required")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("one of branch, tag or ref is required")) } if set > 1 { - return util.NewErrBadRequest(errors.Errorf("only one of branch, tag or ref can be provided")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("only one of branch, tag or ref can be provided")) } gitSource := agolagit.New(h.apiExposedURL+"/repos", prRefRegexes) @@ -895,7 +892,7 @@ func (h *ActionHandler) UserCreateRun(ctx context.Context, req *UserCreateRunReq gitRefType, name, err := gitSource.RefType(ref) if err != nil { - return util.NewErrBadRequest(errors.Errorf("failed to get refType for ref %q: %w", ref, err)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("failed to get refType for ref %q: %w", ref, err)) } var pullRequestID string diff --git a/internal/services/gateway/action/variable.go b/internal/services/gateway/action/variable.go index bb58701..9672325 100644 --- a/internal/services/gateway/action/variable.go +++ b/internal/services/gateway/action/variable.go @@ -16,7 +16,6 @@ package action import ( "context" - "net/http" "agola.io/agola/internal/services/common" "agola.io/agola/internal/util" @@ -40,25 +39,23 @@ func (h *ActionHandler) GetVariables(ctx context.Context, req *GetVariablesReque switch req.ParentType { case cstypes.ConfigTypeProjectGroup: var err error - var resp *http.Response - csvars, resp, err = h.configstoreClient.GetProjectGroupVariables(ctx, req.ParentRef, req.Tree) + csvars, _, err = h.configstoreClient.GetProjectGroupVariables(ctx, req.ParentRef, req.Tree) if err != nil { - return nil, nil, ErrFromRemote(resp, err) + return nil, nil, util.NewAPIError(util.KindFromRemoteError(err), err) } - cssecrets, resp, err = h.configstoreClient.GetProjectGroupSecrets(ctx, req.ParentRef, true) + cssecrets, _, err = h.configstoreClient.GetProjectGroupSecrets(ctx, req.ParentRef, true) if err != nil { - return nil, nil, ErrFromRemote(resp, err) + return nil, nil, util.NewAPIError(util.KindFromRemoteError(err), err) } case cstypes.ConfigTypeProject: var err error - var resp *http.Response - csvars, resp, err = h.configstoreClient.GetProjectVariables(ctx, req.ParentRef, req.Tree) + csvars, _, err = h.configstoreClient.GetProjectVariables(ctx, req.ParentRef, req.Tree) if err != nil { - return nil, nil, ErrFromRemote(resp, err) + return nil, nil, util.NewAPIError(util.KindFromRemoteError(err), err) } - cssecrets, resp, err = h.configstoreClient.GetProjectSecrets(ctx, req.ParentRef, true) + cssecrets, _, err = h.configstoreClient.GetProjectSecrets(ctx, req.ParentRef, true) if err != nil { - return nil, nil, ErrFromRemote(resp, err) + return nil, nil, util.NewAPIError(util.KindFromRemoteError(err), err) } } @@ -85,15 +82,15 @@ func (h *ActionHandler) CreateVariable(ctx context.Context, req *CreateVariableR return nil, nil, errors.Errorf("failed to determine ownership: %w", err) } if !isVariableOwner { - return nil, nil, util.NewErrForbidden(errors.Errorf("user not authorized")) + return nil, nil, util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) } if !util.ValidateName(req.Name) { - return nil, nil, util.NewErrBadRequest(errors.Errorf("invalid variable name %q", req.Name)) + return nil, nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("invalid variable name %q", req.Name)) } if len(req.Values) == 0 { - return nil, nil, util.NewErrBadRequest(errors.Errorf("empty variable values")) + return nil, nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("empty variable values")) } v := &cstypes.Variable{ @@ -111,29 +108,27 @@ func (h *ActionHandler) CreateVariable(ctx context.Context, req *CreateVariableR switch req.ParentType { case cstypes.ConfigTypeProjectGroup: var err error - var resp *http.Response - cssecrets, resp, err = h.configstoreClient.GetProjectGroupSecrets(ctx, req.ParentRef, true) + cssecrets, _, err = h.configstoreClient.GetProjectGroupSecrets(ctx, req.ParentRef, true) if err != nil { - return nil, nil, errors.Errorf("failed to get project group %q secrets: %w", req.ParentRef, ErrFromRemote(resp, err)) + return nil, nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get project group %q secrets: %w", req.ParentRef, err)) } h.log.Infof("creating project group variable") - rv, resp, err = h.configstoreClient.CreateProjectGroupVariable(ctx, req.ParentRef, v) + rv, _, err = h.configstoreClient.CreateProjectGroupVariable(ctx, req.ParentRef, v) if err != nil { - return nil, nil, errors.Errorf("failed to create variable: %w", ErrFromRemote(resp, err)) + return nil, nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to create variable: %w", err)) } case cstypes.ConfigTypeProject: var err error - var resp *http.Response - cssecrets, resp, err = h.configstoreClient.GetProjectSecrets(ctx, req.ParentRef, true) + cssecrets, _, err = h.configstoreClient.GetProjectSecrets(ctx, req.ParentRef, true) if err != nil { - return nil, nil, errors.Errorf("failed to get project %q secrets: %w", req.ParentRef, ErrFromRemote(resp, err)) + return nil, nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get project %q secrets: %w", req.ParentRef, err)) } h.log.Infof("creating project variable") - rv, resp, err = h.configstoreClient.CreateProjectVariable(ctx, req.ParentRef, v) + rv, _, err = h.configstoreClient.CreateProjectVariable(ctx, req.ParentRef, v) if err != nil { - return nil, nil, errors.Errorf("failed to create variable: %w", ErrFromRemote(resp, err)) + return nil, nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to create variable: %w", err)) } } h.log.Infof("variable %s created, ID: %s", rv.Name, rv.ID) @@ -158,15 +153,15 @@ func (h *ActionHandler) UpdateVariable(ctx context.Context, req *UpdateVariableR return nil, nil, errors.Errorf("failed to determine ownership: %w", err) } if !isVariableOwner { - return nil, nil, util.NewErrForbidden(errors.Errorf("user not authorized")) + return nil, nil, util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) } if !util.ValidateName(req.Name) { - return nil, nil, util.NewErrBadRequest(errors.Errorf("invalid variable name %q", req.Name)) + return nil, nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("invalid variable name %q", req.Name)) } if len(req.Values) == 0 { - return nil, nil, util.NewErrBadRequest(errors.Errorf("empty variable values")) + return nil, nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("empty variable values")) } v := &cstypes.Variable{ @@ -184,29 +179,27 @@ func (h *ActionHandler) UpdateVariable(ctx context.Context, req *UpdateVariableR switch req.ParentType { case cstypes.ConfigTypeProjectGroup: var err error - var resp *http.Response - cssecrets, resp, err = h.configstoreClient.GetProjectGroupSecrets(ctx, req.ParentRef, true) + cssecrets, _, err = h.configstoreClient.GetProjectGroupSecrets(ctx, req.ParentRef, true) if err != nil { - return nil, nil, errors.Errorf("failed to get project group %q secrets: %w", req.ParentRef, ErrFromRemote(resp, err)) + return nil, nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get project group %q secrets: %w", req.ParentRef, err)) } h.log.Infof("creating project group variable") - rv, resp, err = h.configstoreClient.UpdateProjectGroupVariable(ctx, req.ParentRef, req.VariableName, v) + rv, _, err = h.configstoreClient.UpdateProjectGroupVariable(ctx, req.ParentRef, req.VariableName, v) if err != nil { - return nil, nil, errors.Errorf("failed to create variable: %w", ErrFromRemote(resp, err)) + return nil, nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to create variable: %w", err)) } case cstypes.ConfigTypeProject: var err error - var resp *http.Response - cssecrets, resp, err = h.configstoreClient.GetProjectSecrets(ctx, req.ParentRef, true) + cssecrets, _, err = h.configstoreClient.GetProjectSecrets(ctx, req.ParentRef, true) if err != nil { - return nil, nil, errors.Errorf("failed to get project %q secrets: %w", req.ParentRef, ErrFromRemote(resp, err)) + return nil, nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to get project %q secrets: %w", req.ParentRef, err)) } h.log.Infof("creating project variable") - rv, resp, err = h.configstoreClient.UpdateProjectVariable(ctx, req.ParentRef, req.VariableName, v) + rv, _, err = h.configstoreClient.UpdateProjectVariable(ctx, req.ParentRef, req.VariableName, v) if err != nil { - return nil, nil, errors.Errorf("failed to create variable: %w", ErrFromRemote(resp, err)) + return nil, nil, util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to create variable: %w", err)) } } h.log.Infof("variable %s created, ID: %s", rv.Name, rv.ID) @@ -220,20 +213,19 @@ func (h *ActionHandler) DeleteVariable(ctx context.Context, parentType cstypes.C return errors.Errorf("failed to determine ownership: %w", err) } if !isVariableOwner { - return util.NewErrForbidden(errors.Errorf("user not authorized")) + return util.NewAPIError(util.ErrForbidden, errors.Errorf("user not authorized")) } - var resp *http.Response switch parentType { case cstypes.ConfigTypeProjectGroup: h.log.Infof("deleting project group variable") - resp, err = h.configstoreClient.DeleteProjectGroupVariable(ctx, parentRef, name) + _, err = h.configstoreClient.DeleteProjectGroupVariable(ctx, parentRef, name) case cstypes.ConfigTypeProject: h.log.Infof("deleting project variable") - resp, err = h.configstoreClient.DeleteProjectVariable(ctx, parentRef, name) + _, err = h.configstoreClient.DeleteProjectVariable(ctx, parentRef, name) } if err != nil { - return errors.Errorf("failed to delete variable: %w", ErrFromRemote(resp, err)) + return util.NewAPIError(util.KindFromRemoteError(err), errors.Errorf("failed to delete variable: %w", err)) } return nil } diff --git a/internal/services/gateway/api/api.go b/internal/services/gateway/api/api.go index a3ced3b..12ee108 100644 --- a/internal/services/gateway/api/api.go +++ b/internal/services/gateway/api/api.go @@ -15,7 +15,6 @@ package api import ( - "encoding/json" "net/http" "net/url" @@ -26,124 +25,11 @@ import ( errors "golang.org/x/xerrors" ) -type ErrorResponse struct { - Message string `json:"message"` -} - -func ErrorResponseFromError(err error) *ErrorResponse { - var aerr error - // use inner errors if of these types - switch { - case util.IsBadRequest(err): - var cerr *util.ErrBadRequest - errors.As(err, &cerr) - aerr = cerr - case util.IsNotExist(err): - var cerr *util.ErrNotExist - errors.As(err, &cerr) - aerr = cerr - case util.IsForbidden(err): - var cerr *util.ErrForbidden - errors.As(err, &cerr) - aerr = cerr - case util.IsUnauthorized(err): - var cerr *util.ErrUnauthorized - errors.As(err, &cerr) - aerr = cerr - case util.IsInternal(err): - var cerr *util.ErrInternal - errors.As(err, &cerr) - aerr = cerr - } - - if aerr != nil { - return &ErrorResponse{Message: aerr.Error()} - } - - // on generic error return an generic message to not leak the real error - return &ErrorResponse{Message: "internal server error"} -} - -func httpError(w http.ResponseWriter, err error) bool { - if err == nil { - return false - } - - response := ErrorResponseFromError(err) - resj, merr := json.Marshal(response) - if merr != nil { - w.WriteHeader(http.StatusInternalServerError) - return true - } - switch { - case util.IsBadRequest(err): - w.WriteHeader(http.StatusBadRequest) - _, _ = w.Write(resj) - case util.IsNotExist(err): - w.WriteHeader(http.StatusNotFound) - _, _ = w.Write(resj) - case util.IsForbidden(err): - w.WriteHeader(http.StatusForbidden) - _, _ = w.Write(resj) - case util.IsUnauthorized(err): - w.WriteHeader(http.StatusUnauthorized) - _, _ = w.Write(resj) - case util.IsInternal(err): - w.WriteHeader(http.StatusInternalServerError) - _, _ = w.Write(resj) - default: - w.WriteHeader(http.StatusInternalServerError) - _, _ = w.Write(resj) - } - return true -} - -func httpResponse(w http.ResponseWriter, code int, res interface{}) error { - w.Header().Set("Content-Type", "application/json") - - if res != nil { - resj, err := json.Marshal(res) - if err != nil { - httpError(w, err) - return err - } - w.WriteHeader(code) - _, err = w.Write(resj) - return err - } - - w.WriteHeader(code) - return nil -} - -func httpErrorFromRemote(w http.ResponseWriter, resp *http.Response, err error) bool { - if err != nil { - // on generic error return an generic message to not leak the real error - response := &ErrorResponse{Message: "internal server error"} - if resp != nil { - response = &ErrorResponse{Message: err.Error()} - } - resj, merr := json.Marshal(response) - if merr != nil { - w.WriteHeader(http.StatusInternalServerError) - return true - } - if resp != nil { - w.WriteHeader(resp.StatusCode) - } else { - w.WriteHeader(http.StatusInternalServerError) - } - _, _ = w.Write(resj) - return true - } - return false -} - func GetConfigTypeRef(r *http.Request) (cstypes.ConfigType, string, error) { vars := mux.Vars(r) projectRef, err := url.PathUnescape(vars["projectref"]) if err != nil { - return "", "", util.NewErrBadRequest(errors.Errorf("wrong projectref %q: %w", vars["projectref"], err)) + return "", "", util.NewAPIError(util.ErrBadRequest, errors.Errorf("wrong projectref %q: %w", vars["projectref"], err)) } if projectRef != "" { return cstypes.ConfigTypeProject, projectRef, nil @@ -151,11 +37,11 @@ func GetConfigTypeRef(r *http.Request) (cstypes.ConfigType, string, error) { projectGroupRef, err := url.PathUnescape(vars["projectgroupref"]) if err != nil { - return "", "", util.NewErrBadRequest(errors.Errorf("wrong projectgroupref %q: %w", vars["projectgroupref"], err)) + return "", "", util.NewAPIError(util.ErrBadRequest, errors.Errorf("wrong projectgroupref %q: %w", vars["projectgroupref"], err)) } if projectGroupRef != "" { return cstypes.ConfigTypeProjectGroup, projectGroupRef, nil } - return "", "", util.NewErrBadRequest(errors.Errorf("cannot get project or projectgroup ref")) + return "", "", util.NewAPIError(util.ErrBadRequest, errors.Errorf("cannot get project or projectgroup ref")) } diff --git a/internal/services/gateway/api/badge.go b/internal/services/gateway/api/badge.go index d4d9fb4..20bba0b 100644 --- a/internal/services/gateway/api/badge.go +++ b/internal/services/gateway/api/badge.go @@ -20,6 +20,7 @@ import ( "agola.io/agola/internal/services/gateway/action" "agola.io/agola/internal/util" + "github.com/gorilla/mux" "go.uber.org/zap" ) @@ -40,13 +41,13 @@ func (h *BadgeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { projectRef, err := url.PathUnescape(vars["projectref"]) if err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } branch := query.Get("branch") badge, err := h.ah.GetBadge(ctx, projectRef, branch) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } diff --git a/internal/services/gateway/api/oauth2.go b/internal/services/gateway/api/oauth2.go index 46cc312..c939714 100644 --- a/internal/services/gateway/api/oauth2.go +++ b/internal/services/gateway/api/oauth2.go @@ -42,7 +42,7 @@ func (h *OAuth2CallbackHandler) ServeHTTP(w http.ResponseWriter, r *http.Request cresp, err := h.ah.HandleOauth2Callback(ctx, code, state) if err != nil { h.log.Errorf("err: %+v", err) - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } @@ -86,7 +86,7 @@ func (h *OAuth2CallbackHandler) ServeHTTP(w http.ResponseWriter, r *http.Request RequestType: string(cresp.RequestType), Response: response, } - if err := httpResponse(w, http.StatusOK, res); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, res); err != nil { h.log.Errorf("err: %+v", err) } } diff --git a/internal/services/gateway/api/org.go b/internal/services/gateway/api/org.go index 45346a3..ec9d048 100644 --- a/internal/services/gateway/api/org.go +++ b/internal/services/gateway/api/org.go @@ -47,7 +47,7 @@ func (h *CreateOrgHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { var req gwapitypes.CreateOrgRequest d := json.NewDecoder(r.Body) if err := d.Decode(&req); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } @@ -58,13 +58,13 @@ func (h *CreateOrgHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } org, err := h.ah.CreateOrg(ctx, creq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } res := createOrgResponse(org) - if err := httpResponse(w, http.StatusCreated, res); err != nil { + if err := util.HTTPResponse(w, http.StatusCreated, res); err != nil { h.log.Errorf("err: %+v", err) } } @@ -84,12 +84,12 @@ func (h *DeleteOrgHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { orgRef := vars["orgref"] err := h.ah.DeleteOrg(ctx, orgRef) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusNoContent, nil); err != nil { + if err := util.HTTPResponse(w, http.StatusNoContent, nil); err != nil { h.log.Errorf("err: %+v", err) } } @@ -109,13 +109,13 @@ func (h *OrgHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { orgRef := vars["orgref"] org, err := h.ah.GetOrg(ctx, orgRef) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } res := createOrgResponse(org) - if err := httpResponse(w, http.StatusOK, res); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, res); err != nil { h.log.Errorf("err: %+v", err) } } @@ -148,12 +148,12 @@ func (h *OrgsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { var err error limit, err = strconv.Atoi(limitS) if err != nil { - httpError(w, util.NewErrBadRequest(errors.Errorf("cannot parse limit: %w", err))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("cannot parse limit: %w", err))) return } } if limit < 0 { - httpError(w, util.NewErrBadRequest(errors.Errorf("limit must be greater or equal than 0"))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("limit must be greater or equal than 0"))) return } if limit > MaxRunsLimit { @@ -172,7 +172,7 @@ func (h *OrgsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { Asc: asc, } csorgs, err := h.ah.GetOrgs(ctx, areq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } @@ -181,7 +181,7 @@ func (h *OrgsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { for i, p := range csorgs { orgs[i] = createOrgResponse(p) } - if err := httpResponse(w, http.StatusOK, orgs); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, orgs); err != nil { h.log.Errorf("err: %+v", err) } } @@ -209,7 +209,7 @@ func (h *OrgMembersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { orgRef := vars["orgref"] ares, err := h.ah.GetOrgMembers(ctx, orgRef) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } @@ -221,7 +221,7 @@ func (h *OrgMembersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { for i, m := range ares.Members { res.Members[i] = createOrgMemberResponse(m.User, m.Role) } - if err := httpResponse(w, http.StatusOK, res); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, res); err != nil { h.log.Errorf("err: %+v", err) } } @@ -255,18 +255,18 @@ func (h *AddOrgMemberHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) var req gwapitypes.AddOrgMemberRequest d := json.NewDecoder(r.Body) if err := d.Decode(&req); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } ares, err := h.ah.AddOrgMember(ctx, orgRef, userRef, cstypes.MemberRole(req.Role)) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } res := createAddOrgMemberResponse(ares.Org, ares.User, ares.OrganizationMember.MemberRole) - if err := httpResponse(w, http.StatusOK, res); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, res); err != nil { h.log.Errorf("err: %+v", err) } } @@ -288,12 +288,12 @@ func (h *RemoveOrgMemberHandler) ServeHTTP(w http.ResponseWriter, r *http.Reques userRef := vars["userref"] err := h.ah.RemoveOrgMember(ctx, orgRef, userRef) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusNoContent, nil); err != nil { + if err := util.HTTPResponse(w, http.StatusNoContent, nil); err != nil { h.log.Errorf("err: %+v", err) } } diff --git a/internal/services/gateway/api/project.go b/internal/services/gateway/api/project.go index 9e8d4f4..d4adf47 100644 --- a/internal/services/gateway/api/project.go +++ b/internal/services/gateway/api/project.go @@ -44,7 +44,7 @@ func (h *CreateProjectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) var req gwapitypes.CreateProjectRequest d := json.NewDecoder(r.Body) if err := d.Decode(&req); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } @@ -59,13 +59,13 @@ func (h *CreateProjectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) } project, err := h.ah.CreateProject(ctx, areq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } res := createProjectResponse(project) - if err := httpResponse(w, http.StatusCreated, res); err != nil { + if err := util.HTTPResponse(w, http.StatusCreated, res); err != nil { h.log.Errorf("err: %+v", err) } } @@ -84,14 +84,14 @@ func (h *UpdateProjectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) vars := mux.Vars(r) projectRef, err := url.PathUnescape(vars["projectref"]) if err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } var req gwapitypes.UpdateProjectRequest d := json.NewDecoder(r.Body) if err := d.Decode(&req); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } @@ -108,13 +108,13 @@ func (h *UpdateProjectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) PassVarsToForkedPR: req.PassVarsToForkedPR, } project, err := h.ah.UpdateProject(ctx, projectRef, areq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } res := createProjectResponse(project) - if err := httpResponse(w, http.StatusCreated, res); err != nil { + if err := util.HTTPResponse(w, http.StatusCreated, res); err != nil { h.log.Errorf("err: %+v", err) } } @@ -133,15 +133,15 @@ func (h *ProjectReconfigHandler) ServeHTTP(w http.ResponseWriter, r *http.Reques vars := mux.Vars(r) projectRef, err := url.PathUnescape(vars["projectref"]) if err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } if err := h.ah.ReconfigProject(ctx, projectRef); err != nil { - httpError(w, err) + util.HTTPError(w, err) return } - if err := httpResponse(w, http.StatusNoContent, nil); err != nil { + if err := util.HTTPResponse(w, http.StatusNoContent, nil); err != nil { h.log.Errorf("err: %+v", err) } } @@ -160,18 +160,18 @@ func (h *ProjectUpdateRepoLinkedAccountHandler) ServeHTTP(w http.ResponseWriter, vars := mux.Vars(r) projectRef, err := url.PathUnescape(vars["projectref"]) if err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } project, err := h.ah.ProjectUpdateRepoLinkedAccount(ctx, projectRef) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } res := createProjectResponse(project) - if err := httpResponse(w, http.StatusOK, res); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, res); err != nil { h.log.Errorf("err: %+v", err) } } @@ -190,17 +190,17 @@ func (h *DeleteProjectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) vars := mux.Vars(r) projectRef, err := url.PathUnescape(vars["projectref"]) if err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } err = h.ah.DeleteProject(ctx, projectRef) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusNoContent, nil); err != nil { + if err := util.HTTPResponse(w, http.StatusNoContent, nil); err != nil { h.log.Errorf("err: %+v", err) } } @@ -219,18 +219,18 @@ func (h *ProjectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) projectRef, err := url.PathUnescape(vars["projectref"]) if err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } project, err := h.ah.GetProject(ctx, projectRef) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } res := createProjectResponse(project) - if err := httpResponse(w, http.StatusOK, res); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, res); err != nil { h.log.Errorf("err: %+v", err) } } @@ -263,24 +263,24 @@ func (h *ProjectCreateRunHandler) ServeHTTP(w http.ResponseWriter, r *http.Reque vars := mux.Vars(r) projectRef, err := url.PathUnescape(vars["projectref"]) if err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } var req gwapitypes.ProjectCreateRunRequest d := json.NewDecoder(r.Body) if err := d.Decode(&req); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } err = h.ah.ProjectCreateRun(ctx, projectRef, req.Branch, req.Tag, req.Ref, req.CommitSHA) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusCreated, nil); err != nil { + if err := util.HTTPResponse(w, http.StatusCreated, nil); err != nil { h.log.Errorf("err: %+v", err) } } diff --git a/internal/services/gateway/api/projectgroup.go b/internal/services/gateway/api/projectgroup.go index 8b9e194..c7ca473 100644 --- a/internal/services/gateway/api/projectgroup.go +++ b/internal/services/gateway/api/projectgroup.go @@ -46,13 +46,13 @@ func (h *CreateProjectGroupHandler) ServeHTTP(w http.ResponseWriter, r *http.Req var req gwapitypes.CreateProjectGroupRequest d := json.NewDecoder(r.Body) if err := d.Decode(&req); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } userID := common.CurrentUserID(ctx) if userID == "" { - httpError(w, util.NewErrBadRequest(errors.Errorf("user not authenticated"))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("user not authenticated"))) return } @@ -64,13 +64,13 @@ func (h *CreateProjectGroupHandler) ServeHTTP(w http.ResponseWriter, r *http.Req } projectGroup, err := h.ah.CreateProjectGroup(ctx, creq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } res := createProjectGroupResponse(projectGroup) - if err := httpResponse(w, http.StatusCreated, res); err != nil { + if err := util.HTTPResponse(w, http.StatusCreated, res); err != nil { h.log.Errorf("err: %+v", err) } } @@ -89,14 +89,14 @@ func (h *UpdateProjectGroupHandler) ServeHTTP(w http.ResponseWriter, r *http.Req vars := mux.Vars(r) projectGroupRef, err := url.PathUnescape(vars["projectgroupref"]) if err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } var req gwapitypes.UpdateProjectGroupRequest d := json.NewDecoder(r.Body) if err := d.Decode(&req); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } @@ -112,13 +112,13 @@ func (h *UpdateProjectGroupHandler) ServeHTTP(w http.ResponseWriter, r *http.Req Visibility: visibility, } projectGroup, err := h.ah.UpdateProjectGroup(ctx, projectGroupRef, areq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } res := createProjectGroupResponse(projectGroup) - if err := httpResponse(w, http.StatusCreated, res); err != nil { + if err := util.HTTPResponse(w, http.StatusCreated, res); err != nil { h.log.Errorf("err: %+v", err) } } @@ -137,17 +137,17 @@ func (h *DeleteProjectGroupHandler) ServeHTTP(w http.ResponseWriter, r *http.Req vars := mux.Vars(r) projectGroupRef, err := url.PathUnescape(vars["projectgroupref"]) if err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } err = h.ah.DeleteProjectGroup(ctx, projectGroupRef) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusNoContent, nil); err != nil { + if err := util.HTTPResponse(w, http.StatusNoContent, nil); err != nil { h.log.Errorf("err: %+v", err) } } @@ -166,18 +166,18 @@ func (h *ProjectGroupHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) vars := mux.Vars(r) projectGroupRef, err := url.PathUnescape(vars["projectgroupref"]) if err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } projectGroup, err := h.ah.GetProjectGroup(ctx, projectGroupRef) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } res := createProjectGroupResponse(projectGroup) - if err := httpResponse(w, http.StatusOK, res); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, res); err != nil { h.log.Errorf("err: %+v", err) } } @@ -196,12 +196,12 @@ func (h *ProjectGroupProjectsHandler) ServeHTTP(w http.ResponseWriter, r *http.R vars := mux.Vars(r) projectGroupRef, err := url.PathUnescape(vars["projectgroupref"]) if err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } csprojects, err := h.ah.GetProjectGroupProjects(ctx, projectGroupRef) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } @@ -211,7 +211,7 @@ func (h *ProjectGroupProjectsHandler) ServeHTTP(w http.ResponseWriter, r *http.R projects[i] = createProjectResponse(p) } - if err := httpResponse(w, http.StatusOK, projects); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, projects); err != nil { h.log.Errorf("err: %+v", err) } } @@ -230,12 +230,12 @@ func (h *ProjectGroupSubgroupsHandler) ServeHTTP(w http.ResponseWriter, r *http. vars := mux.Vars(r) projectGroupRef, err := url.PathUnescape(vars["projectgroupref"]) if err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } cssubgroups, err := h.ah.GetProjectGroupSubgroups(ctx, projectGroupRef) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } @@ -245,7 +245,7 @@ func (h *ProjectGroupSubgroupsHandler) ServeHTTP(w http.ResponseWriter, r *http. subgroups[i] = createProjectGroupResponse(g) } - if err := httpResponse(w, http.StatusOK, subgroups); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, subgroups); err != nil { h.log.Errorf("err: %+v", err) } } diff --git a/internal/services/gateway/api/remoterepo.go b/internal/services/gateway/api/remoterepo.go index 9569cca..c70f97f 100644 --- a/internal/services/gateway/api/remoterepo.go +++ b/internal/services/gateway/api/remoterepo.go @@ -56,18 +56,18 @@ func (h *UserRemoteReposHandler) ServeHTTP(w http.ResponseWriter, r *http.Reques userID := common.CurrentUserID(ctx) if userID == "" { - httpError(w, util.NewErrBadRequest(errors.Errorf("user not authenticated"))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("user not authenticated"))) return } - user, resp, err := h.configstoreClient.GetUser(ctx, userID) - if httpErrorFromRemote(w, resp, err) { + user, _, err := h.configstoreClient.GetUser(ctx, userID) + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - rs, resp, err := h.configstoreClient.GetRemoteSource(ctx, remoteSourceRef) - if httpErrorFromRemote(w, resp, err) { + rs, _, err := h.configstoreClient.GetRemoteSource(ctx, remoteSourceRef) + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } @@ -80,23 +80,23 @@ func (h *UserRemoteReposHandler) ServeHTTP(w http.ResponseWriter, r *http.Reques } } if la == nil { - err := util.NewErrBadRequest(errors.Errorf("user doesn't have a linked account for remote source %q", rs.Name)) - httpError(w, err) + err := util.NewAPIError(util.ErrBadRequest, errors.Errorf("user doesn't have a linked account for remote source %q", rs.Name)) + util.HTTPError(w, err) h.log.Errorf("err: %+v", err) return } gitsource, err := h.ah.GetGitSource(ctx, rs, user.Name, la) if err != nil { - httpError(w, err) + util.HTTPError(w, err) h.log.Errorf("err: %+v", err) return } remoteRepos, err := gitsource.ListUserRepos() if err != nil { - err := util.NewErrBadRequest(errors.Errorf("failed to get user repositories from git source: %w", err)) - httpError(w, err) + err := util.NewAPIError(util.ErrBadRequest, errors.Errorf("failed to get user repositories from git source: %w", err)) + util.HTTPError(w, err) h.log.Errorf("err: %+v", err) return } @@ -105,7 +105,7 @@ func (h *UserRemoteReposHandler) ServeHTTP(w http.ResponseWriter, r *http.Reques for i, r := range remoteRepos { repos[i] = createRemoteRepoResponse(r) } - if err := httpResponse(w, http.StatusOK, repos); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, repos); err != nil { h.log.Errorf("err: %+v", err) } } diff --git a/internal/services/gateway/api/remotesource.go b/internal/services/gateway/api/remotesource.go index b718838..b6a5d61 100644 --- a/internal/services/gateway/api/remotesource.go +++ b/internal/services/gateway/api/remotesource.go @@ -44,7 +44,7 @@ func (h *CreateRemoteSourceHandler) ServeHTTP(w http.ResponseWriter, r *http.Req var req gwapitypes.CreateRemoteSourceRequest d := json.NewDecoder(r.Body) if err := d.Decode(&req); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } @@ -62,13 +62,13 @@ func (h *CreateRemoteSourceHandler) ServeHTTP(w http.ResponseWriter, r *http.Req LoginEnabled: req.LoginEnabled, } rs, err := h.ah.CreateRemoteSource(ctx, creq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } res := createRemoteSourceResponse(rs) - if err := httpResponse(w, http.StatusCreated, res); err != nil { + if err := util.HTTPResponse(w, http.StatusCreated, res); err != nil { h.log.Errorf("err: %+v", err) } } @@ -90,7 +90,7 @@ func (h *UpdateRemoteSourceHandler) ServeHTTP(w http.ResponseWriter, r *http.Req var req gwapitypes.UpdateRemoteSourceRequest d := json.NewDecoder(r.Body) if err := d.Decode(&req); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } @@ -108,13 +108,13 @@ func (h *UpdateRemoteSourceHandler) ServeHTTP(w http.ResponseWriter, r *http.Req LoginEnabled: req.LoginEnabled, } rs, err := h.ah.UpdateRemoteSource(ctx, creq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } res := createRemoteSourceResponse(rs) - if err := httpResponse(w, http.StatusCreated, res); err != nil { + if err := util.HTTPResponse(w, http.StatusCreated, res); err != nil { h.log.Errorf("err: %+v", err) } } @@ -145,13 +145,13 @@ func (h *RemoteSourceHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) rsRef := vars["remotesourceref"] rs, err := h.ah.GetRemoteSource(ctx, rsRef) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } res := createRemoteSourceResponse(rs) - if err := httpResponse(w, http.StatusOK, res); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, res); err != nil { h.log.Errorf("err: %+v", err) } } @@ -175,12 +175,12 @@ func (h *RemoteSourcesHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) var err error limit, err = strconv.Atoi(limitS) if err != nil { - httpError(w, util.NewErrBadRequest(errors.Errorf("cannot parse limit: %w", err))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("cannot parse limit: %w", err))) return } } if limit < 0 { - httpError(w, util.NewErrBadRequest(errors.Errorf("limit must be greater or equal than 0"))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("limit must be greater or equal than 0"))) return } if limit > MaxRunsLimit { @@ -199,7 +199,7 @@ func (h *RemoteSourcesHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) Asc: asc, } csRemoteSources, err := h.ah.GetRemoteSources(ctx, areq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } @@ -209,7 +209,7 @@ func (h *RemoteSourcesHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) remoteSources[i] = createRemoteSourceResponse(rs) } - if err := httpResponse(w, http.StatusOK, remoteSources); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, remoteSources); err != nil { h.log.Errorf("err: %+v", err) } } @@ -229,12 +229,12 @@ func (h *DeleteRemoteSourceHandler) ServeHTTP(w http.ResponseWriter, r *http.Req rsRef := vars["remotesourceref"] err := h.ah.DeleteRemoteSource(ctx, rsRef) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusNoContent, nil); err != nil { + if err := util.HTTPResponse(w, http.StatusNoContent, nil); err != nil { h.log.Errorf("err: %+v", err) } } diff --git a/internal/services/gateway/api/repos.go b/internal/services/gateway/api/repos.go index b64ae45..603ea9c 100644 --- a/internal/services/gateway/api/repos.go +++ b/internal/services/gateway/api/repos.go @@ -19,9 +19,10 @@ import ( "net/http" "net/url" - "go.uber.org/zap" + util "agola.io/agola/internal/util" "github.com/gorilla/mux" + "go.uber.org/zap" ) type ReposHandler struct { @@ -41,7 +42,7 @@ func (h *ReposHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { u, err := url.Parse(h.gitServerURL) if err != nil { h.log.Errorf("err: %+v", err) - httpError(w, err) + util.HTTPError(w, err) return } u.Path = path @@ -53,7 +54,7 @@ func (h *ReposHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { req = req.WithContext(ctx) if err != nil { h.log.Errorf("err: %+v", err) - httpError(w, err) + util.HTTPError(w, err) return } @@ -67,7 +68,7 @@ func (h *ReposHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { resp, err := http.DefaultClient.Do(req) if err != nil { h.log.Errorf("err: %+v", err) - httpError(w, err) + util.HTTPError(w, err) return } @@ -84,7 +85,7 @@ func (h *ReposHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // copy response body if _, err := io.Copy(w, resp.Body); err != nil { h.log.Errorf("err: %+v", err) - httpError(w, err) + util.HTTPError(w, err) return } } diff --git a/internal/services/gateway/api/run.go b/internal/services/gateway/api/run.go index 8c19f43..e85c7d5 100644 --- a/internal/services/gateway/api/run.go +++ b/internal/services/gateway/api/run.go @@ -164,13 +164,13 @@ func (h *RunHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { runID := vars["runid"] runResp, err := h.ah.GetRun(ctx, runID) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } res := createRunResponse(runResp.Run, runResp.RunConfig) - if err := httpResponse(w, http.StatusOK, res); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, res); err != nil { h.log.Errorf("err: %+v", err) } } @@ -191,7 +191,7 @@ func (h *RuntaskHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { taskID := vars["taskid"] runResp, err := h.ah.GetRun(ctx, runID) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } @@ -201,13 +201,13 @@ func (h *RuntaskHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { rt, ok := run.Tasks[taskID] if !ok { - httpError(w, util.NewErrNotExist(errors.Errorf("run %q task %q not found", runID, taskID))) + util.HTTPError(w, util.NewAPIError(util.ErrNotExist, errors.Errorf("run %q task %q not found", runID, taskID))) return } rct := rc.Tasks[rt.ID] res := createRunTaskResponse(rt, rct) - if err := httpResponse(w, http.StatusOK, res); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, res); err != nil { h.log.Errorf("err: %+v", err) } } @@ -254,7 +254,7 @@ func (h *RunsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { group := q.Get("group") // we require that groups are specified to not return all runs if group == "" { - httpError(w, util.NewErrBadRequest(errors.Errorf("no groups specified"))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("no groups specified"))) return } @@ -269,12 +269,12 @@ func (h *RunsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { var err error limit, err = strconv.Atoi(limitS) if err != nil { - httpError(w, util.NewErrBadRequest(errors.Errorf("cannot parse limit: %w", err))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("cannot parse limit: %w", err))) return } } if limit < 0 { - httpError(w, util.NewErrBadRequest(errors.Errorf("limit must be greater or equal than 0"))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("limit must be greater or equal than 0"))) return } if limit > MaxRunsLimit { @@ -298,7 +298,7 @@ func (h *RunsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { Asc: asc, } runsResp, err := h.ah.GetRuns(ctx, areq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } @@ -307,7 +307,7 @@ func (h *RunsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { for i, r := range runsResp.Runs { runs[i] = createRunsResponse(r) } - if err := httpResponse(w, http.StatusOK, runs); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, runs); err != nil { h.log.Errorf("err: %+v", err) } } @@ -329,7 +329,7 @@ func (h *RunActionsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { var req gwapitypes.RunActionsRequest d := json.NewDecoder(r.Body) if err := d.Decode(&req); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } @@ -340,13 +340,13 @@ func (h *RunActionsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } runResp, err := h.ah.RunAction(ctx, areq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } res := createRunResponse(runResp.Run, runResp.RunConfig) - if err := httpResponse(w, http.StatusOK, res); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, res); err != nil { h.log.Errorf("err: %+v", err) } } @@ -369,7 +369,7 @@ func (h *RunTaskActionsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request var req gwapitypes.RunTaskActionsRequest d := json.NewDecoder(r.Body) if err := d.Decode(&req); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } @@ -380,7 +380,7 @@ func (h *RunTaskActionsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request } err := h.ah.RunTaskAction(ctx, areq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } @@ -402,23 +402,23 @@ func (h *LogsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { runID := q.Get("runID") if runID == "" { - httpError(w, util.NewErrBadRequest(errors.Errorf("empty run id"))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("empty run id"))) return } taskID := q.Get("taskID") if taskID == "" { - httpError(w, util.NewErrBadRequest(errors.Errorf("empty task id"))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("empty task id"))) return } _, setup := q["setup"] stepStr := q.Get("step") if !setup && stepStr == "" { - httpError(w, util.NewErrBadRequest(errors.Errorf("no setup or step number provided"))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("no setup or step number provided"))) return } if setup && stepStr != "" { - httpError(w, util.NewErrBadRequest(errors.Errorf("both setup and step number provided"))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("both setup and step number provided"))) return } @@ -427,7 +427,7 @@ func (h *LogsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { var err error step, err = strconv.Atoi(stepStr) if err != nil { - httpError(w, util.NewErrBadRequest(errors.Errorf("cannot parse step number: %w", err))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("cannot parse step number: %w", err))) return } } @@ -446,7 +446,7 @@ func (h *LogsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } resp, err := h.ah.GetLogs(ctx, areq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } @@ -519,23 +519,23 @@ func (h *LogsDeleteHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { runID := q.Get("runID") if runID == "" { - httpError(w, util.NewErrBadRequest(errors.Errorf("empty run id"))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("empty run id"))) return } taskID := q.Get("taskID") if taskID == "" { - httpError(w, util.NewErrBadRequest(errors.Errorf("empty task id"))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("empty task id"))) return } _, setup := q["setup"] stepStr := q.Get("step") if !setup && stepStr == "" { - httpError(w, util.NewErrBadRequest(errors.Errorf("no setup or step number provided"))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("no setup or step number provided"))) return } if setup && stepStr != "" { - httpError(w, util.NewErrBadRequest(errors.Errorf("both setup and step number provided"))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("both setup and step number provided"))) return } @@ -544,7 +544,7 @@ func (h *LogsDeleteHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { var err error step, err = strconv.Atoi(stepStr) if err != nil { - httpError(w, util.NewErrBadRequest(errors.Errorf("cannot parse step number: %w", err))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("cannot parse step number: %w", err))) return } } @@ -557,7 +557,7 @@ func (h *LogsDeleteHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } err := h.ah.DeleteLogs(ctx, areq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } diff --git a/internal/services/gateway/api/secret.go b/internal/services/gateway/api/secret.go index 9a5e33b..db5d4ff 100644 --- a/internal/services/gateway/api/secret.go +++ b/internal/services/gateway/api/secret.go @@ -52,7 +52,7 @@ func (h *SecretHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { _, removeoverridden := query["removeoverridden"] parentType, parentRef, err := GetConfigTypeRef(r) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } @@ -64,7 +64,7 @@ func (h *SecretHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { RemoveOverridden: removeoverridden, } cssecrets, err := h.ah.GetSecrets(ctx, areq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } @@ -74,7 +74,7 @@ func (h *SecretHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { secrets[i] = createSecretResponse(s) } - if err := httpResponse(w, http.StatusOK, secrets); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, secrets); err != nil { h.log.Errorf("err: %+v", err) } } @@ -91,14 +91,14 @@ func NewCreateSecretHandler(logger *zap.Logger, ah *action.ActionHandler) *Creat func (h *CreateSecretHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { ctx := r.Context() parentType, parentRef, err := GetConfigTypeRef(r) - if httpError(w, err) { + if util.HTTPError(w, err) { return } var req gwapitypes.CreateSecretRequest d := json.NewDecoder(r.Body) if err := d.Decode(&req); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } @@ -112,13 +112,13 @@ func (h *CreateSecretHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) Path: req.Path, } cssecret, err := h.ah.CreateSecret(ctx, areq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } res := createSecretResponse(cssecret) - if err := httpResponse(w, http.StatusCreated, res); err != nil { + if err := util.HTTPResponse(w, http.StatusCreated, res); err != nil { h.log.Errorf("err: %+v", err) } } @@ -138,7 +138,7 @@ func (h *UpdateSecretHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) secretName := vars["secretname"] parentType, parentRef, err := GetConfigTypeRef(r) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } @@ -146,7 +146,7 @@ func (h *UpdateSecretHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) var req gwapitypes.UpdateSecretRequest d := json.NewDecoder(r.Body) if err := d.Decode(&req); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } areq := &action.UpdateSecretRequest{ @@ -161,13 +161,13 @@ func (h *UpdateSecretHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) Path: req.Path, } cssecret, err := h.ah.UpdateSecret(ctx, areq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } res := createSecretResponse(cssecret) - if err := httpResponse(w, http.StatusOK, res); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, res); err != nil { h.log.Errorf("err: %+v", err) } } @@ -187,17 +187,17 @@ func (h *DeleteSecretHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) secretName := vars["secretname"] parentType, parentRef, err := GetConfigTypeRef(r) - if httpError(w, err) { + if util.HTTPError(w, err) { return } err = h.ah.DeleteSecret(ctx, parentType, parentRef, secretName) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusNoContent, nil); err != nil { + if err := util.HTTPResponse(w, http.StatusNoContent, nil); err != nil { h.log.Errorf("err: %+v", err) } } diff --git a/internal/services/gateway/api/user.go b/internal/services/gateway/api/user.go index e8c25d8..f84a68c 100644 --- a/internal/services/gateway/api/user.go +++ b/internal/services/gateway/api/user.go @@ -48,7 +48,7 @@ func (h *CreateUserHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { var req gwapitypes.CreateUserRequest d := json.NewDecoder(r.Body) if err := d.Decode(&req); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } @@ -57,13 +57,13 @@ func (h *CreateUserHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } u, err := h.ah.CreateUser(ctx, creq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } res := createUserResponse(u) - if err := httpResponse(w, http.StatusCreated, res); err != nil { + if err := util.HTTPResponse(w, http.StatusCreated, res); err != nil { h.log.Errorf("err: %+v", err) } } @@ -83,12 +83,12 @@ func (h *DeleteUserHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { userRef := vars["userref"] err := h.ah.DeleteUser(ctx, userRef) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusNoContent, nil); err != nil { + if err := util.HTTPResponse(w, http.StatusNoContent, nil); err != nil { h.log.Errorf("err: %+v", err) } } @@ -107,18 +107,18 @@ func (h *CurrentUserHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { userID := common.CurrentUserID(ctx) if userID == "" { - httpError(w, util.NewErrBadRequest(errors.Errorf("user not authenticated"))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("user not authenticated"))) return } user, err := h.ah.GetUser(ctx, userID) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } res := createUserResponse(user) - if err := httpResponse(w, http.StatusOK, res); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, res); err != nil { h.log.Errorf("err: %+v", err) } } @@ -138,13 +138,13 @@ func (h *UserHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { userRef := vars["userref"] user, err := h.ah.GetUser(ctx, userRef) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } res := createUserResponse(user) - if err := httpResponse(w, http.StatusOK, res); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, res); err != nil { h.log.Errorf("err: %+v", err) } } @@ -193,12 +193,12 @@ func (h *UsersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { var err error limit, err = strconv.Atoi(limitS) if err != nil { - httpError(w, util.NewErrBadRequest(errors.Errorf("cannot parse limit: %w", err))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("cannot parse limit: %w", err))) return } } if limit < 0 { - httpError(w, util.NewErrBadRequest(errors.Errorf("limit must be greater or equal than 0"))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("limit must be greater or equal than 0"))) return } if limit > MaxRunsLimit { @@ -217,7 +217,7 @@ func (h *UsersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { Asc: asc, } csusers, err := h.ah.GetUsers(ctx, areq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } @@ -227,7 +227,7 @@ func (h *UsersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { users[i] = createUserResponse(p) } - if err := httpResponse(w, http.StatusOK, users); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, users); err != nil { h.log.Errorf("err: %+v", err) } } @@ -249,17 +249,17 @@ func (h *CreateUserLAHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) var req *gwapitypes.CreateUserLARequest d := json.NewDecoder(r.Body) if err := d.Decode(&req); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } res, err := h.createUserLA(ctx, userRef, req) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusCreated, res); err != nil { + if err := util.HTTPResponse(w, http.StatusCreated, res); err != nil { h.log.Errorf("err: %+v", err) } } @@ -311,12 +311,12 @@ func (h *DeleteUserLAHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) laID := vars["laid"] err := h.ah.DeleteUserLA(ctx, userRef, laID) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusNoContent, nil); err != nil { + if err := util.HTTPResponse(w, http.StatusNoContent, nil); err != nil { h.log.Errorf("err: %+v", err) } } @@ -338,7 +338,7 @@ func (h *CreateUserTokenHandler) ServeHTTP(w http.ResponseWriter, r *http.Reques var req gwapitypes.CreateUserTokenRequest d := json.NewDecoder(r.Body) if err := d.Decode(&req); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } @@ -348,7 +348,7 @@ func (h *CreateUserTokenHandler) ServeHTTP(w http.ResponseWriter, r *http.Reques } h.log.Infof("creating user %q token", userRef) token, err := h.ah.CreateUserToken(ctx, creq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } @@ -357,7 +357,7 @@ func (h *CreateUserTokenHandler) ServeHTTP(w http.ResponseWriter, r *http.Reques Token: token, } - if err := httpResponse(w, http.StatusCreated, res); err != nil { + if err := util.HTTPResponse(w, http.StatusCreated, res); err != nil { h.log.Errorf("err: %+v", err) } } @@ -379,12 +379,12 @@ func (h *DeleteUserTokenHandler) ServeHTTP(w http.ResponseWriter, r *http.Reques h.log.Infof("deleting user %q token %q", userRef, tokenName) err := h.ah.DeleteUserToken(ctx, userRef, tokenName) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusNoContent, nil); err != nil { + if err := util.HTTPResponse(w, http.StatusNoContent, nil); err != nil { h.log.Errorf("err: %+v", err) } } @@ -404,17 +404,17 @@ func (h *RegisterUserHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) var req *gwapitypes.RegisterUserRequest d := json.NewDecoder(r.Body) if err := d.Decode(&req); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } res, err := h.registerUser(ctx, req) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusCreated, res); err != nil { + if err := util.HTTPResponse(w, http.StatusCreated, res); err != nil { h.log.Errorf("err: %+v", err) } } @@ -455,17 +455,17 @@ func (h *AuthorizeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { var req *gwapitypes.LoginUserRequest d := json.NewDecoder(r.Body) if err := d.Decode(&req); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } res, err := h.authorize(ctx, req) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusCreated, res); err != nil { + if err := util.HTTPResponse(w, http.StatusCreated, res); err != nil { h.log.Errorf("err: %+v", err) } } @@ -512,17 +512,17 @@ func (h *LoginUserHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { var req *gwapitypes.LoginUserRequest d := json.NewDecoder(r.Body) if err := d.Decode(&req); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } res, err := h.loginUser(ctx, req) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusCreated, res); err != nil { + if err := util.HTTPResponse(w, http.StatusCreated, res); err != nil { h.log.Errorf("err: %+v", err) } } @@ -566,7 +566,7 @@ func (h *UserCreateRunHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) var req gwapitypes.UserCreateRunRequest d := json.NewDecoder(r.Body) if err := d.Decode(&req); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } @@ -582,12 +582,12 @@ func (h *UserCreateRunHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) Variables: req.Variables, } err := h.ah.UserCreateRun(ctx, creq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusCreated, nil); err != nil { + if err := util.HTTPResponse(w, http.StatusCreated, nil); err != nil { h.log.Errorf("err: %+v", err) } } @@ -606,12 +606,12 @@ func (h *UserOrgsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { userID := common.CurrentUserID(ctx) if userID == "" { - httpError(w, util.NewErrBadRequest(errors.Errorf("user not authenticated"))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("user not authenticated"))) return } userOrgs, err := h.ah.GetUserOrgs(ctx, userID) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } @@ -621,7 +621,7 @@ func (h *UserOrgsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { res[i] = createUserOrgsResponse(userOrg) } - if err := httpResponse(w, http.StatusOK, res); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, res); err != nil { h.log.Errorf("err: %+v", err) } } diff --git a/internal/services/gateway/api/variable.go b/internal/services/gateway/api/variable.go index 9a80f47..8a14f5a 100644 --- a/internal/services/gateway/api/variable.go +++ b/internal/services/gateway/api/variable.go @@ -69,7 +69,7 @@ func (h *VariableHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { _, removeoverridden := query["removeoverridden"] parentType, parentRef, err := GetConfigTypeRef(r) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } @@ -81,7 +81,7 @@ func (h *VariableHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { RemoveOverridden: removeoverridden, } csvars, cssecrets, err := h.ah.GetVariables(ctx, areq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } @@ -91,7 +91,7 @@ func (h *VariableHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { variables[i] = createVariableResponse(v, cssecrets) } - if err := httpResponse(w, http.StatusOK, variables); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, variables); err != nil { h.log.Errorf("err: %+v", err) } } @@ -108,7 +108,7 @@ func NewCreateVariableHandler(logger *zap.Logger, ah *action.ActionHandler) *Cre func (h *CreateVariableHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { ctx := r.Context() parentType, parentRef, err := GetConfigTypeRef(r) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } @@ -116,7 +116,7 @@ func (h *CreateVariableHandler) ServeHTTP(w http.ResponseWriter, r *http.Request var req gwapitypes.CreateVariableRequest d := json.NewDecoder(r.Body) if err := d.Decode(&req); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } areq := &action.CreateVariableRequest{ @@ -126,13 +126,13 @@ func (h *CreateVariableHandler) ServeHTTP(w http.ResponseWriter, r *http.Request Values: fromApiVariableValues(req.Values), } csvar, cssecrets, err := h.ah.CreateVariable(ctx, areq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } res := createVariableResponse(csvar, cssecrets) - if err := httpResponse(w, http.StatusCreated, res); err != nil { + if err := util.HTTPResponse(w, http.StatusCreated, res); err != nil { h.log.Errorf("err: %+v", err) } } @@ -152,7 +152,7 @@ func (h *UpdateVariableHandler) ServeHTTP(w http.ResponseWriter, r *http.Request variableName := vars["variablename"] parentType, parentRef, err := GetConfigTypeRef(r) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } @@ -160,7 +160,7 @@ func (h *UpdateVariableHandler) ServeHTTP(w http.ResponseWriter, r *http.Request var req gwapitypes.UpdateVariableRequest d := json.NewDecoder(r.Body) if err := d.Decode(&req); err != nil { - httpError(w, util.NewErrBadRequest(err)) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, err)) return } @@ -173,13 +173,13 @@ func (h *UpdateVariableHandler) ServeHTTP(w http.ResponseWriter, r *http.Request Values: fromApiVariableValues(req.Values), } csvar, cssecrets, err := h.ah.UpdateVariable(ctx, areq) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } res := createVariableResponse(csvar, cssecrets) - if err := httpResponse(w, http.StatusOK, res); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, res); err != nil { h.log.Errorf("err: %+v", err) } } @@ -199,18 +199,18 @@ func (h *DeleteVariableHandler) ServeHTTP(w http.ResponseWriter, r *http.Request variableName := vars["variablename"] parentType, parentRef, err := GetConfigTypeRef(r) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } err = h.ah.DeleteVariable(ctx, parentType, parentRef, variableName) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusNoContent, nil); err != nil { + if err := util.HTTPResponse(w, http.StatusNoContent, nil); err != nil { h.log.Errorf("err: %+v", err) } } diff --git a/internal/services/gateway/api/version.go b/internal/services/gateway/api/version.go index 8062a76..461e15b 100644 --- a/internal/services/gateway/api/version.go +++ b/internal/services/gateway/api/version.go @@ -18,6 +18,7 @@ import ( "net/http" "agola.io/agola/internal/services/gateway/action" + util "agola.io/agola/internal/util" "go.uber.org/zap" ) @@ -35,12 +36,12 @@ func (h *VersionHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { ctx := r.Context() version, err := h.ah.GetVersion(ctx) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusOK, version); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, version); err != nil { h.log.Errorf("err: %+v", err) } } diff --git a/internal/services/gateway/api/webhook.go b/internal/services/gateway/api/webhook.go index ba916a9..c406bd7 100644 --- a/internal/services/gateway/api/webhook.go +++ b/internal/services/gateway/api/webhook.go @@ -48,12 +48,12 @@ func NewWebhooksHandler(logger *zap.Logger, ah *action.ActionHandler, configstor func (h *webhooksHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { err := h.handleWebhook(r) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusOK, nil); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, nil); err != nil { h.log.Errorf("err: %+v", err) } } @@ -63,33 +63,33 @@ func (h *webhooksHandler) handleWebhook(r *http.Request) error { projectID := r.URL.Query().Get("projectid") if projectID == "" { - return util.NewErrBadRequest(errors.Errorf("bad webhook url %q. Missing projectid", r.URL)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("bad webhook url %q. Missing projectid", r.URL)) } defer r.Body.Close() csProject, _, err := h.configstoreClient.GetProject(ctx, projectID) if err != nil { - return util.NewErrBadRequest(errors.Errorf("failed to get project %s: %w", projectID, err)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("failed to get project %s: %w", projectID, err)) } project := csProject.Project user, _, err := h.configstoreClient.GetUserByLinkedAccount(ctx, project.LinkedAccountID) if err != nil { - return util.NewErrInternal(errors.Errorf("failed to get user by linked account %q: %w", project.LinkedAccountID, err)) + return util.NewAPIError(util.ErrInternal, errors.Errorf("failed to get user by linked account %q: %w", project.LinkedAccountID, err)) } la := user.LinkedAccounts[project.LinkedAccountID] if la == nil { - return util.NewErrInternal(errors.Errorf("linked account %q in user %q doesn't exist", project.LinkedAccountID, user.Name)) + return util.NewAPIError(util.ErrInternal, errors.Errorf("linked account %q in user %q doesn't exist", project.LinkedAccountID, user.Name)) } rs, _, err := h.configstoreClient.GetRemoteSource(ctx, la.RemoteSourceID) if err != nil { - return util.NewErrInternal(errors.Errorf("failed to get remote source %q: %w", la.RemoteSourceID, err)) + return util.NewAPIError(util.ErrInternal, errors.Errorf("failed to get remote source %q: %w", la.RemoteSourceID, err)) } gitSource, err := h.ah.GetGitSource(ctx, rs, user.Name, la) if err != nil { - return util.NewErrInternal(errors.Errorf("failed to create gitea client: %w", err)) + return util.NewAPIError(util.ErrInternal, errors.Errorf("failed to create gitea client: %w", err)) } sshPrivKey := project.SSHPrivateKey @@ -102,7 +102,7 @@ func (h *webhooksHandler) handleWebhook(r *http.Request) error { webhookData, err := gitSource.ParseWebhook(r, project.WebhookSecret) if err != nil { - return util.NewErrBadRequest(errors.Errorf("failed to parse webhook: %w", err)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("failed to parse webhook: %w", err)) } // skip nil webhook data // TODO(sgotti) report the reason of the skip @@ -141,7 +141,7 @@ func (h *webhooksHandler) handleWebhook(r *http.Request) error { CompareLink: webhookData.CompareLink, } if err := h.ah.CreateRuns(ctx, req); err != nil { - return util.NewErrInternal(errors.Errorf("failed to create run: %w", err)) + return util.NewAPIError(util.ErrInternal, errors.Errorf("failed to create run: %w", err)) } return nil diff --git a/internal/services/gateway/handlers/auth.go b/internal/services/gateway/handlers/auth.go index 354e8a7..7d114bf 100644 --- a/internal/services/gateway/handlers/auth.go +++ b/internal/services/gateway/handlers/auth.go @@ -21,6 +21,7 @@ import ( scommon "agola.io/agola/internal/services/common" "agola.io/agola/internal/services/gateway/common" + "agola.io/agola/internal/util" csclient "agola.io/agola/services/configstore/client" "github.com/golang-jwt/jwt/v4" @@ -64,12 +65,12 @@ func (h *AuthHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { h.next.ServeHTTP(w, r.WithContext(ctx)) return } else { - user, resp, err := h.configstoreClient.GetUserByToken(ctx, tokenString) - if err != nil && resp.StatusCode == http.StatusNotFound { - http.Error(w, "", http.StatusUnauthorized) - return - } + user, _, err := h.configstoreClient.GetUserByToken(ctx, tokenString) if err != nil { + if util.RemoteErrorIs(err, util.ErrNotExist) { + http.Error(w, "", http.StatusUnauthorized) + return + } http.Error(w, "", http.StatusInternalServerError) return } @@ -118,9 +119,9 @@ func (h *AuthHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { claims := token.Claims.(jwt.MapClaims) userID := claims["sub"].(string) - user, resp, err := h.configstoreClient.GetUser(ctx, userID) + user, _, err := h.configstoreClient.GetUser(ctx, userID) if err != nil { - if resp != nil && resp.StatusCode == http.StatusNotFound { + if util.RemoteErrorIs(err, util.ErrNotExist) { http.Error(w, "", http.StatusUnauthorized) return } diff --git a/internal/services/runservice/action/action.go b/internal/services/runservice/action/action.go index be15fc3..19b2771 100644 --- a/internal/services/runservice/action/action.go +++ b/internal/services/runservice/action/action.go @@ -179,13 +179,13 @@ func (h *ActionHandler) newRun(ctx context.Context, req *RunCreateRequest) (*typ setupErrors := req.SetupErrors if req.Group == "" { - return nil, util.NewErrBadRequest(errors.Errorf("run group is empty")) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("run group is empty")) } if !path.IsAbs(req.Group) { - return nil, util.NewErrBadRequest(errors.Errorf("run group %q must be an absolute path", req.Group)) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("run group %q must be an absolute path", req.Group)) } if req.RunConfigTasks == nil && len(setupErrors) == 0 { - return nil, util.NewErrBadRequest(errors.Errorf("empty run config tasks and setup errors")) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("empty run config tasks and setup errors")) } // generate a new run sequence that will be the same for the run and runconfig @@ -241,7 +241,7 @@ func (h *ActionHandler) recreateRun(ctx context.Context, req *RunCreateRequest) h.log.Infof("creating run from existing run") rc, err := store.OSTGetRunConfig(h.dm, req.RunID) if err != nil { - return nil, util.NewErrBadRequest(errors.Errorf("runconfig %q doesn't exist: %w", req.RunID, err)) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("runconfig %q doesn't exist: %w", req.RunID, err)) } run, err := store.GetRunEtcdOrOST(ctx, h.e, h.dm, req.RunID) @@ -249,7 +249,7 @@ func (h *ActionHandler) recreateRun(ctx context.Context, req *RunCreateRequest) return nil, err } if run == nil { - return nil, util.NewErrBadRequest(errors.Errorf("run %q doesn't exist: %w", req.RunID, err)) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("run %q doesn't exist: %w", req.RunID, err)) } h.log.Debugf("rc: %s", util.Dump(rc)) @@ -257,11 +257,11 @@ func (h *ActionHandler) recreateRun(ctx context.Context, req *RunCreateRequest) if req.FromStart { if canRestart, reason := run.CanRestartFromScratch(); !canRestart { - return nil, util.NewErrBadRequest(errors.Errorf("run cannot be restarted: %s", reason)) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("run cannot be restarted: %s", reason)) } } else { if canRestart, reason := run.CanRestartFromFailedTasks(); !canRestart { - return nil, util.NewErrBadRequest(errors.Errorf("run cannot be restarted: %s", reason)) + return nil, util.NewAPIError(util.ErrBadRequest, errors.Errorf("run cannot be restarted: %s", reason)) } } @@ -510,7 +510,7 @@ func (h *ActionHandler) RunTaskSetAnnotations(ctx context.Context, req *RunTaskS task, ok := r.Tasks[req.TaskID] if !ok { - return util.NewErrBadRequest(errors.Errorf("run %q doesn't have task %q", r.ID, req.TaskID)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("run %q doesn't have task %q", r.ID, req.TaskID)) } task.Annotations = req.Annotations @@ -538,15 +538,15 @@ func (h *ActionHandler) ApproveRunTask(ctx context.Context, req *RunTaskApproveR task, ok := r.Tasks[req.TaskID] if !ok { - return util.NewErrBadRequest(errors.Errorf("run %q doesn't have task %q", r.ID, req.TaskID)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("run %q doesn't have task %q", r.ID, req.TaskID)) } if !task.WaitingApproval { - return util.NewErrBadRequest(errors.Errorf("run %q, task %q is not in waiting approval state", r.ID, req.TaskID)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("run %q, task %q is not in waiting approval state", r.ID, req.TaskID)) } if task.Approved { - return util.NewErrBadRequest(errors.Errorf("run %q, task %q is already approved", r.ID, req.TaskID)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("run %q, task %q is already approved", r.ID, req.TaskID)) } task.WaitingApproval = false @@ -595,7 +595,7 @@ func (h *ActionHandler) GetExecutorTask(ctx context.Context, etID string) (*type return nil, err } if et == nil { - return nil, util.NewErrNotExist(errors.Errorf("executor task %q not found", etID)) + return nil, util.NewAPIError(util.ErrNotExist, errors.Errorf("executor task %q not found", etID)) } r, _, err := store.GetRun(ctx, h.e, et.Spec.RunID) diff --git a/internal/services/runservice/action/maintenance.go b/internal/services/runservice/action/maintenance.go index 0ef5bf2..7705d73 100644 --- a/internal/services/runservice/action/maintenance.go +++ b/internal/services/runservice/action/maintenance.go @@ -32,10 +32,10 @@ func (h *ActionHandler) MaintenanceMode(ctx context.Context, enable bool) error } if enable && len(resp.Kvs) > 0 { - return util.NewErrBadRequest(errors.Errorf("maintenance mode already enabled")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("maintenance mode already enabled")) } if !enable && len(resp.Kvs) == 0 { - return util.NewErrBadRequest(errors.Errorf("maintenance mode already disabled")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("maintenance mode already disabled")) } if enable { @@ -67,7 +67,7 @@ func (h *ActionHandler) Export(ctx context.Context, w io.Writer) error { func (h *ActionHandler) Import(ctx context.Context, r io.Reader) error { if !h.maintenanceMode { - return util.NewErrBadRequest(errors.Errorf("not in maintenance mode")) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("not in maintenance mode")) } return h.dm.Import(ctx, r) } diff --git a/internal/services/runservice/api/api.go b/internal/services/runservice/api/api.go index a5bbeff..526b523 100644 --- a/internal/services/runservice/api/api.go +++ b/internal/services/runservice/api/api.go @@ -46,92 +46,6 @@ type ErrorResponse struct { Message string `json:"message"` } -func ErrorResponseFromError(err error) *ErrorResponse { - var aerr error - // use inner errors if of these types - switch { - case util.IsBadRequest(err): - var cerr *util.ErrBadRequest - errors.As(err, &cerr) - aerr = cerr - case util.IsNotExist(err): - var cerr *util.ErrNotExist - errors.As(err, &cerr) - aerr = cerr - case util.IsForbidden(err): - var cerr *util.ErrForbidden - errors.As(err, &cerr) - aerr = cerr - case util.IsUnauthorized(err): - var cerr *util.ErrUnauthorized - errors.As(err, &cerr) - aerr = cerr - case util.IsInternal(err): - var cerr *util.ErrInternal - errors.As(err, &cerr) - aerr = cerr - } - - if aerr != nil { - return &ErrorResponse{Message: aerr.Error()} - } - - // on generic error return an generic message to not leak the real error - return &ErrorResponse{Message: "internal server error"} -} - -func httpError(w http.ResponseWriter, err error) bool { - if err == nil { - return false - } - - response := ErrorResponseFromError(err) - resj, merr := json.Marshal(response) - if merr != nil { - w.WriteHeader(http.StatusInternalServerError) - return true - } - switch { - case util.IsBadRequest(err): - w.WriteHeader(http.StatusBadRequest) - _, _ = w.Write(resj) - case util.IsNotExist(err): - w.WriteHeader(http.StatusNotFound) - _, _ = w.Write(resj) - case util.IsForbidden(err): - w.WriteHeader(http.StatusForbidden) - _, _ = w.Write(resj) - case util.IsUnauthorized(err): - w.WriteHeader(http.StatusUnauthorized) - _, _ = w.Write(resj) - case util.IsInternal(err): - w.WriteHeader(http.StatusInternalServerError) - _, _ = w.Write(resj) - default: - w.WriteHeader(http.StatusInternalServerError) - _, _ = w.Write(resj) - } - return true -} - -func httpResponse(w http.ResponseWriter, code int, res interface{}) error { - w.Header().Set("Content-Type", "application/json") - - if res != nil { - resj, err := json.Marshal(res) - if err != nil { - httpError(w, err) - return err - } - w.WriteHeader(code) - _, err = w.Write(resj) - return err - } - - w.WriteHeader(code) - return nil -} - type LogsHandler struct { log *zap.SugaredLogger e *etcd.Store @@ -194,10 +108,10 @@ func (h *LogsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { h.log.Errorf("err: %+v", err) if sendError { switch { - case util.IsNotExist(err): - httpError(w, util.NewErrNotExist(errors.Errorf("log doesn't exist: %w", err))) + case util.APIErrorIs(err, util.ErrNotExist): + util.HTTPError(w, util.NewAPIError(util.ErrNotExist, errors.Errorf("log doesn't exist: %w", err))) default: - httpError(w, err) + util.HTTPError(w, err) } } } @@ -209,15 +123,15 @@ func (h *LogsHandler) readTaskLogs(ctx context.Context, runID, taskID string, se return err, true } if r == nil { - return util.NewErrNotExist(errors.Errorf("no such run with id: %s", runID)), true + return util.NewAPIError(util.ErrNotExist, errors.Errorf("no such run with id: %s", runID)), true } task, ok := r.Tasks[taskID] if !ok { - return util.NewErrNotExist(errors.Errorf("no such task with ID %s in run %s", taskID, runID)), true + return util.NewAPIError(util.ErrNotExist, errors.Errorf("no such task with ID %s in run %s", taskID, runID)), true } if len(task.Steps) <= step { - return util.NewErrNotExist(errors.Errorf("no such step for task %s in run %s", taskID, runID)), true + return util.NewAPIError(util.ErrNotExist, errors.Errorf("no such step for task %s in run %s", taskID, runID)), true } // if the log has been already fetched use it, otherwise fetch it from the executor @@ -231,7 +145,7 @@ func (h *LogsHandler) readTaskLogs(ctx context.Context, runID, taskID string, se f, err := h.ost.ReadObject(logPath) if err != nil { if objectstorage.IsNotExist(err) { - return util.NewErrNotExist(err), true + return util.NewAPIError(util.ErrNotExist, err), true } return err, true } @@ -242,14 +156,14 @@ func (h *LogsHandler) readTaskLogs(ctx context.Context, runID, taskID string, se et, err := store.GetExecutorTask(ctx, h.e, task.ID) if err != nil { if errors.Is(err, etcd.ErrKeyNotFound) { - return util.NewErrNotExist(errors.Errorf("executor task with id %q doesn't exist", task.ID)), true + return util.NewAPIError(util.ErrNotExist, errors.Errorf("executor task with id %q doesn't exist", task.ID)), true } return err, true } executor, err := store.GetExecutor(ctx, h.e, et.Spec.ExecutorID) if err != nil { if errors.Is(err, etcd.ErrKeyNotFound) { - return util.NewErrNotExist(errors.Errorf("executor with id %q doesn't exist", et.Spec.ExecutorID)), true + return util.NewAPIError(util.ErrNotExist, errors.Errorf("executor with id %q doesn't exist", et.Spec.ExecutorID)), true } return err, true } @@ -270,7 +184,7 @@ func (h *LogsHandler) readTaskLogs(ctx context.Context, runID, taskID string, se defer req.Body.Close() if req.StatusCode != http.StatusOK { if req.StatusCode == http.StatusNotFound { - return util.NewErrNotExist(errors.New("no log on executor")), true + return util.NewAPIError(util.ErrNotExist, errors.New("no log on executor")), true } return errors.Errorf("received http status: %d", req.StatusCode), true } @@ -346,23 +260,23 @@ func (h *LogsDeleteHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { runID := q.Get("runid") if runID == "" { - httpError(w, util.NewErrBadRequest(errors.Errorf("runid is empty"))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("runid is empty"))) return } taskID := q.Get("taskid") if taskID == "" { - httpError(w, util.NewErrBadRequest(errors.Errorf("taskid is empty"))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("taskid is empty"))) return } _, setup := q["setup"] stepStr := q.Get("step") if !setup && stepStr == "" { - httpError(w, util.NewErrBadRequest(errors.Errorf("setup is false and step is empty"))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("setup is false and step is empty"))) return } if setup && stepStr != "" { - httpError(w, util.NewErrBadRequest(errors.Errorf("setup is true and step is %s", stepStr))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("setup is true and step is %s", stepStr))) return } @@ -371,7 +285,7 @@ func (h *LogsDeleteHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { var err error step, err = strconv.Atoi(stepStr) if err != nil { - httpError(w, util.NewErrBadRequest(errors.Errorf("step %s is not a valid number", stepStr))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("step %s is not a valid number", stepStr))) return } } @@ -379,10 +293,10 @@ func (h *LogsDeleteHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if err := h.deleteTaskLogs(ctx, runID, taskID, setup, step, w); err != nil { h.log.Errorf("err: %+v", err) switch { - case util.IsNotExist(err): - httpError(w, util.NewErrNotExist(errors.Errorf("log doesn't exist: %w", err))) + case util.APIErrorIs(err, util.ErrNotExist): + util.HTTPError(w, util.NewAPIError(util.ErrNotExist, errors.Errorf("log doesn't exist: %w", err))) default: - httpError(w, err) + util.HTTPError(w, err) } } } @@ -393,15 +307,15 @@ func (h *LogsDeleteHandler) deleteTaskLogs(ctx context.Context, runID, taskID st return err } if r == nil { - return util.NewErrNotExist(errors.Errorf("no such run with id: %s", runID)) + return util.NewAPIError(util.ErrNotExist, errors.Errorf("no such run with id: %s", runID)) } task, ok := r.Tasks[taskID] if !ok { - return util.NewErrNotExist(errors.Errorf("no such task with ID %s in run %s", taskID, runID)) + return util.NewAPIError(util.ErrNotExist, errors.Errorf("no such task with ID %s in run %s", taskID, runID)) } if len(task.Steps) <= step { - return util.NewErrNotExist(errors.Errorf("no such step for task %s in run %s", taskID, runID)) + return util.NewAPIError(util.ErrNotExist, errors.Errorf("no such step for task %s in run %s", taskID, runID)) } if task.Steps[step].LogPhase == types.RunTaskFetchPhaseFinished { @@ -414,13 +328,13 @@ func (h *LogsDeleteHandler) deleteTaskLogs(ctx context.Context, runID, taskID st err := h.ost.DeleteObject(logPath) if err != nil { if objectstorage.IsNotExist(err) { - return util.NewErrNotExist(err) + return util.NewAPIError(util.ErrNotExist, err) } return err } return nil } - return util.NewErrBadRequest(errors.Errorf("Log for task %s in run %s is not yet archived", taskID, runID)) + return util.NewAPIError(util.ErrBadRequest, errors.Errorf("Log for task %s in run %s is not yet archived", taskID, runID)) } type ChangeGroupsUpdateTokensHandler struct { @@ -458,7 +372,7 @@ func (h *ChangeGroupsUpdateTokensHandler) ServeHTTP(w http.ResponseWriter, r *ht return } - if err := httpResponse(w, http.StatusOK, cgts); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, cgts); err != nil { h.log.Errorf("err: %+v", err) } } @@ -506,7 +420,7 @@ func (h *RunHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } if run == nil { - httpError(w, util.NewErrNotExist(errors.Errorf("run %q doesn't exist", runID))) + util.HTTPError(w, util.NewAPIError(util.ErrNotExist, errors.Errorf("run %q doesn't exist", runID))) return } @@ -528,7 +442,7 @@ func (h *RunHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { ChangeGroupsUpdateToken: cgts, } - if err := httpResponse(w, http.StatusOK, res); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, res); err != nil { h.log.Errorf("err: %+v", err) } } @@ -613,7 +527,7 @@ func (h *RunsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { Runs: runs, ChangeGroupsUpdateToken: cgts, } - if err := httpResponse(w, http.StatusOK, res); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, res); err != nil { h.log.Errorf("err: %+v", err) } } @@ -659,7 +573,7 @@ func (h *RunCreateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { rb, err := h.ah.CreateRun(ctx, creq) if err != nil { h.log.Errorf("err: %+v", err) - httpError(w, err) + util.HTTPError(w, err) return } @@ -668,7 +582,7 @@ func (h *RunCreateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { RunConfig: rb.Rc, } - if err := httpResponse(w, http.StatusCreated, res); err != nil { + if err := util.HTTPResponse(w, http.StatusCreated, res); err != nil { h.log.Errorf("err: %+v", err) } } @@ -706,7 +620,7 @@ func (h *RunActionsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } if err := h.ah.ChangeRunPhase(ctx, creq); err != nil { h.log.Errorf("err: %+v", err) - httpError(w, err) + util.HTTPError(w, err) return } case rsapitypes.RunActionTypeStop: @@ -716,7 +630,7 @@ func (h *RunActionsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } if err := h.ah.StopRun(ctx, creq); err != nil { h.log.Errorf("err: %+v", err) - httpError(w, err) + util.HTTPError(w, err) return } default: @@ -760,7 +674,7 @@ func (h *RunTaskActionsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request } if err := h.ah.RunTaskSetAnnotations(ctx, creq); err != nil { h.log.Errorf("err: %+v", err) - httpError(w, err) + util.HTTPError(w, err) return } @@ -772,7 +686,7 @@ func (h *RunTaskActionsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request } if err := h.ah.ApproveRunTask(ctx, creq); err != nil { h.log.Errorf("err: %+v", err) - httpError(w, err) + util.HTTPError(w, err) return } diff --git a/internal/services/runservice/api/executor.go b/internal/services/runservice/api/executor.go index f58a1ba..c7e4210 100644 --- a/internal/services/runservice/api/executor.go +++ b/internal/services/runservice/api/executor.go @@ -153,17 +153,17 @@ func (h *ExecutorTaskHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) // TODO(sgotti) Check authorized call from executors etID := vars["taskid"] if etID == "" { - httpError(w, util.NewErrBadRequest(errors.Errorf("taskid is empty"))) + util.HTTPError(w, util.NewAPIError(util.ErrBadRequest, errors.Errorf("taskid is empty"))) return } et, err := h.ah.GetExecutorTask(ctx, etID) - if httpError(w, err) { + if util.HTTPError(w, err) { h.log.Errorf("err: %+v", err) return } - if err := httpResponse(w, http.StatusOK, et); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, et); err != nil { h.log.Errorf("err: %+v", err) } } @@ -235,7 +235,7 @@ func (h *ArchivesHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if err := h.readArchive(taskID, step, w); err != nil { switch { - case util.IsNotExist(err): + case util.APIErrorIs(err, util.ErrNotExist): http.Error(w, err.Error(), http.StatusNotFound) default: http.Error(w, err.Error(), http.StatusInternalServerError) @@ -249,7 +249,7 @@ func (h *ArchivesHandler) readArchive(rtID string, step int, w io.Writer) error f, err := h.ost.ReadObject(archivePath) if err != nil { if objectstorage.IsNotExist(err) { - return util.NewErrNotExist(err) + return util.NewAPIError(util.ErrNotExist, err) } return err } @@ -308,7 +308,7 @@ func (h *CacheHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if err := h.readCache(matchedKey, w); err != nil { switch { - case util.IsNotExist(err): + case util.APIErrorIs(err, util.ErrNotExist): http.Error(w, err.Error(), http.StatusNotFound) default: http.Error(w, err.Error(), http.StatusInternalServerError) @@ -358,7 +358,7 @@ func (h *CacheHandler) readCache(key string, w io.Writer) error { f, err := h.ost.ReadObject(cachePath) if err != nil { if objectstorage.IsNotExist(err) { - return util.NewErrNotExist(err) + return util.NewAPIError(util.ErrNotExist, err) } return err } diff --git a/internal/services/runservice/api/maintenance.go b/internal/services/runservice/api/maintenance.go index 711bf7c..6172635 100644 --- a/internal/services/runservice/api/maintenance.go +++ b/internal/services/runservice/api/maintenance.go @@ -19,6 +19,7 @@ import ( "agola.io/agola/internal/etcd" "agola.io/agola/internal/services/runservice/action" + "agola.io/agola/internal/util" "go.uber.org/zap" ) @@ -47,11 +48,11 @@ func (h *MaintenanceModeHandler) ServeHTTP(w http.ResponseWriter, r *http.Reques err := h.ah.MaintenanceMode(ctx, enable) if err != nil { h.log.Errorf("err: %+v", err) - httpError(w, err) + util.HTTPError(w, err) return } - if err := httpResponse(w, http.StatusOK, nil); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, nil); err != nil { h.log.Errorf("err: %+v", err) } @@ -96,11 +97,11 @@ func (h *ImportHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { err := h.ah.Import(ctx, r.Body) if err != nil { h.log.Errorf("err: %+v", err) - httpError(w, err) + util.HTTPError(w, err) return } - if err := httpResponse(w, http.StatusOK, nil); err != nil { + if err := util.HTTPResponse(w, http.StatusOK, nil); err != nil { h.log.Errorf("err: %+v", err) } diff --git a/internal/services/runservice/store/store.go b/internal/services/runservice/store/store.go index a292079..e4e0ff9 100644 --- a/internal/services/runservice/store/store.go +++ b/internal/services/runservice/store/store.go @@ -24,7 +24,6 @@ import ( "agola.io/agola/internal/datamanager" "agola.io/agola/internal/etcd" - "agola.io/agola/internal/objectstorage" "agola.io/agola/internal/services/runservice/common" "agola.io/agola/internal/util" "agola.io/agola/services/runservice/types" @@ -527,7 +526,7 @@ func GetRunEtcdOrOST(ctx context.Context, e *etcd.Store, dm *datamanager.DataMan } if r == nil { r, err = OSTGetRun(dm, runID) - if err != nil && !objectstorage.IsNotExist(err) { + if err != nil && !datamanager.IsNotExist(err) { return nil, err } } diff --git a/internal/services/scheduler/scheduler.go b/internal/services/scheduler/scheduler.go index 833325a..cd6eafd 100644 --- a/internal/services/scheduler/scheduler.go +++ b/internal/services/scheduler/scheduler.go @@ -163,7 +163,7 @@ func (s *Scheduler) approveRunTasks(ctx context.Context, runID string) error { for _, rtID := range tasksWaitingApproval { rt, ok := run.Tasks[rtID] if !ok { - return util.NewErrBadRequest(errors.Errorf("run %q doesn't have task %q", run.ID, rtID)) + return errors.Errorf("run %q doesn't have task %q", run.ID, rtID) } annotations := rt.Annotations if annotations == nil { diff --git a/internal/util/errors.go b/internal/util/errors.go index a69cf44..948cda4 100644 --- a/internal/util/errors.go +++ b/internal/util/errors.go @@ -15,9 +15,9 @@ package util import ( + "errors" + "fmt" "strings" - - errors "golang.org/x/xerrors" ) // Errors is an error that contains multiple errors @@ -59,116 +59,130 @@ func (e *Errors) Equal(e2 error) bool { return CompareStringSliceNoOrder(errs1, errs2) } -// ErrBadRequest represent an error caused by a bad command request -// it's used to differentiate an internal error from an user error -type ErrBadRequest struct { - Err error +type ErrorKind int +type ErrorCode string + +const ( + ErrBadRequest ErrorKind = iota + ErrNotExist + ErrForbidden + ErrUnauthorized + ErrInternal +) + +func (k ErrorKind) String() string { + switch k { + case ErrBadRequest: + return "badrequest" + case ErrNotExist: + return "notexist" + case ErrForbidden: + return "forbidden" + case ErrUnauthorized: + return "unauthorized" + case ErrInternal: + return "internal" + } + + return "unknown" } -func (e *ErrBadRequest) Error() string { - return e.Err.Error() +type APIError struct { + err error + Kind ErrorKind + Code ErrorCode + Message string } -func NewErrBadRequest(err error) *ErrBadRequest { - return &ErrBadRequest{Err: err} +func NewAPIError(kind ErrorKind, err error, options ...APIErrorOption) error { + derr := &APIError{err: err, Kind: kind} + + for _, opt := range options { + opt(derr) + } + + return derr } -func (e *ErrBadRequest) Unwrap() error { - return e.Err +func (e *APIError) Error() string { + return e.err.Error() } -func IsBadRequest(err error) bool { - var e *ErrBadRequest - return errors.As(err, &e) +func (e *APIError) Unwrap() error { + return e.err } -// ErrNotExist represent a not exist error -// it's used to differentiate an internal error from an user error -type ErrNotExist struct { - Err error +type APIErrorOption func(e *APIError) + +func WithCode(code ErrorCode) APIErrorOption { + return func(e *APIError) { + e.Code = code + } } -func (e *ErrNotExist) Error() string { - return e.Err.Error() +func WithMessage(message string) APIErrorOption { + return func(e *APIError) { + e.Message = message + } } -func NewErrNotExist(err error) *ErrNotExist { - return &ErrNotExist{Err: err} +func AsAPIError(err error) (*APIError, bool) { + var derr *APIError + return derr, errors.As(err, &derr) } -func (e *ErrNotExist) Unwrap() error { - return e.Err +func APIErrorIs(err error, kind ErrorKind) bool { + if derr, ok := AsAPIError(err); ok && derr.Kind == kind { + return true + } + + return false } -func IsNotExist(err error) bool { - var e *ErrNotExist - return errors.As(err, &e) +// RemoteError is an error received from a remote call. It's similar to +// APIError but with another type so it can be distinguished and won't be +// propagated to the api response. +type RemoteError struct { + Kind ErrorKind + Code string + Message string } -// ErrForbidden represent an error caused by an forbidden operation -// it's used to differentiate an internal error from an user error -type ErrForbidden struct { - Err error +func NewRemoteError(kind ErrorKind, code string, message string) error { + return &RemoteError{Kind: kind, Code: code, Message: message} } -func (e *ErrForbidden) Error() string { - return e.Err.Error() +func (e *RemoteError) Error() string { + code := e.Code + message := e.Message + errStr := fmt.Sprintf("remote error %s", e.Kind) + if code != "" { + errStr += fmt.Sprintf(" (code: %s)", code) + } + if message != "" { + errStr += fmt.Sprintf(" (message: %s)", message) + } + + return errStr } -func NewErrForbidden(err error) *ErrForbidden { - return &ErrForbidden{Err: err} +func AsRemoteError(err error) (*RemoteError, bool) { + var rerr *RemoteError + return rerr, errors.As(err, &rerr) } -func (e *ErrForbidden) Unwrap() error { - return e.Err +func RemoteErrorIs(err error, kind ErrorKind) bool { + if rerr, ok := AsRemoteError(err); ok && rerr.Kind == kind { + return true + } + + return false } -func IsForbidden(err error) bool { - var e *ErrForbidden - return errors.As(err, &e) -} +func KindFromRemoteError(err error) ErrorKind { + if rerr, ok := AsRemoteError(err); ok { + return rerr.Kind + } -// ErrUnauthorized represent an error caused by an unauthorized request -// it's used to differentiate an internal error from an user error -type ErrUnauthorized struct { - Err error -} - -func (e *ErrUnauthorized) Error() string { - return e.Err.Error() -} - -func NewErrUnauthorized(err error) *ErrUnauthorized { - return &ErrUnauthorized{Err: err} -} - -func (e *ErrUnauthorized) Unwrap() error { - return e.Err -} - -func IsUnauthorized(err error) bool { - var e *ErrUnauthorized - return errors.As(err, &e) -} - -type ErrInternal struct { - Err error -} - -// ErrInternal represent an internal error that should be returned to the user -func (e *ErrInternal) Error() string { - return e.Err.Error() -} - -func NewErrInternal(err error) *ErrInternal { - return &ErrInternal{Err: err} -} - -func (e *ErrInternal) Unwrap() error { - return e.Err -} - -func IsInternal(err error) bool { - var e *ErrInternal - return errors.As(err, &e) + return ErrInternal } diff --git a/internal/util/http.go b/internal/util/http.go new file mode 100644 index 0000000..8ec1421 --- /dev/null +++ b/internal/util/http.go @@ -0,0 +1,124 @@ +package util + +import ( + "bytes" + "encoding/json" + "io/ioutil" + "net/http" + + errors "golang.org/x/xerrors" +) + +func HTTPResponse(w http.ResponseWriter, code int, res interface{}) error { + w.Header().Set("Content-Type", "application/json") + + if res != nil { + resj, err := json.Marshal(res) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return err + } + w.WriteHeader(code) + _, err = w.Write(resj) + return err + } + + w.WriteHeader(code) + return nil +} + +type ErrorResponse struct { + Code string `json:"code"` + Message string `json:"message"` +} + +func ErrorResponseFromError(err error) *ErrorResponse { + if err == nil { + return nil + } + + var derr *APIError + if errors.As(err, &derr) { + return &ErrorResponse{Code: string(derr.Code), Message: derr.Message} + } + + // on generic error return an error response without any code + return &ErrorResponse{} +} + +func HTTPError(w http.ResponseWriter, err error) bool { + if err == nil { + return false + } + + response := ErrorResponseFromError(err) + resj, merr := json.Marshal(response) + if merr != nil { + w.WriteHeader(http.StatusInternalServerError) + return true + } + + code := http.StatusInternalServerError + + var derr *APIError + if errors.As(err, &derr) { + switch derr.Kind { + case ErrBadRequest: + code = http.StatusBadRequest + case ErrNotExist: + code = http.StatusNotFound + case ErrForbidden: + code = http.StatusForbidden + case ErrUnauthorized: + code = http.StatusUnauthorized + case ErrInternal: + code = http.StatusInternalServerError + } + } + + w.WriteHeader(code) + _, _ = w.Write(resj) + + return true +} + +func ErrFromRemote(resp *http.Response) error { + if resp == nil { + return nil + } + if resp.StatusCode/100 == 2 { + return nil + } + + response := &ErrorResponse{} + + defer resp.Body.Close() + + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + + // Re-populate error response body so it can be parsed by the caller if needed + resp.Body = ioutil.NopCloser(bytes.NewBuffer(data)) + + if err := json.Unmarshal(data, &response); err != nil { + return errors.Errorf("unknown api error (status: %d)", resp.StatusCode) + } + + kind := ErrInternal + switch resp.StatusCode { + case http.StatusBadRequest: + kind = ErrBadRequest + case http.StatusNotFound: + kind = ErrNotExist + case http.StatusForbidden: + kind = ErrForbidden + case http.StatusUnauthorized: + kind = ErrUnauthorized + case http.StatusInternalServerError: + kind = ErrInternal + } + + return NewRemoteError(kind, response.Code, response.Message) +} diff --git a/services/configstore/client/client.go b/services/configstore/client/client.go index 1f62711..c3f6d98 100644 --- a/services/configstore/client/client.go +++ b/services/configstore/client/client.go @@ -20,17 +20,14 @@ import ( "encoding/json" "fmt" "io" - "io/ioutil" "net/http" "net/url" "strconv" "strings" + "agola.io/agola/internal/util" csapitypes "agola.io/agola/services/configstore/api/types" - "agola.io/agola/services/configstore/types" cstypes "agola.io/agola/services/configstore/types" - - errors "golang.org/x/xerrors" ) var jsonContent = http.Header{"Content-Type": []string{"application/json"}} @@ -78,18 +75,8 @@ func (c *Client) getResponse(ctx context.Context, method, path string, query url return nil, err } - if resp.StatusCode/100 != 2 { - defer resp.Body.Close() - data, err := ioutil.ReadAll(resp.Body) - if err != nil { - return resp, err - } - - errMap := make(map[string]interface{}) - if err = json.Unmarshal(data, &errMap); err != nil { - return resp, fmt.Errorf("unknown api error (code: %d): %s", resp.StatusCode, string(data)) - } - return resp, errors.New(errMap["message"].(string)) + if err := util.ErrFromRemote(resp); err != nil { + return resp, err } return resp, nil @@ -332,7 +319,7 @@ func (c *Client) DeleteProjectVariable(ctx context.Context, projectRef, variable } func (c *Client) GetUser(ctx context.Context, userRef string) (*cstypes.User, *http.Response, error) { - user := new(types.User) + user := new(cstypes.User) resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/users/%s", userRef), nil, jsonContent, nil, user) return user, resp, err } @@ -383,7 +370,7 @@ func (c *Client) CreateUser(ctx context.Context, req *csapitypes.CreateUserReque return nil, nil, err } - user := new(types.User) + user := new(cstypes.User) resp, err := c.getParsedResponse(ctx, "POST", "/users", nil, jsonContent, bytes.NewReader(reqj), user) return user, resp, err } @@ -394,7 +381,7 @@ func (c *Client) UpdateUser(ctx context.Context, userRef string, req *csapitypes return nil, nil, err } - user := new(types.User) + user := new(cstypes.User) resp, err := c.getParsedResponse(ctx, "PUT", fmt.Sprintf("/users/%s", userRef), nil, jsonContent, bytes.NewReader(reqj), user) return user, resp, err } @@ -426,7 +413,7 @@ func (c *Client) CreateUserLA(ctx context.Context, userRef string, req *csapityp return nil, nil, err } - la := new(types.LinkedAccount) + la := new(cstypes.LinkedAccount) resp, err := c.getParsedResponse(ctx, "POST", fmt.Sprintf("/users/%s/linkedaccounts", userRef), nil, jsonContent, bytes.NewReader(reqj), la) return la, resp, err } @@ -441,7 +428,7 @@ func (c *Client) UpdateUserLA(ctx context.Context, userRef, laID string, req *cs return nil, nil, err } - la := new(types.LinkedAccount) + la := new(cstypes.LinkedAccount) resp, err := c.getParsedResponse(ctx, "PUT", fmt.Sprintf("/users/%s/linkedaccounts/%s", userRef, laID), nil, jsonContent, bytes.NewReader(reqj), la) return la, resp, err } @@ -468,7 +455,7 @@ func (c *Client) GetUserOrgs(ctx context.Context, userRef string) ([]*csapitypes } func (c *Client) GetRemoteSource(ctx context.Context, rsRef string) (*cstypes.RemoteSource, *http.Response, error) { - rs := new(types.RemoteSource) + rs := new(cstypes.RemoteSource) resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/remotesources/%s", rsRef), nil, jsonContent, nil, rs) return rs, resp, err } @@ -490,24 +477,24 @@ func (c *Client) GetRemoteSources(ctx context.Context, start string, limit int, return rss, resp, err } -func (c *Client) CreateRemoteSource(ctx context.Context, rs *cstypes.RemoteSource) (*types.RemoteSource, *http.Response, error) { +func (c *Client) CreateRemoteSource(ctx context.Context, rs *cstypes.RemoteSource) (*cstypes.RemoteSource, *http.Response, error) { rsj, err := json.Marshal(rs) if err != nil { return nil, nil, err } - rs = new(types.RemoteSource) + rs = new(cstypes.RemoteSource) resp, err := c.getParsedResponse(ctx, "POST", "/remotesources", nil, jsonContent, bytes.NewReader(rsj), rs) return rs, resp, err } -func (c *Client) UpdateRemoteSource(ctx context.Context, remoteSourceRef string, remoteSource *cstypes.RemoteSource) (*types.RemoteSource, *http.Response, error) { +func (c *Client) UpdateRemoteSource(ctx context.Context, remoteSourceRef string, remoteSource *cstypes.RemoteSource) (*cstypes.RemoteSource, *http.Response, error) { rsj, err := json.Marshal(remoteSource) if err != nil { return nil, nil, err } - resRemoteSource := new(types.RemoteSource) + resRemoteSource := new(cstypes.RemoteSource) resp, err := c.getParsedResponse(ctx, "PUT", fmt.Sprintf("/remotesources/%s", url.PathEscape(remoteSourceRef)), nil, jsonContent, bytes.NewReader(rsj), resRemoteSource) return resRemoteSource, resp, err } @@ -516,13 +503,13 @@ func (c *Client) DeleteRemoteSource(ctx context.Context, rsRef string) (*http.Re return c.getResponse(ctx, "DELETE", fmt.Sprintf("/remotesources/%s", rsRef), nil, jsonContent, nil) } -func (c *Client) CreateOrg(ctx context.Context, org *cstypes.Organization) (*types.Organization, *http.Response, error) { +func (c *Client) CreateOrg(ctx context.Context, org *cstypes.Organization) (*cstypes.Organization, *http.Response, error) { oj, err := json.Marshal(org) if err != nil { return nil, nil, err } - org = new(types.Organization) + org = new(cstypes.Organization) resp, err := c.getParsedResponse(ctx, "POST", "/orgs", nil, jsonContent, bytes.NewReader(oj), org) return org, resp, err } @@ -540,7 +527,7 @@ func (c *Client) AddOrgMember(ctx context.Context, orgRef, userRef string, role return nil, nil, err } - orgmember := new(types.OrganizationMember) + orgmember := new(cstypes.OrganizationMember) resp, err := c.getParsedResponse(ctx, "PUT", fmt.Sprintf("/orgs/%s/members/%s", orgRef, userRef), nil, jsonContent, bytes.NewReader(omj), orgmember) return orgmember, resp, err } @@ -567,7 +554,7 @@ func (c *Client) GetOrgs(ctx context.Context, start string, limit int, asc bool) } func (c *Client) GetOrg(ctx context.Context, orgRef string) (*cstypes.Organization, *http.Response, error) { - org := new(types.Organization) + org := new(cstypes.Organization) resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/orgs/%s", orgRef), nil, jsonContent, nil, org) return org, resp, err } diff --git a/services/gateway/client/client.go b/services/gateway/client/client.go index c9e2e88..eed6c2e 100644 --- a/services/gateway/client/client.go +++ b/services/gateway/client/client.go @@ -20,16 +20,14 @@ import ( "encoding/json" "fmt" "io" - "io/ioutil" "net/http" "net/url" "path" "strconv" "strings" + "agola.io/agola/internal/util" gwapitypes "agola.io/agola/services/gateway/api/types" - - errors "golang.org/x/xerrors" ) var jsonContent = http.Header{"Content-Type": []string{"application/json"}} @@ -80,18 +78,8 @@ func (c *Client) getResponse(ctx context.Context, method, path string, query url return nil, err } - if resp.StatusCode/100 != 2 { - defer resp.Body.Close() - data, err := ioutil.ReadAll(resp.Body) - if err != nil { - return resp, err - } - - errMap := make(map[string]interface{}) - if err = json.Unmarshal(data, &errMap); err != nil { - return resp, fmt.Errorf("unknown api error (code: %d): %s", resp.StatusCode, string(data)) - } - return resp, errors.New(errMap["message"].(string)) + if err := util.ErrFromRemote(resp); err != nil { + return resp, err } return resp, nil diff --git a/services/runservice/client/client.go b/services/runservice/client/client.go index 355c3d7..8f093f9 100644 --- a/services/runservice/client/client.go +++ b/services/runservice/client/client.go @@ -20,15 +20,14 @@ import ( "encoding/json" "fmt" "io" - "io/ioutil" "net/http" "net/url" "strconv" "strings" + "agola.io/agola/internal/util" rsapitypes "agola.io/agola/services/runservice/api/types" rstypes "agola.io/agola/services/runservice/types" - errors "golang.org/x/xerrors" ) var jsonContent = http.Header{"Content-Type": []string{"application/json"}} @@ -80,18 +79,8 @@ func (c *Client) getResponse(ctx context.Context, method, path string, query url return nil, err } - if resp.StatusCode/100 != 2 { - defer resp.Body.Close() - data, err := ioutil.ReadAll(resp.Body) - if err != nil { - return resp, err - } - - errMap := make(map[string]interface{}) - if err = json.Unmarshal(data, &errMap); err != nil { - return resp, fmt.Errorf("unknown api error (code: %d): %s", resp.StatusCode, string(data)) - } - return resp, errors.New(errMap["message"].(string)) + if err := util.ErrFromRemote(resp); err != nil { + return resp, err } return resp, nil diff --git a/tests/setup_test.go b/tests/setup_test.go index 2d8232b..7723a38 100644 --- a/tests/setup_test.go +++ b/tests/setup_test.go @@ -1288,7 +1288,7 @@ func TestDirectRunLogs(t *testing.T) { { name: "test get log with unexisting step", step: 99, - err: errors.Errorf("log doesn't exist"), + err: util.NewRemoteError(util.ErrNotExist, "", ""), }, { name: "test delete log step 1", @@ -1304,7 +1304,7 @@ func TestDirectRunLogs(t *testing.T) { name: "test delete log with unexisting step", step: 99, delete: true, - err: errors.Errorf("log doesn't exist"), + err: util.NewRemoteError(util.ErrNotExist, "", ""), }, }