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, "", ""), }, }