Switch to fmt.Errorf

Replace all instances of errors.Wrap() with fmt.Errorf.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
This commit is contained in:
Gabriel Adrian Samfira 2025-08-16 19:31:58 +00:00
parent 10dcbec954
commit 118319c7c1
88 changed files with 1007 additions and 4467 deletions

View file

@ -17,6 +17,8 @@ package controllers
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"errors"
"fmt"
"io" "io"
"log/slog" "log/slog"
"net/http" "net/http"
@ -25,7 +27,6 @@ import (
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
"github.com/pkg/errors"
gErrors "github.com/cloudbase/garm-provider-common/errors" gErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm-provider-common/util" "github.com/cloudbase/garm-provider-common/util"
@ -43,7 +44,7 @@ import (
func NewAPIController(r *runner.Runner, authenticator *auth.Authenticator, hub *wsWriter.Hub, apiCfg config.APIServer) (*APIController, error) { func NewAPIController(r *runner.Runner, authenticator *auth.Authenticator, hub *wsWriter.Hub, apiCfg config.APIServer) (*APIController, error) {
controllerInfo, err := r.GetControllerInfo(auth.GetAdminContext(context.Background())) controllerInfo, err := r.GetControllerInfo(auth.GetAdminContext(context.Background()))
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to get controller info") return nil, fmt.Errorf("failed to get controller info: %w", err)
} }
var checkOrigin func(r *http.Request) bool var checkOrigin func(r *http.Request) bool
if len(apiCfg.CORSOrigins) > 0 { if len(apiCfg.CORSOrigins) > 0 {
@ -91,24 +92,22 @@ type APIController struct {
func handleError(ctx context.Context, w http.ResponseWriter, err error) { func handleError(ctx context.Context, w http.ResponseWriter, err error) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
origErr := errors.Cause(err)
apiErr := params.APIErrorResponse{ apiErr := params.APIErrorResponse{
Details: origErr.Error(), Details: err.Error(),
} }
switch {
switch origErr.(type) { case errors.Is(err, gErrors.ErrNotFound):
case *gErrors.NotFoundError:
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
apiErr.Error = "Not Found" apiErr.Error = "Not Found"
case *gErrors.UnauthorizedError: case errors.Is(err, gErrors.ErrUnauthorized):
w.WriteHeader(http.StatusUnauthorized) w.WriteHeader(http.StatusUnauthorized)
apiErr.Error = "Not Authorized" apiErr.Error = "Not Authorized"
// Don't include details on 401 errors. // Don't include details on 401 errors.
apiErr.Details = "" apiErr.Details = ""
case *gErrors.BadRequestError: case errors.Is(err, gErrors.ErrBadRequest):
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
apiErr.Error = "Bad Request" apiErr.Error = "Bad Request"
case *gErrors.DuplicateUserError, *gErrors.ConflictError: case errors.Is(err, gErrors.ErrDuplicateEntity), errors.Is(err, &gErrors.ConflictError{}):
w.WriteHeader(http.StatusConflict) w.WriteHeader(http.StatusConflict)
apiErr.Error = "Conflict" apiErr.Error = "Conflict"
default: default:

View file

@ -16,11 +16,12 @@ package auth
import ( import (
"context" "context"
"errors"
"fmt"
"time" "time"
jwt "github.com/golang-jwt/jwt/v5" jwt "github.com/golang-jwt/jwt/v5"
"github.com/nbutton23/zxcvbn-go" "github.com/nbutton23/zxcvbn-go"
"github.com/pkg/errors"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
runnerErrors "github.com/cloudbase/garm-provider-common/errors" runnerErrors "github.com/cloudbase/garm-provider-common/errors"
@ -49,7 +50,7 @@ func (a *Authenticator) IsInitialized() bool {
func (a *Authenticator) GetJWTToken(ctx context.Context) (string, error) { func (a *Authenticator) GetJWTToken(ctx context.Context) (string, error) {
tokenID, err := util.GetRandomString(16) tokenID, err := util.GetRandomString(16)
if err != nil { if err != nil {
return "", errors.Wrap(err, "generating random string") return "", fmt.Errorf("error generating random string: %w", err)
} }
expireToken := time.Now().Add(a.cfg.TimeToLive.Duration()) expireToken := time.Now().Add(a.cfg.TimeToLive.Duration())
expires := &jwt.NumericDate{ expires := &jwt.NumericDate{
@ -72,7 +73,7 @@ func (a *Authenticator) GetJWTToken(ctx context.Context) (string, error) {
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, err := token.SignedString([]byte(a.cfg.Secret)) tokenString, err := token.SignedString([]byte(a.cfg.Secret))
if err != nil { if err != nil {
return "", errors.Wrap(err, "fetching token string") return "", fmt.Errorf("error fetching token string: %w", err)
} }
return tokenString, nil return tokenString, nil
@ -87,7 +88,7 @@ func (a *Authenticator) GetJWTMetricsToken(ctx context.Context) (string, error)
tokenID, err := util.GetRandomString(16) tokenID, err := util.GetRandomString(16)
if err != nil { if err != nil {
return "", errors.Wrap(err, "generating random string") return "", fmt.Errorf("error generating random string: %w", err)
} }
// nolint:golangci-lint,godox // nolint:golangci-lint,godox
// TODO: currently this is the same TTL as the normal Token // TODO: currently this is the same TTL as the normal Token
@ -111,7 +112,7 @@ func (a *Authenticator) GetJWTMetricsToken(ctx context.Context) (string, error)
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, err := token.SignedString([]byte(a.cfg.Secret)) tokenString, err := token.SignedString([]byte(a.cfg.Secret))
if err != nil { if err != nil {
return "", errors.Wrap(err, "fetching token string") return "", fmt.Errorf("error fetching token string: %w", err)
} }
return tokenString, nil return tokenString, nil
@ -121,7 +122,7 @@ func (a *Authenticator) InitController(ctx context.Context, param params.NewUser
_, err := a.store.ControllerInfo() _, err := a.store.ControllerInfo()
if err != nil { if err != nil {
if !errors.Is(err, runnerErrors.ErrNotFound) { if !errors.Is(err, runnerErrors.ErrNotFound) {
return params.User{}, errors.Wrap(err, "initializing controller") return params.User{}, fmt.Errorf("error initializing controller: %w", err)
} }
} }
if a.store.HasAdminUser(ctx) { if a.store.HasAdminUser(ctx) {
@ -151,7 +152,7 @@ func (a *Authenticator) InitController(ctx context.Context, param params.NewUser
hashed, err := util.PaswsordToBcrypt(param.Password) hashed, err := util.PaswsordToBcrypt(param.Password)
if err != nil { if err != nil {
return params.User{}, errors.Wrap(err, "creating user") return params.User{}, fmt.Errorf("error creating user: %w", err)
} }
param.Password = hashed param.Password = hashed
@ -169,7 +170,7 @@ func (a *Authenticator) AuthenticateUser(ctx context.Context, info params.Passwo
if errors.Is(err, runnerErrors.ErrNotFound) { if errors.Is(err, runnerErrors.ErrNotFound) {
return ctx, runnerErrors.ErrUnauthorized return ctx, runnerErrors.ErrUnauthorized
} }
return ctx, errors.Wrap(err, "authenticating") return ctx, fmt.Errorf("error authenticating: %w", err)
} }
if !user.Enabled { if !user.Enabled {

View file

@ -24,7 +24,6 @@ import (
"time" "time"
jwt "github.com/golang-jwt/jwt/v5" jwt "github.com/golang-jwt/jwt/v5"
"github.com/pkg/errors"
runnerErrors "github.com/cloudbase/garm-provider-common/errors" runnerErrors "github.com/cloudbase/garm-provider-common/errors"
commonParams "github.com/cloudbase/garm-provider-common/params" commonParams "github.com/cloudbase/garm-provider-common/params"
@ -91,7 +90,7 @@ func (i *instanceToken) NewInstanceJWTToken(instance params.Instance, entity par
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, err := token.SignedString([]byte(i.jwtSecret)) tokenString, err := token.SignedString([]byte(i.jwtSecret))
if err != nil { if err != nil {
return "", errors.Wrap(err, "signing token") return "", fmt.Errorf("error signing token: %w", err)
} }
return tokenString, nil return tokenString, nil

View file

@ -21,7 +21,6 @@ import (
openapiRuntimeClient "github.com/go-openapi/runtime/client" openapiRuntimeClient "github.com/go-openapi/runtime/client"
"github.com/jedib0t/go-pretty/v6/table" "github.com/jedib0t/go-pretty/v6/table"
"github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
apiClientController "github.com/cloudbase/garm/client/controller" apiClientController "github.com/cloudbase/garm/client/controller"
@ -80,7 +79,7 @@ garm-cli init --name=dev --url=https://runner.example.com --username=admin --pas
response, err := apiCli.FirstRun.FirstRun(newUserReq, authToken) response, err := apiCli.FirstRun.FirstRun(newUserReq, authToken)
if err != nil { if err != nil {
return errors.Wrap(err, "initializing manager") return fmt.Errorf("error initializing manager: %w", err)
} }
newLoginParamsReq := apiClientLogin.NewLoginParams() newLoginParamsReq := apiClientLogin.NewLoginParams()
@ -91,7 +90,7 @@ garm-cli init --name=dev --url=https://runner.example.com --username=admin --pas
token, err := apiCli.Login.Login(newLoginParamsReq, authToken) token, err := apiCli.Login.Login(newLoginParamsReq, authToken)
if err != nil { if err != nil {
return errors.Wrap(err, "authenticating") return fmt.Errorf("error authenticating: %w", err)
} }
cfg.Managers = append(cfg.Managers, config.Manager{ cfg.Managers = append(cfg.Managers, config.Manager{
@ -104,7 +103,7 @@ garm-cli init --name=dev --url=https://runner.example.com --username=admin --pas
cfg.ActiveManager = loginProfileName cfg.ActiveManager = loginProfileName
if err := cfg.SaveConfig(); err != nil { if err := cfg.SaveConfig(); err != nil {
return errors.Wrap(err, "saving config") return fmt.Errorf("error saving config: %w", err)
} }
updateUrlsReq := apiClientController.NewUpdateControllerParams() updateUrlsReq := apiClientController.NewUpdateControllerParams()

View file

@ -21,7 +21,6 @@ import (
"strings" "strings"
"github.com/jedib0t/go-pretty/v6/table" "github.com/jedib0t/go-pretty/v6/table"
"github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
commonParams "github.com/cloudbase/garm-provider-common/params" commonParams "github.com/cloudbase/garm-provider-common/params"
@ -471,7 +470,7 @@ func init() {
func extraSpecsFromFile(specsFile string) (json.RawMessage, error) { func extraSpecsFromFile(specsFile string) (json.RawMessage, error) {
data, err := os.ReadFile(specsFile) data, err := os.ReadFile(specsFile)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "opening specs file") return nil, fmt.Errorf("error opening specs file: %w", err)
} }
return asRawMessage(data) return asRawMessage(data)
} }
@ -481,14 +480,14 @@ func asRawMessage(data []byte) (json.RawMessage, error) {
// have a valid json. // have a valid json.
var unmarshaled interface{} var unmarshaled interface{}
if err := json.Unmarshal(data, &unmarshaled); err != nil { if err := json.Unmarshal(data, &unmarshaled); err != nil {
return nil, errors.Wrap(err, "decoding extra specs") return nil, fmt.Errorf("error decoding extra specs: %w", err)
} }
var asRawJSON json.RawMessage var asRawJSON json.RawMessage
var err error var err error
asRawJSON, err = json.Marshal(unmarshaled) asRawJSON, err = json.Marshal(unmarshaled)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "marshaling json") return nil, fmt.Errorf("error marshaling json: %w", err)
} }
return asRawJSON, nil return asRawJSON, nil
} }

View file

@ -15,13 +15,13 @@
package config package config
import ( import (
"errors"
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
"sync" "sync"
"github.com/BurntSushi/toml" "github.com/BurntSushi/toml"
"github.com/pkg/errors"
runnerErrors "github.com/cloudbase/garm-provider-common/errors" runnerErrors "github.com/cloudbase/garm-provider-common/errors"
) )
@ -34,11 +34,11 @@ const (
func getConfigFilePath() (string, error) { func getConfigFilePath() (string, error) {
configDir, err := getHomeDir() configDir, err := getHomeDir()
if err != nil { if err != nil {
return "", errors.Wrap(err, "fetching home folder") return "", fmt.Errorf("error fetching home folder: %w", err)
} }
if err := ensureHomeDir(configDir); err != nil { if err := ensureHomeDir(configDir); err != nil {
return "", errors.Wrap(err, "ensuring config dir") return "", fmt.Errorf("error ensuring config dir: %w", err)
} }
cfgFile := filepath.Join(configDir, DefaultConfigFileName) cfgFile := filepath.Join(configDir, DefaultConfigFileName)
@ -48,7 +48,7 @@ func getConfigFilePath() (string, error) {
func LoadConfig() (*Config, error) { func LoadConfig() (*Config, error) {
cfgFile, err := getConfigFilePath() cfgFile, err := getConfigFilePath()
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching config") return nil, fmt.Errorf("error fetching config: %w", err)
} }
if _, err := os.Stat(cfgFile); err != nil { if _, err := os.Stat(cfgFile); err != nil {
@ -56,12 +56,12 @@ func LoadConfig() (*Config, error) {
// return empty config // return empty config
return &Config{}, nil return &Config{}, nil
} }
return nil, errors.Wrap(err, "accessing config file") return nil, fmt.Errorf("error accessing config file: %w", err)
} }
var config Config var config Config
if _, err := toml.DecodeFile(cfgFile, &config); err != nil { if _, err := toml.DecodeFile(cfgFile, &config); err != nil {
return nil, errors.Wrap(err, "decoding toml") return nil, fmt.Errorf("error decoding toml: %w", err)
} }
return &config, nil return &config, nil
@ -157,17 +157,17 @@ func (c *Config) SaveConfig() error {
cfgFile, err := getConfigFilePath() cfgFile, err := getConfigFilePath()
if err != nil { if err != nil {
if !errors.Is(err, os.ErrNotExist) { if !errors.Is(err, os.ErrNotExist) {
return errors.Wrap(err, "getting config") return fmt.Errorf("error getting config: %w", err)
} }
} }
cfgHandle, err := os.Create(cfgFile) cfgHandle, err := os.Create(cfgFile)
if err != nil { if err != nil {
return errors.Wrap(err, "getting file handle") return fmt.Errorf("error getting file handle: %w", err)
} }
encoder := toml.NewEncoder(cfgHandle) encoder := toml.NewEncoder(cfgHandle)
if err := encoder.Encode(c); err != nil { if err := encoder.Encode(c); err != nil {
return errors.Wrap(err, "saving config") return fmt.Errorf("error saving config: %w", err)
} }
return nil return nil

View file

@ -15,19 +15,19 @@
package config package config
import ( import (
"errors"
"fmt"
"os" "os"
"github.com/pkg/errors"
) )
func ensureHomeDir(folder string) error { func ensureHomeDir(folder string) error {
if _, err := os.Stat(folder); err != nil { if _, err := os.Stat(folder); err != nil {
if !errors.Is(err, os.ErrNotExist) { if !errors.Is(err, os.ErrNotExist) {
return errors.Wrap(err, "checking home dir") return fmt.Errorf("error checking home dir: %w", err)
} }
if err := os.MkdirAll(folder, 0o710); err != nil { if err := os.MkdirAll(folder, 0o710); err != nil {
return errors.Wrapf(err, "creating %s", folder) return fmt.Errorf("error creating %s: %w", folder, err)
} }
} }

View file

@ -17,16 +17,15 @@
package config package config
import ( import (
"fmt"
"os" "os"
"path/filepath" "path/filepath"
"github.com/pkg/errors"
) )
func getHomeDir() (string, error) { func getHomeDir() (string, error) {
home, err := os.UserHomeDir() home, err := os.UserHomeDir()
if err != nil { if err != nil {
return "", errors.Wrap(err, "fetching home dir") return "", fmt.Errorf("error fetching home dir: %w", err)
} }
return filepath.Join(home, ".local", "share", DefaultAppFolder), nil return filepath.Join(home, ".local", "share", DefaultAppFolder), nil

View file

@ -31,7 +31,6 @@ import (
"github.com/gorilla/handlers" "github.com/gorilla/handlers"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/pkg/errors"
lumberjack "gopkg.in/natefinch/lumberjack.v2" lumberjack "gopkg.in/natefinch/lumberjack.v2"
"github.com/cloudbase/garm-provider-common/util" "github.com/cloudbase/garm-provider-common/util"
@ -73,7 +72,7 @@ func maybeInitController(db common.Store) (params.ControllerInfo, error) {
info, err := db.InitController() info, err := db.InitController()
if err != nil { if err != nil {
return params.ControllerInfo{}, errors.Wrap(err, "initializing controller") return params.ControllerInfo{}, fmt.Errorf("error initializing controller: %w", err)
} }
return info, nil return info, nil
@ -152,7 +151,7 @@ func setupLogging(ctx context.Context, logCfg config.Logging, hub *websocket.Hub
func maybeUpdateURLsFromConfig(cfg config.Config, store common.Store) error { func maybeUpdateURLsFromConfig(cfg config.Config, store common.Store) error {
info, err := store.ControllerInfo() info, err := store.ControllerInfo()
if err != nil { if err != nil {
return errors.Wrap(err, "fetching controller info") return fmt.Errorf("error fetching controller info: %w", err)
} }
var updateParams params.UpdateControllerParams var updateParams params.UpdateControllerParams
@ -176,7 +175,7 @@ func maybeUpdateURLsFromConfig(cfg config.Config, store common.Store) error {
_, err = store.UpdateController(updateParams) _, err = store.UpdateController(updateParams)
if err != nil { if err != nil {
return errors.Wrap(err, "updating controller info") return fmt.Errorf("error updating controller info: %w", err)
} }
return nil return nil
} }

View file

@ -31,7 +31,6 @@ import (
"github.com/BurntSushi/toml" "github.com/BurntSushi/toml"
"github.com/bradleyfalzon/ghinstallation/v2" "github.com/bradleyfalzon/ghinstallation/v2"
zxcvbn "github.com/nbutton23/zxcvbn-go" zxcvbn "github.com/nbutton23/zxcvbn-go"
"github.com/pkg/errors"
"golang.org/x/oauth2" "golang.org/x/oauth2"
"github.com/cloudbase/garm/params" "github.com/cloudbase/garm/params"
@ -84,10 +83,10 @@ const (
func NewConfig(cfgFile string) (*Config, error) { func NewConfig(cfgFile string) (*Config, error) {
var config Config var config Config
if _, err := toml.DecodeFile(cfgFile, &config); err != nil { if _, err := toml.DecodeFile(cfgFile, &config); err != nil {
return nil, errors.Wrap(err, "decoding toml") return nil, fmt.Errorf("error decoding toml: %w", err)
} }
if err := config.Validate(); err != nil { if err := config.Validate(); err != nil {
return nil, errors.Wrap(err, "validating config") return nil, fmt.Errorf("error validating config: %w", err)
} }
return &config, nil return &config, nil
} }
@ -496,19 +495,19 @@ type Database struct {
// GormParams returns the database type and connection URI // GormParams returns the database type and connection URI
func (d *Database) GormParams() (dbType DBBackendType, uri string, err error) { func (d *Database) GormParams() (dbType DBBackendType, uri string, err error) {
if err := d.Validate(); err != nil { if err := d.Validate(); err != nil {
return "", "", errors.Wrap(err, "validating database config") return "", "", fmt.Errorf("error validating database config: %w", err)
} }
dbType = d.DbBackend dbType = d.DbBackend
switch dbType { switch dbType {
case MySQLBackend: case MySQLBackend:
uri, err = d.MySQL.ConnectionString() uri, err = d.MySQL.ConnectionString()
if err != nil { if err != nil {
return "", "", errors.Wrap(err, "fetching mysql connection string") return "", "", fmt.Errorf("error fetching mysql connection string: %w", err)
} }
case SQLiteBackend: case SQLiteBackend:
uri, err = d.SQLite.ConnectionString() uri, err = d.SQLite.ConnectionString()
if err != nil { if err != nil {
return "", "", errors.Wrap(err, "fetching sqlite3 connection string") return "", "", fmt.Errorf("error fetching sqlite3 connection string: %w", err)
} }
default: default:
return "", "", fmt.Errorf("invalid database backend: %s", dbType) return "", "", fmt.Errorf("invalid database backend: %s", dbType)

View file

@ -517,7 +517,6 @@ func TestJWTAuthConfig(t *testing.T) {
func TestTimeToLiveDuration(t *testing.T) { func TestTimeToLiveDuration(t *testing.T) {
cfg := JWTAuth{ cfg := JWTAuth{
Secret: EncryptionPassphrase,
TimeToLive: "48h", TimeToLive: "48h",
} }

View file

@ -15,10 +15,11 @@
package sql package sql
import ( import (
"errors"
"fmt"
"net/url" "net/url"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/pkg/errors"
"gorm.io/gorm" "gorm.io/gorm"
runnerErrors "github.com/cloudbase/garm-provider-common/errors" runnerErrors "github.com/cloudbase/garm-provider-common/errors"
@ -30,7 +31,7 @@ import (
func dbControllerToCommonController(dbInfo ControllerInfo) (params.ControllerInfo, error) { func dbControllerToCommonController(dbInfo ControllerInfo) (params.ControllerInfo, error) {
url, err := url.JoinPath(dbInfo.WebhookBaseURL, dbInfo.ControllerID.String()) url, err := url.JoinPath(dbInfo.WebhookBaseURL, dbInfo.ControllerID.String())
if err != nil { if err != nil {
return params.ControllerInfo{}, errors.Wrap(err, "joining webhook URL") return params.ControllerInfo{}, fmt.Errorf("error joining webhook URL: %w", err)
} }
return params.ControllerInfo{ return params.ControllerInfo{
@ -49,14 +50,14 @@ func (s *sqlDatabase) ControllerInfo() (params.ControllerInfo, error) {
q := s.conn.Model(&ControllerInfo{}).First(&info) q := s.conn.Model(&ControllerInfo{}).First(&info)
if q.Error != nil { if q.Error != nil {
if errors.Is(q.Error, gorm.ErrRecordNotFound) { if errors.Is(q.Error, gorm.ErrRecordNotFound) {
return params.ControllerInfo{}, errors.Wrap(runnerErrors.ErrNotFound, "fetching controller info") return params.ControllerInfo{}, fmt.Errorf("error fetching controller info: %w", runnerErrors.ErrNotFound)
} }
return params.ControllerInfo{}, errors.Wrap(q.Error, "fetching controller info") return params.ControllerInfo{}, fmt.Errorf("error fetching controller info: %w", q.Error)
} }
paramInfo, err := dbControllerToCommonController(info) paramInfo, err := dbControllerToCommonController(info)
if err != nil { if err != nil {
return params.ControllerInfo{}, errors.Wrap(err, "converting controller info") return params.ControllerInfo{}, fmt.Errorf("error converting controller info: %w", err)
} }
return paramInfo, nil return paramInfo, nil
@ -69,7 +70,7 @@ func (s *sqlDatabase) InitController() (params.ControllerInfo, error) {
newID, err := uuid.NewRandom() newID, err := uuid.NewRandom()
if err != nil { if err != nil {
return params.ControllerInfo{}, errors.Wrap(err, "generating UUID") return params.ControllerInfo{}, fmt.Errorf("error generating UUID: %w", err)
} }
newInfo := ControllerInfo{ newInfo := ControllerInfo{
@ -79,7 +80,7 @@ func (s *sqlDatabase) InitController() (params.ControllerInfo, error) {
q := s.conn.Save(&newInfo) q := s.conn.Save(&newInfo)
if q.Error != nil { if q.Error != nil {
return params.ControllerInfo{}, errors.Wrap(q.Error, "saving controller info") return params.ControllerInfo{}, fmt.Errorf("error saving controller info: %w", q.Error)
} }
return params.ControllerInfo{ return params.ControllerInfo{
@ -98,13 +99,13 @@ func (s *sqlDatabase) UpdateController(info params.UpdateControllerParams) (para
q := tx.Model(&ControllerInfo{}).First(&dbInfo) q := tx.Model(&ControllerInfo{}).First(&dbInfo)
if q.Error != nil { if q.Error != nil {
if errors.Is(q.Error, gorm.ErrRecordNotFound) { if errors.Is(q.Error, gorm.ErrRecordNotFound) {
return errors.Wrap(runnerErrors.ErrNotFound, "fetching controller info") return fmt.Errorf("error fetching controller info: %w", runnerErrors.ErrNotFound)
} }
return errors.Wrap(q.Error, "fetching controller info") return fmt.Errorf("error fetching controller info: %w", q.Error)
} }
if err := info.Validate(); err != nil { if err := info.Validate(); err != nil {
return errors.Wrap(err, "validating controller info") return fmt.Errorf("error validating controller info: %w", err)
} }
if info.MetadataURL != nil { if info.MetadataURL != nil {
@ -125,17 +126,17 @@ func (s *sqlDatabase) UpdateController(info params.UpdateControllerParams) (para
q = tx.Save(&dbInfo) q = tx.Save(&dbInfo)
if q.Error != nil { if q.Error != nil {
return errors.Wrap(q.Error, "saving controller info") return fmt.Errorf("error saving controller info: %w", q.Error)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return params.ControllerInfo{}, errors.Wrap(err, "updating controller info") return params.ControllerInfo{}, fmt.Errorf("error updating controller info: %w", err)
} }
paramInfo, err = dbControllerToCommonController(dbInfo) paramInfo, err = dbControllerToCommonController(dbInfo)
if err != nil { if err != nil {
return params.ControllerInfo{}, errors.Wrap(err, "converting controller info") return params.ControllerInfo{}, fmt.Errorf("error converting controller info: %w", err)
} }
return paramInfo, nil return paramInfo, nil
} }

View file

@ -16,10 +16,11 @@ package sql
import ( import (
"context" "context"
"errors"
"fmt"
"log/slog" "log/slog"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/pkg/errors"
"gorm.io/gorm" "gorm.io/gorm"
runnerErrors "github.com/cloudbase/garm-provider-common/errors" runnerErrors "github.com/cloudbase/garm-provider-common/errors"
@ -33,12 +34,12 @@ func (s *sqlDatabase) CreateEnterprise(ctx context.Context, name string, credent
return params.Enterprise{}, errors.New("creating enterprise: missing secret") return params.Enterprise{}, errors.New("creating enterprise: missing secret")
} }
if credentials.ForgeType != params.GithubEndpointType { if credentials.ForgeType != params.GithubEndpointType {
return params.Enterprise{}, errors.Wrap(runnerErrors.ErrBadRequest, "enterprises are not supported on this forge type") return params.Enterprise{}, fmt.Errorf("enterprises are not supported on this forge type: %w", runnerErrors.ErrBadRequest)
} }
secret, err := util.Seal([]byte(webhookSecret), []byte(s.cfg.Passphrase)) secret, err := util.Seal([]byte(webhookSecret), []byte(s.cfg.Passphrase))
if err != nil { if err != nil {
return params.Enterprise{}, errors.Wrap(err, "encoding secret") return params.Enterprise{}, fmt.Errorf("error encoding secret: %w", err)
} }
defer func() { defer func() {
@ -57,22 +58,22 @@ func (s *sqlDatabase) CreateEnterprise(ctx context.Context, name string, credent
q := tx.Create(&newEnterprise) q := tx.Create(&newEnterprise)
if q.Error != nil { if q.Error != nil {
return errors.Wrap(q.Error, "creating enterprise") return fmt.Errorf("error creating enterprise: %w", q.Error)
} }
newEnterprise, err = s.getEnterpriseByID(ctx, tx, newEnterprise.ID.String(), "Pools", "Credentials", "Endpoint", "Credentials.Endpoint") newEnterprise, err = s.getEnterpriseByID(ctx, tx, newEnterprise.ID.String(), "Pools", "Credentials", "Endpoint", "Credentials.Endpoint")
if err != nil { if err != nil {
return errors.Wrap(err, "creating enterprise") return fmt.Errorf("error creating enterprise: %w", err)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return params.Enterprise{}, errors.Wrap(err, "creating enterprise") return params.Enterprise{}, fmt.Errorf("error creating enterprise: %w", err)
} }
ret, err := s.GetEnterpriseByID(ctx, newEnterprise.ID.String()) ret, err := s.GetEnterpriseByID(ctx, newEnterprise.ID.String())
if err != nil { if err != nil {
return params.Enterprise{}, errors.Wrap(err, "creating enterprise") return params.Enterprise{}, fmt.Errorf("error creating enterprise: %w", err)
} }
return ret, nil return ret, nil
@ -81,12 +82,12 @@ func (s *sqlDatabase) CreateEnterprise(ctx context.Context, name string, credent
func (s *sqlDatabase) GetEnterprise(ctx context.Context, name, endpointName string) (params.Enterprise, error) { func (s *sqlDatabase) GetEnterprise(ctx context.Context, name, endpointName string) (params.Enterprise, error) {
enterprise, err := s.getEnterprise(ctx, name, endpointName) enterprise, err := s.getEnterprise(ctx, name, endpointName)
if err != nil { if err != nil {
return params.Enterprise{}, errors.Wrap(err, "fetching enterprise") return params.Enterprise{}, fmt.Errorf("error fetching enterprise: %w", err)
} }
param, err := s.sqlToCommonEnterprise(enterprise, true) param, err := s.sqlToCommonEnterprise(enterprise, true)
if err != nil { if err != nil {
return params.Enterprise{}, errors.Wrap(err, "fetching enterprise") return params.Enterprise{}, fmt.Errorf("error fetching enterprise: %w", err)
} }
return param, nil return param, nil
} }
@ -101,12 +102,12 @@ func (s *sqlDatabase) GetEnterpriseByID(ctx context.Context, enterpriseID string
} }
enterprise, err := s.getEnterpriseByID(ctx, s.conn, enterpriseID, preloadList...) enterprise, err := s.getEnterpriseByID(ctx, s.conn, enterpriseID, preloadList...)
if err != nil { if err != nil {
return params.Enterprise{}, errors.Wrap(err, "fetching enterprise") return params.Enterprise{}, fmt.Errorf("error fetching enterprise: %w", err)
} }
param, err := s.sqlToCommonEnterprise(enterprise, true) param, err := s.sqlToCommonEnterprise(enterprise, true)
if err != nil { if err != nil {
return params.Enterprise{}, errors.Wrap(err, "fetching enterprise") return params.Enterprise{}, fmt.Errorf("error fetching enterprise: %w", err)
} }
return param, nil return param, nil
} }
@ -125,7 +126,7 @@ func (s *sqlDatabase) ListEnterprises(_ context.Context, filter params.Enterpris
} }
q = q.Find(&enterprises) q = q.Find(&enterprises)
if q.Error != nil { if q.Error != nil {
return []params.Enterprise{}, errors.Wrap(q.Error, "fetching enterprises") return []params.Enterprise{}, fmt.Errorf("error fetching enterprises: %w", q.Error)
} }
ret := make([]params.Enterprise, len(enterprises)) ret := make([]params.Enterprise, len(enterprises))
@ -133,7 +134,7 @@ func (s *sqlDatabase) ListEnterprises(_ context.Context, filter params.Enterpris
var err error var err error
ret[idx], err = s.sqlToCommonEnterprise(val, true) ret[idx], err = s.sqlToCommonEnterprise(val, true)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching enterprises") return nil, fmt.Errorf("error fetching enterprises: %w", err)
} }
} }
@ -143,7 +144,7 @@ func (s *sqlDatabase) ListEnterprises(_ context.Context, filter params.Enterpris
func (s *sqlDatabase) DeleteEnterprise(ctx context.Context, enterpriseID string) error { func (s *sqlDatabase) DeleteEnterprise(ctx context.Context, enterpriseID string) error {
enterprise, err := s.getEnterpriseByID(ctx, s.conn, enterpriseID, "Endpoint", "Credentials", "Credentials.Endpoint") enterprise, err := s.getEnterpriseByID(ctx, s.conn, enterpriseID, "Endpoint", "Credentials", "Credentials.Endpoint")
if err != nil { if err != nil {
return errors.Wrap(err, "fetching enterprise") return fmt.Errorf("error fetching enterprise: %w", err)
} }
defer func(ent Enterprise) { defer func(ent Enterprise) {
@ -159,7 +160,7 @@ func (s *sqlDatabase) DeleteEnterprise(ctx context.Context, enterpriseID string)
q := s.conn.Unscoped().Delete(&enterprise) q := s.conn.Unscoped().Delete(&enterprise)
if q.Error != nil && !errors.Is(q.Error, gorm.ErrRecordNotFound) { if q.Error != nil && !errors.Is(q.Error, gorm.ErrRecordNotFound) {
return errors.Wrap(q.Error, "deleting enterprise") return fmt.Errorf("error deleting enterprise: %w", q.Error)
} }
return nil return nil
@ -177,31 +178,31 @@ func (s *sqlDatabase) UpdateEnterprise(ctx context.Context, enterpriseID string,
var err error var err error
enterprise, err = s.getEnterpriseByID(ctx, tx, enterpriseID) enterprise, err = s.getEnterpriseByID(ctx, tx, enterpriseID)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching enterprise") return fmt.Errorf("error fetching enterprise: %w", err)
} }
if enterprise.EndpointName == nil { if enterprise.EndpointName == nil {
return errors.Wrap(runnerErrors.ErrUnprocessable, "enterprise has no endpoint") return fmt.Errorf("error enterprise has no endpoint: %w", runnerErrors.ErrUnprocessable)
} }
if param.CredentialsName != "" { if param.CredentialsName != "" {
creds, err = s.getGithubCredentialsByName(ctx, tx, param.CredentialsName, false) creds, err = s.getGithubCredentialsByName(ctx, tx, param.CredentialsName, false)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching credentials") return fmt.Errorf("error fetching credentials: %w", err)
} }
if creds.EndpointName == nil { if creds.EndpointName == nil {
return errors.Wrap(runnerErrors.ErrUnprocessable, "credentials have no endpoint") return fmt.Errorf("error credentials have no endpoint: %w", runnerErrors.ErrUnprocessable)
} }
if *creds.EndpointName != *enterprise.EndpointName { if *creds.EndpointName != *enterprise.EndpointName {
return errors.Wrap(runnerErrors.ErrBadRequest, "endpoint mismatch") return fmt.Errorf("error endpoint mismatch: %w", runnerErrors.ErrBadRequest)
} }
enterprise.CredentialsID = &creds.ID enterprise.CredentialsID = &creds.ID
} }
if param.WebhookSecret != "" { if param.WebhookSecret != "" {
secret, err := util.Seal([]byte(param.WebhookSecret), []byte(s.cfg.Passphrase)) secret, err := util.Seal([]byte(param.WebhookSecret), []byte(s.cfg.Passphrase))
if err != nil { if err != nil {
return errors.Wrap(err, "encoding secret") return fmt.Errorf("error encoding secret: %w", err)
} }
enterprise.WebhookSecret = secret enterprise.WebhookSecret = secret
} }
@ -212,22 +213,22 @@ func (s *sqlDatabase) UpdateEnterprise(ctx context.Context, enterpriseID string,
q := tx.Save(&enterprise) q := tx.Save(&enterprise)
if q.Error != nil { if q.Error != nil {
return errors.Wrap(q.Error, "saving enterprise") return fmt.Errorf("error saving enterprise: %w", q.Error)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return params.Enterprise{}, errors.Wrap(err, "updating enterprise") return params.Enterprise{}, fmt.Errorf("error updating enterprise: %w", err)
} }
enterprise, err = s.getEnterpriseByID(ctx, s.conn, enterpriseID, "Endpoint", "Credentials", "Credentials.Endpoint") enterprise, err = s.getEnterpriseByID(ctx, s.conn, enterpriseID, "Endpoint", "Credentials", "Credentials.Endpoint")
if err != nil { if err != nil {
return params.Enterprise{}, errors.Wrap(err, "updating enterprise") return params.Enterprise{}, fmt.Errorf("error updating enterprise: %w", err)
} }
newParams, err = s.sqlToCommonEnterprise(enterprise, true) newParams, err = s.sqlToCommonEnterprise(enterprise, true)
if err != nil { if err != nil {
return params.Enterprise{}, errors.Wrap(err, "updating enterprise") return params.Enterprise{}, fmt.Errorf("error updating enterprise: %w", err)
} }
return newParams, nil return newParams, nil
} }
@ -244,7 +245,7 @@ func (s *sqlDatabase) getEnterprise(_ context.Context, name, endpointName string
if errors.Is(q.Error, gorm.ErrRecordNotFound) { if errors.Is(q.Error, gorm.ErrRecordNotFound) {
return Enterprise{}, runnerErrors.ErrNotFound return Enterprise{}, runnerErrors.ErrNotFound
} }
return Enterprise{}, errors.Wrap(q.Error, "fetching enterprise from database") return Enterprise{}, fmt.Errorf("error fetching enterprise from database: %w", q.Error)
} }
return enterprise, nil return enterprise, nil
} }
@ -252,7 +253,7 @@ func (s *sqlDatabase) getEnterprise(_ context.Context, name, endpointName string
func (s *sqlDatabase) getEnterpriseByID(_ context.Context, tx *gorm.DB, id string, preload ...string) (Enterprise, error) { func (s *sqlDatabase) getEnterpriseByID(_ context.Context, tx *gorm.DB, id string, preload ...string) (Enterprise, error) {
u, err := uuid.Parse(id) u, err := uuid.Parse(id)
if err != nil { if err != nil {
return Enterprise{}, errors.Wrap(runnerErrors.ErrBadRequest, "parsing id") return Enterprise{}, fmt.Errorf("error parsing id: %w", runnerErrors.ErrBadRequest)
} }
var enterprise Enterprise var enterprise Enterprise
@ -268,7 +269,7 @@ func (s *sqlDatabase) getEnterpriseByID(_ context.Context, tx *gorm.DB, id strin
if errors.Is(q.Error, gorm.ErrRecordNotFound) { if errors.Is(q.Error, gorm.ErrRecordNotFound) {
return Enterprise{}, runnerErrors.ErrNotFound return Enterprise{}, runnerErrors.ErrNotFound
} }
return Enterprise{}, errors.Wrap(q.Error, "fetching enterprise from database") return Enterprise{}, fmt.Errorf("error fetching enterprise from database: %w", q.Error)
} }
return enterprise, nil return enterprise, nil
} }

View file

@ -218,7 +218,7 @@ func (s *EnterpriseTestSuite) TestCreateEnterpriseInvalidDBPassphrase() {
params.PoolBalancerTypeRoundRobin) params.PoolBalancerTypeRoundRobin)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("encoding secret: invalid passphrase length (expected length 32 characters)", err.Error()) s.Require().Equal("error encoding secret: invalid passphrase length (expected length 32 characters)", err.Error())
} }
func (s *EnterpriseTestSuite) TestCreateEnterpriseDBCreateErr() { func (s *EnterpriseTestSuite) TestCreateEnterpriseDBCreateErr() {
@ -236,7 +236,7 @@ func (s *EnterpriseTestSuite) TestCreateEnterpriseDBCreateErr() {
params.PoolBalancerTypeRoundRobin) params.PoolBalancerTypeRoundRobin)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("creating enterprise: creating enterprise: creating enterprise mock error", err.Error()) s.Require().Equal("error creating enterprise: error creating enterprise: creating enterprise mock error", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -259,7 +259,7 @@ func (s *EnterpriseTestSuite) TestGetEnterpriseNotFound() {
_, err := s.Store.GetEnterprise(s.adminCtx, "dummy-name", "github.com") _, err := s.Store.GetEnterprise(s.adminCtx, "dummy-name", "github.com")
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching enterprise: not found", err.Error()) s.Require().Equal("error fetching enterprise: not found", err.Error())
} }
func (s *EnterpriseTestSuite) TestGetEnterpriseDBDecryptingErr() { func (s *EnterpriseTestSuite) TestGetEnterpriseDBDecryptingErr() {
@ -271,7 +271,7 @@ func (s *EnterpriseTestSuite) TestGetEnterpriseDBDecryptingErr() {
_, err := s.StoreSQLMocked.GetEnterprise(s.adminCtx, s.Fixtures.Enterprises[0].Name, s.Fixtures.Enterprises[0].Endpoint.Name) _, err := s.StoreSQLMocked.GetEnterprise(s.adminCtx, s.Fixtures.Enterprises[0].Name, s.Fixtures.Enterprises[0].Endpoint.Name)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching enterprise: missing secret", err.Error()) s.Require().Equal("error fetching enterprise: missing secret", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -341,7 +341,7 @@ func (s *EnterpriseTestSuite) TestListEnterprisesDBFetchErr() {
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching enterprises: fetching user from database mock error", err.Error()) s.Require().Equal("error fetching enterprises: fetching user from database mock error", err.Error())
} }
func (s *EnterpriseTestSuite) TestDeleteEnterprise() { func (s *EnterpriseTestSuite) TestDeleteEnterprise() {
@ -350,14 +350,14 @@ func (s *EnterpriseTestSuite) TestDeleteEnterprise() {
s.Require().Nil(err) s.Require().Nil(err)
_, err = s.Store.GetEnterpriseByID(s.adminCtx, s.Fixtures.Enterprises[0].ID) _, err = s.Store.GetEnterpriseByID(s.adminCtx, s.Fixtures.Enterprises[0].ID)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching enterprise: not found", err.Error()) s.Require().Equal("error fetching enterprise: not found", err.Error())
} }
func (s *EnterpriseTestSuite) TestDeleteEnterpriseInvalidEnterpriseID() { func (s *EnterpriseTestSuite) TestDeleteEnterpriseInvalidEnterpriseID() {
err := s.Store.DeleteEnterprise(s.adminCtx, "dummy-enterprise-id") err := s.Store.DeleteEnterprise(s.adminCtx, "dummy-enterprise-id")
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching enterprise: parsing id: invalid request", err.Error()) s.Require().Equal("error fetching enterprise: error parsing id: invalid request", err.Error())
} }
func (s *EnterpriseTestSuite) TestDeleteEnterpriseDBDeleteErr() { func (s *EnterpriseTestSuite) TestDeleteEnterpriseDBDeleteErr() {
@ -375,7 +375,7 @@ func (s *EnterpriseTestSuite) TestDeleteEnterpriseDBDeleteErr() {
err := s.StoreSQLMocked.DeleteEnterprise(s.adminCtx, s.Fixtures.Enterprises[0].ID) err := s.StoreSQLMocked.DeleteEnterprise(s.adminCtx, s.Fixtures.Enterprises[0].ID)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("deleting enterprise: mocked delete enterprise error", err.Error()) s.Require().Equal("error deleting enterprise: mocked delete enterprise error", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -391,7 +391,7 @@ func (s *EnterpriseTestSuite) TestUpdateEnterpriseInvalidEnterpriseID() {
_, err := s.Store.UpdateEnterprise(s.adminCtx, "dummy-enterprise-id", s.Fixtures.UpdateRepoParams) _, err := s.Store.UpdateEnterprise(s.adminCtx, "dummy-enterprise-id", s.Fixtures.UpdateRepoParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("updating enterprise: fetching enterprise: parsing id: invalid request", err.Error()) s.Require().Equal("error updating enterprise: error fetching enterprise: error parsing id: invalid request", err.Error())
} }
func (s *EnterpriseTestSuite) TestUpdateEnterpriseDBEncryptErr() { func (s *EnterpriseTestSuite) TestUpdateEnterpriseDBEncryptErr() {
@ -416,7 +416,7 @@ func (s *EnterpriseTestSuite) TestUpdateEnterpriseDBEncryptErr() {
_, err := s.StoreSQLMocked.UpdateEnterprise(s.adminCtx, s.Fixtures.Enterprises[0].ID, s.Fixtures.UpdateRepoParams) _, err := s.StoreSQLMocked.UpdateEnterprise(s.adminCtx, s.Fixtures.Enterprises[0].ID, s.Fixtures.UpdateRepoParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("updating enterprise: encoding secret: invalid passphrase length (expected length 32 characters)", err.Error()) s.Require().Equal("error updating enterprise: error encoding secret: invalid passphrase length (expected length 32 characters)", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -444,7 +444,7 @@ func (s *EnterpriseTestSuite) TestUpdateEnterpriseDBSaveErr() {
_, err := s.StoreSQLMocked.UpdateEnterprise(s.adminCtx, s.Fixtures.Enterprises[0].ID, s.Fixtures.UpdateRepoParams) _, err := s.StoreSQLMocked.UpdateEnterprise(s.adminCtx, s.Fixtures.Enterprises[0].ID, s.Fixtures.UpdateRepoParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("updating enterprise: saving enterprise: saving enterprise mock error", err.Error()) s.Require().Equal("error updating enterprise: error saving enterprise: saving enterprise mock error", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -472,7 +472,7 @@ func (s *EnterpriseTestSuite) TestUpdateEnterpriseDBDecryptingErr() {
_, err := s.StoreSQLMocked.UpdateEnterprise(s.adminCtx, s.Fixtures.Enterprises[0].ID, s.Fixtures.UpdateRepoParams) _, err := s.StoreSQLMocked.UpdateEnterprise(s.adminCtx, s.Fixtures.Enterprises[0].ID, s.Fixtures.UpdateRepoParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("updating enterprise: encoding secret: invalid passphrase length (expected length 32 characters)", err.Error()) s.Require().Equal("error updating enterprise: error encoding secret: invalid passphrase length (expected length 32 characters)", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -487,7 +487,7 @@ func (s *EnterpriseTestSuite) TestGetEnterpriseByIDInvalidEnterpriseID() {
_, err := s.Store.GetEnterpriseByID(s.adminCtx, "dummy-enterprise-id") _, err := s.Store.GetEnterpriseByID(s.adminCtx, "dummy-enterprise-id")
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching enterprise: parsing id: invalid request", err.Error()) s.Require().Equal("error fetching enterprise: error parsing id: invalid request", err.Error())
} }
func (s *EnterpriseTestSuite) TestGetEnterpriseByIDDBDecryptingErr() { func (s *EnterpriseTestSuite) TestGetEnterpriseByIDDBDecryptingErr() {
@ -508,7 +508,7 @@ func (s *EnterpriseTestSuite) TestGetEnterpriseByIDDBDecryptingErr() {
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching enterprise: missing secret", err.Error()) s.Require().Equal("error fetching enterprise: missing secret", err.Error())
} }
func (s *EnterpriseTestSuite) TestCreateEnterprisePool() { func (s *EnterpriseTestSuite) TestCreateEnterprisePool() {
@ -547,7 +547,7 @@ func (s *EnterpriseTestSuite) TestCreateEnterprisePoolInvalidEnterpriseID() {
_, err := s.Store.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams) _, err := s.Store.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("parsing id: invalid request", err.Error()) s.Require().Equal("error parsing id: invalid request", err.Error())
} }
func (s *EnterpriseTestSuite) TestCreateEnterprisePoolDBFetchTagErr() { func (s *EnterpriseTestSuite) TestCreateEnterprisePoolDBFetchTagErr() {
@ -565,7 +565,7 @@ func (s *EnterpriseTestSuite) TestCreateEnterprisePoolDBFetchTagErr() {
_, err = s.StoreSQLMocked.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams) _, err = s.StoreSQLMocked.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("creating tag: fetching tag from database: mocked fetching tag error", err.Error()) s.Require().Equal("error creating tag: error fetching tag from database: mocked fetching tag error", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -592,7 +592,7 @@ func (s *EnterpriseTestSuite) TestCreateEnterprisePoolDBAddingPoolErr() {
_, err = s.StoreSQLMocked.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams) _, err = s.StoreSQLMocked.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("creating pool: mocked adding pool error", err.Error()) s.Require().Equal("error creating pool: mocked adding pool error", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -623,7 +623,7 @@ func (s *EnterpriseTestSuite) TestCreateEnterprisePoolDBSaveTagErr() {
_, err = s.StoreSQLMocked.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams) _, err = s.StoreSQLMocked.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("associating tags: mocked saving tag error", err.Error()) s.Require().Equal("error associating tags: mocked saving tag error", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -663,7 +663,7 @@ func (s *EnterpriseTestSuite) TestCreateEnterprisePoolDBFetchPoolErr() {
_, err = s.StoreSQLMocked.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams) _, err = s.StoreSQLMocked.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching pool: not found", err.Error()) s.Require().Equal("error fetching pool: not found", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -694,7 +694,7 @@ func (s *EnterpriseTestSuite) TestListEnterprisePoolsInvalidEnterpriseID() {
_, err := s.Store.ListEntityPools(s.adminCtx, entity) _, err := s.Store.ListEntityPools(s.adminCtx, entity)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching pools: parsing id: invalid request", err.Error()) s.Require().Equal("error fetching pools: error parsing id: invalid request", err.Error())
} }
func (s *EnterpriseTestSuite) TestGetEnterprisePool() { func (s *EnterpriseTestSuite) TestGetEnterprisePool() {
@ -719,7 +719,7 @@ func (s *EnterpriseTestSuite) TestGetEnterprisePoolInvalidEnterpriseID() {
_, err := s.Store.GetEntityPool(s.adminCtx, entity, "dummy-pool-id") _, err := s.Store.GetEntityPool(s.adminCtx, entity, "dummy-pool-id")
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching pool: parsing id: invalid request", err.Error()) s.Require().Equal("fetching pool: error parsing id: invalid request", err.Error())
} }
func (s *EnterpriseTestSuite) TestDeleteEnterprisePool() { func (s *EnterpriseTestSuite) TestDeleteEnterprisePool() {
@ -734,7 +734,7 @@ func (s *EnterpriseTestSuite) TestDeleteEnterprisePool() {
s.Require().Nil(err) s.Require().Nil(err)
_, err = s.Store.GetEntityPool(s.adminCtx, entity, pool.ID) _, err = s.Store.GetEntityPool(s.adminCtx, entity, pool.ID)
s.Require().Equal("fetching pool: finding pool: not found", err.Error()) s.Require().Equal("fetching pool: error finding pool: not found", err.Error())
} }
func (s *EnterpriseTestSuite) TestDeleteEnterprisePoolInvalidEnterpriseID() { func (s *EnterpriseTestSuite) TestDeleteEnterprisePoolInvalidEnterpriseID() {
@ -745,7 +745,7 @@ func (s *EnterpriseTestSuite) TestDeleteEnterprisePoolInvalidEnterpriseID() {
err := s.Store.DeleteEntityPool(s.adminCtx, entity, "dummy-pool-id") err := s.Store.DeleteEntityPool(s.adminCtx, entity, "dummy-pool-id")
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("parsing id: invalid request", err.Error()) s.Require().Equal("error parsing id: invalid request", err.Error())
} }
func (s *EnterpriseTestSuite) TestDeleteEnterprisePoolDBDeleteErr() { func (s *EnterpriseTestSuite) TestDeleteEnterprisePoolDBDeleteErr() {
@ -765,7 +765,7 @@ func (s *EnterpriseTestSuite) TestDeleteEnterprisePoolDBDeleteErr() {
err = s.StoreSQLMocked.DeleteEntityPool(s.adminCtx, entity, pool.ID) err = s.StoreSQLMocked.DeleteEntityPool(s.adminCtx, entity, pool.ID)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("removing pool: mocked deleting pool error", err.Error()) s.Require().Equal("error removing pool: mocked deleting pool error", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -800,7 +800,7 @@ func (s *EnterpriseTestSuite) TestListEnterpriseInstancesInvalidEnterpriseID() {
_, err := s.Store.ListEntityInstances(s.adminCtx, entity) _, err := s.Store.ListEntityInstances(s.adminCtx, entity)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching entity: parsing id: invalid request", err.Error()) s.Require().Equal("error fetching entity: error parsing id: invalid request", err.Error())
} }
func (s *EnterpriseTestSuite) TestUpdateEnterprisePool() { func (s *EnterpriseTestSuite) TestUpdateEnterprisePool() {
@ -828,7 +828,7 @@ func (s *EnterpriseTestSuite) TestUpdateEnterprisePoolInvalidEnterpriseID() {
_, err := s.Store.UpdateEntityPool(s.adminCtx, entity, "dummy-pool-id", s.Fixtures.UpdatePoolParams) _, err := s.Store.UpdateEntityPool(s.adminCtx, entity, "dummy-pool-id", s.Fixtures.UpdatePoolParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching pool: parsing id: invalid request", err.Error()) s.Require().Equal("error fetching pool: error parsing id: invalid request", err.Error())
} }
func (s *EnterpriseTestSuite) TestAddRepoEntityEvent() { func (s *EnterpriseTestSuite) TestAddRepoEntityEvent() {

View file

@ -16,9 +16,10 @@ package sql
import ( import (
"context" "context"
"errors"
"fmt"
"log/slog" "log/slog"
"github.com/pkg/errors"
"gorm.io/gorm" "gorm.io/gorm"
runnerErrors "github.com/cloudbase/garm-provider-common/errors" runnerErrors "github.com/cloudbase/garm-provider-common/errors"
@ -36,7 +37,7 @@ func (s *sqlDatabase) CreateGiteaEndpoint(_ context.Context, param params.Create
var endpoint GithubEndpoint var endpoint GithubEndpoint
err = s.conn.Transaction(func(tx *gorm.DB) error { err = s.conn.Transaction(func(tx *gorm.DB) error {
if err := tx.Where("name = ?", param.Name).First(&endpoint).Error; err == nil { if err := tx.Where("name = ?", param.Name).First(&endpoint).Error; err == nil {
return errors.Wrap(runnerErrors.ErrDuplicateEntity, "gitea endpoint already exists") return fmt.Errorf("gitea endpoint already exists: %w", runnerErrors.ErrDuplicateEntity)
} }
endpoint = GithubEndpoint{ endpoint = GithubEndpoint{
Name: param.Name, Name: param.Name,
@ -48,16 +49,16 @@ func (s *sqlDatabase) CreateGiteaEndpoint(_ context.Context, param params.Create
} }
if err := tx.Create(&endpoint).Error; err != nil { if err := tx.Create(&endpoint).Error; err != nil {
return errors.Wrap(err, "creating gitea endpoint") return fmt.Errorf("error creating gitea endpoint: %w", err)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return params.ForgeEndpoint{}, errors.Wrap(err, "creating gitea endpoint") return params.ForgeEndpoint{}, fmt.Errorf("error creating gitea endpoint: %w", err)
} }
ghEndpoint, err = s.sqlToCommonGithubEndpoint(endpoint) ghEndpoint, err = s.sqlToCommonGithubEndpoint(endpoint)
if err != nil { if err != nil {
return params.ForgeEndpoint{}, errors.Wrap(err, "converting gitea endpoint") return params.ForgeEndpoint{}, fmt.Errorf("error converting gitea endpoint: %w", err)
} }
return ghEndpoint, nil return ghEndpoint, nil
} }
@ -66,14 +67,14 @@ func (s *sqlDatabase) ListGiteaEndpoints(_ context.Context) ([]params.ForgeEndpo
var endpoints []GithubEndpoint var endpoints []GithubEndpoint
err := s.conn.Where("endpoint_type = ?", params.GiteaEndpointType).Find(&endpoints).Error err := s.conn.Where("endpoint_type = ?", params.GiteaEndpointType).Find(&endpoints).Error
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching gitea endpoints") return nil, fmt.Errorf("error fetching gitea endpoints: %w", err)
} }
var ret []params.ForgeEndpoint var ret []params.ForgeEndpoint
for _, ep := range endpoints { for _, ep := range endpoints {
commonEp, err := s.sqlToCommonGithubEndpoint(ep) commonEp, err := s.sqlToCommonGithubEndpoint(ep)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "converting gitea endpoint") return nil, fmt.Errorf("error converting gitea endpoint: %w", err)
} }
ret = append(ret, commonEp) ret = append(ret, commonEp)
} }
@ -90,19 +91,19 @@ func (s *sqlDatabase) UpdateGiteaEndpoint(_ context.Context, name string, param
err = s.conn.Transaction(func(tx *gorm.DB) error { err = s.conn.Transaction(func(tx *gorm.DB) error {
if err := tx.Where("name = ? and endpoint_type = ?", name, params.GiteaEndpointType).First(&endpoint).Error; err != nil { if err := tx.Where("name = ? and endpoint_type = ?", name, params.GiteaEndpointType).First(&endpoint).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return errors.Wrap(runnerErrors.ErrNotFound, "gitea endpoint not found") return runnerErrors.NewNotFoundError("gitea endpoint %q not found", name)
} }
return errors.Wrap(err, "fetching gitea endpoint") return fmt.Errorf("error fetching gitea endpoint: %w", err)
} }
var credsCount int64 var credsCount int64
if err := tx.Model(&GiteaCredentials{}).Where("endpoint_name = ?", endpoint.Name).Count(&credsCount).Error; err != nil { if err := tx.Model(&GiteaCredentials{}).Where("endpoint_name = ?", endpoint.Name).Count(&credsCount).Error; err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) { if !errors.Is(err, gorm.ErrRecordNotFound) {
return errors.Wrap(err, "fetching gitea credentials") return fmt.Errorf("error fetching gitea credentials: %w", err)
} }
} }
if credsCount > 0 && (param.APIBaseURL != nil || param.BaseURL != nil) { if credsCount > 0 && (param.APIBaseURL != nil || param.BaseURL != nil) {
return errors.Wrap(runnerErrors.ErrBadRequest, "cannot update endpoint URLs with existing credentials") return runnerErrors.NewBadRequestError("cannot update endpoint URLs with existing credentials")
} }
if param.APIBaseURL != nil { if param.APIBaseURL != nil {
@ -122,17 +123,17 @@ func (s *sqlDatabase) UpdateGiteaEndpoint(_ context.Context, name string, param
} }
if err := tx.Save(&endpoint).Error; err != nil { if err := tx.Save(&endpoint).Error; err != nil {
return errors.Wrap(err, "updating gitea endpoint") return fmt.Errorf("error updating gitea endpoint: %w", err)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return params.ForgeEndpoint{}, errors.Wrap(err, "updating gitea endpoint") return params.ForgeEndpoint{}, fmt.Errorf("error updating gitea endpoint: %w", err)
} }
ghEndpoint, err = s.sqlToCommonGithubEndpoint(endpoint) ghEndpoint, err = s.sqlToCommonGithubEndpoint(endpoint)
if err != nil { if err != nil {
return params.ForgeEndpoint{}, errors.Wrap(err, "converting gitea endpoint") return params.ForgeEndpoint{}, fmt.Errorf("error converting gitea endpoint: %w", err)
} }
return ghEndpoint, nil return ghEndpoint, nil
} }
@ -142,9 +143,9 @@ func (s *sqlDatabase) GetGiteaEndpoint(_ context.Context, name string) (params.F
err := s.conn.Where("name = ? and endpoint_type = ?", name, params.GiteaEndpointType).First(&endpoint).Error err := s.conn.Where("name = ? and endpoint_type = ?", name, params.GiteaEndpointType).First(&endpoint).Error
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return params.ForgeEndpoint{}, errors.Wrap(runnerErrors.ErrNotFound, "gitea endpoint not found") return params.ForgeEndpoint{}, runnerErrors.NewNotFoundError("gitea endpoint %q not found", name)
} }
return params.ForgeEndpoint{}, errors.Wrap(err, "fetching gitea endpoint") return params.ForgeEndpoint{}, fmt.Errorf("error fetching gitea endpoint: %w", err)
} }
return s.sqlToCommonGithubEndpoint(endpoint) return s.sqlToCommonGithubEndpoint(endpoint)
@ -162,41 +163,41 @@ func (s *sqlDatabase) DeleteGiteaEndpoint(_ context.Context, name string) (err e
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return nil return nil
} }
return errors.Wrap(err, "fetching gitea endpoint") return fmt.Errorf("error fetching gitea endpoint: %w", err)
} }
var credsCount int64 var credsCount int64
if err := tx.Model(&GiteaCredentials{}).Where("endpoint_name = ?", endpoint.Name).Count(&credsCount).Error; err != nil { if err := tx.Model(&GiteaCredentials{}).Where("endpoint_name = ?", endpoint.Name).Count(&credsCount).Error; err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) { if !errors.Is(err, gorm.ErrRecordNotFound) {
return errors.Wrap(err, "fetching gitea credentials") return fmt.Errorf("error fetching gitea credentials: %w", err)
} }
} }
var repoCnt int64 var repoCnt int64
if err := tx.Model(&Repository{}).Where("endpoint_name = ?", endpoint.Name).Count(&repoCnt).Error; err != nil { if err := tx.Model(&Repository{}).Where("endpoint_name = ?", endpoint.Name).Count(&repoCnt).Error; err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) { if !errors.Is(err, gorm.ErrRecordNotFound) {
return errors.Wrap(err, "fetching gitea repositories") return fmt.Errorf("error fetching gitea repositories: %w", err)
} }
} }
var orgCnt int64 var orgCnt int64
if err := tx.Model(&Organization{}).Where("endpoint_name = ?", endpoint.Name).Count(&orgCnt).Error; err != nil { if err := tx.Model(&Organization{}).Where("endpoint_name = ?", endpoint.Name).Count(&orgCnt).Error; err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) { if !errors.Is(err, gorm.ErrRecordNotFound) {
return errors.Wrap(err, "fetching gitea organizations") return fmt.Errorf("error fetching gitea organizations: %w", err)
} }
} }
if credsCount > 0 || repoCnt > 0 || orgCnt > 0 { if credsCount > 0 || repoCnt > 0 || orgCnt > 0 {
return errors.Wrap(runnerErrors.ErrBadRequest, "cannot delete endpoint with associated entities") return runnerErrors.NewBadRequestError("cannot delete endpoint with associated entities")
} }
if err := tx.Unscoped().Delete(&endpoint).Error; err != nil { if err := tx.Unscoped().Delete(&endpoint).Error; err != nil {
return errors.Wrap(err, "deleting gitea endpoint") return fmt.Errorf("error deleting gitea endpoint: %w", err)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return errors.Wrap(err, "deleting gitea endpoint") return fmt.Errorf("error deleting gitea endpoint: %w", err)
} }
return nil return nil
} }
@ -204,10 +205,10 @@ func (s *sqlDatabase) DeleteGiteaEndpoint(_ context.Context, name string) (err e
func (s *sqlDatabase) CreateGiteaCredentials(ctx context.Context, param params.CreateGiteaCredentialsParams) (gtCreds params.ForgeCredentials, err error) { func (s *sqlDatabase) CreateGiteaCredentials(ctx context.Context, param params.CreateGiteaCredentialsParams) (gtCreds params.ForgeCredentials, err error) {
userID, err := getUIDFromContext(ctx) userID, err := getUIDFromContext(ctx)
if err != nil { if err != nil {
return params.ForgeCredentials{}, errors.Wrap(err, "creating gitea credentials") return params.ForgeCredentials{}, fmt.Errorf("error creating gitea credentials: %w", err)
} }
if param.Endpoint == "" { if param.Endpoint == "" {
return params.ForgeCredentials{}, errors.Wrap(runnerErrors.ErrBadRequest, "endpoint name is required") return params.ForgeCredentials{}, runnerErrors.NewBadRequestError("endpoint name is required")
} }
defer func() { defer func() {
@ -220,13 +221,13 @@ func (s *sqlDatabase) CreateGiteaCredentials(ctx context.Context, param params.C
var endpoint GithubEndpoint var endpoint GithubEndpoint
if err := tx.Where("name = ? and endpoint_type = ?", param.Endpoint, params.GiteaEndpointType).First(&endpoint).Error; err != nil { if err := tx.Where("name = ? and endpoint_type = ?", param.Endpoint, params.GiteaEndpointType).First(&endpoint).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return errors.Wrap(runnerErrors.ErrNotFound, "gitea endpoint not found") return runnerErrors.NewNotFoundError("gitea endpoint %q not found", param.Endpoint)
} }
return errors.Wrap(err, "fetching gitea endpoint") return fmt.Errorf("error fetching gitea endpoint: %w", err)
} }
if err := tx.Where("name = ? and user_id = ?", param.Name, userID).First(&creds).Error; err == nil { if err := tx.Where("name = ? and user_id = ?", param.Name, userID).First(&creds).Error; err == nil {
return errors.Wrap(runnerErrors.ErrDuplicateEntity, "gitea credentials already exists") return fmt.Errorf("gitea credentials already exists: %w", runnerErrors.ErrDuplicateEntity)
} }
var data []byte var data []byte
@ -235,10 +236,10 @@ func (s *sqlDatabase) CreateGiteaCredentials(ctx context.Context, param params.C
case params.ForgeAuthTypePAT: case params.ForgeAuthTypePAT:
data, err = s.marshalAndSeal(param.PAT) data, err = s.marshalAndSeal(param.PAT)
default: default:
return errors.Wrap(runnerErrors.ErrBadRequest, "invalid auth type") return runnerErrors.NewBadRequestError("invalid auth type %q", param.AuthType)
} }
if err != nil { if err != nil {
return errors.Wrap(err, "marshaling and sealing credentials") return fmt.Errorf("error marshaling and sealing credentials: %w", err)
} }
creds = GiteaCredentials{ creds = GiteaCredentials{
@ -251,7 +252,7 @@ func (s *sqlDatabase) CreateGiteaCredentials(ctx context.Context, param params.C
} }
if err := tx.Create(&creds).Error; err != nil { if err := tx.Create(&creds).Error; err != nil {
return errors.Wrap(err, "creating gitea credentials") return fmt.Errorf("error creating gitea credentials: %w", err)
} }
// Skip making an extra query. // Skip making an extra query.
creds.Endpoint = endpoint creds.Endpoint = endpoint
@ -259,11 +260,11 @@ func (s *sqlDatabase) CreateGiteaCredentials(ctx context.Context, param params.C
return nil return nil
}) })
if err != nil { if err != nil {
return params.ForgeCredentials{}, errors.Wrap(err, "creating gitea credentials") return params.ForgeCredentials{}, fmt.Errorf("error creating gitea credentials: %w", err)
} }
gtCreds, err = s.sqlGiteaToCommonForgeCredentials(creds) gtCreds, err = s.sqlGiteaToCommonForgeCredentials(creds)
if err != nil { if err != nil {
return params.ForgeCredentials{}, errors.Wrap(err, "converting gitea credentials") return params.ForgeCredentials{}, fmt.Errorf("error converting gitea credentials: %w", err)
} }
return gtCreds, nil return gtCreds, nil
} }
@ -284,16 +285,16 @@ func (s *sqlDatabase) getGiteaCredentialsByName(ctx context.Context, tx *gorm.DB
userID, err := getUIDFromContext(ctx) userID, err := getUIDFromContext(ctx)
if err != nil { if err != nil {
return GiteaCredentials{}, errors.Wrap(err, "fetching gitea credentials") return GiteaCredentials{}, fmt.Errorf("error fetching gitea credentials: %w", err)
} }
q = q.Where("user_id = ?", userID) q = q.Where("user_id = ?", userID)
err = q.Where("name = ?", name).First(&creds).Error err = q.Where("name = ?", name).First(&creds).Error
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return GiteaCredentials{}, errors.Wrap(runnerErrors.ErrNotFound, "gitea credentials not found") return GiteaCredentials{}, runnerErrors.NewNotFoundError("gitea credentials %q not found", name)
} }
return GiteaCredentials{}, errors.Wrap(err, "fetching gitea credentials") return GiteaCredentials{}, fmt.Errorf("error fetching gitea credentials: %w", err)
} }
return creds, nil return creds, nil
@ -302,7 +303,7 @@ func (s *sqlDatabase) getGiteaCredentialsByName(ctx context.Context, tx *gorm.DB
func (s *sqlDatabase) GetGiteaCredentialsByName(ctx context.Context, name string, detailed bool) (params.ForgeCredentials, error) { func (s *sqlDatabase) GetGiteaCredentialsByName(ctx context.Context, name string, detailed bool) (params.ForgeCredentials, error) {
creds, err := s.getGiteaCredentialsByName(ctx, s.conn, name, detailed) creds, err := s.getGiteaCredentialsByName(ctx, s.conn, name, detailed)
if err != nil { if err != nil {
return params.ForgeCredentials{}, errors.Wrap(err, "fetching gitea credentials") return params.ForgeCredentials{}, fmt.Errorf("error fetching gitea credentials: %w", err)
} }
return s.sqlGiteaToCommonForgeCredentials(creds) return s.sqlGiteaToCommonForgeCredentials(creds)
@ -325,7 +326,7 @@ func (s *sqlDatabase) GetGiteaCredentials(ctx context.Context, id uint, detailed
if !auth.IsAdmin(ctx) { if !auth.IsAdmin(ctx) {
userID, err := getUIDFromContext(ctx) userID, err := getUIDFromContext(ctx)
if err != nil { if err != nil {
return params.ForgeCredentials{}, errors.Wrap(err, "fetching gitea credentials") return params.ForgeCredentials{}, fmt.Errorf("error fetching gitea credentials: %w", err)
} }
q = q.Where("user_id = ?", userID) q = q.Where("user_id = ?", userID)
} }
@ -333,9 +334,9 @@ func (s *sqlDatabase) GetGiteaCredentials(ctx context.Context, id uint, detailed
err := q.Where("id = ?", id).First(&creds).Error err := q.Where("id = ?", id).First(&creds).Error
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return params.ForgeCredentials{}, errors.Wrap(runnerErrors.ErrNotFound, "gitea credentials not found") return params.ForgeCredentials{}, runnerErrors.NewNotFoundError("gitea credentials not found")
} }
return params.ForgeCredentials{}, errors.Wrap(err, "fetching gitea credentials") return params.ForgeCredentials{}, fmt.Errorf("error fetching gitea credentials: %w", err)
} }
return s.sqlGiteaToCommonForgeCredentials(creds) return s.sqlGiteaToCommonForgeCredentials(creds)
@ -346,7 +347,7 @@ func (s *sqlDatabase) ListGiteaCredentials(ctx context.Context) ([]params.ForgeC
if !auth.IsAdmin(ctx) { if !auth.IsAdmin(ctx) {
userID, err := getUIDFromContext(ctx) userID, err := getUIDFromContext(ctx)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching gitea credentials") return nil, fmt.Errorf("error fetching gitea credentials: %w", err)
} }
q = q.Where("user_id = ?", userID) q = q.Where("user_id = ?", userID)
} }
@ -354,14 +355,14 @@ func (s *sqlDatabase) ListGiteaCredentials(ctx context.Context) ([]params.ForgeC
var creds []GiteaCredentials var creds []GiteaCredentials
err := q.Preload("Endpoint").Find(&creds).Error err := q.Preload("Endpoint").Find(&creds).Error
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching gitea credentials") return nil, fmt.Errorf("error fetching gitea credentials: %w", err)
} }
var ret []params.ForgeCredentials var ret []params.ForgeCredentials
for _, c := range creds { for _, c := range creds {
commonCreds, err := s.sqlGiteaToCommonForgeCredentials(c) commonCreds, err := s.sqlGiteaToCommonForgeCredentials(c)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "converting gitea credentials") return nil, fmt.Errorf("error converting gitea credentials: %w", err)
} }
ret = append(ret, commonCreds) ret = append(ret, commonCreds)
} }
@ -380,16 +381,16 @@ func (s *sqlDatabase) UpdateGiteaCredentials(ctx context.Context, id uint, param
if !auth.IsAdmin(ctx) { if !auth.IsAdmin(ctx) {
userID, err := getUIDFromContext(ctx) userID, err := getUIDFromContext(ctx)
if err != nil { if err != nil {
return errors.Wrap(err, "updating gitea credentials") return fmt.Errorf("error updating gitea credentials: %w", err)
} }
q = q.Where("user_id = ?", userID) q = q.Where("user_id = ?", userID)
} }
if err := q.Where("id = ?", id).First(&creds).Error; err != nil { if err := q.Where("id = ?", id).First(&creds).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return errors.Wrap(runnerErrors.ErrNotFound, "gitea credentials not found") return runnerErrors.NewNotFoundError("gitea credentials not found")
} }
return errors.Wrap(err, "fetching gitea credentials") return fmt.Errorf("error fetching gitea credentials: %w", err)
} }
if param.Name != nil { if param.Name != nil {
@ -407,28 +408,28 @@ func (s *sqlDatabase) UpdateGiteaCredentials(ctx context.Context, id uint, param
data, err = s.marshalAndSeal(param.PAT) data, err = s.marshalAndSeal(param.PAT)
} }
default: default:
return errors.Wrap(runnerErrors.ErrBadRequest, "invalid auth type") return runnerErrors.NewBadRequestError("invalid auth type %q", creds.AuthType)
} }
if err != nil { if err != nil {
return errors.Wrap(err, "marshaling and sealing credentials") return fmt.Errorf("error marshaling and sealing credentials: %w", err)
} }
if len(data) > 0 { if len(data) > 0 {
creds.Payload = data creds.Payload = data
} }
if err := tx.Save(&creds).Error; err != nil { if err := tx.Save(&creds).Error; err != nil {
return errors.Wrap(err, "updating gitea credentials") return fmt.Errorf("error updating gitea credentials: %w", err)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return params.ForgeCredentials{}, errors.Wrap(err, "updating gitea credentials") return params.ForgeCredentials{}, fmt.Errorf("error updating gitea credentials: %w", err)
} }
gtCreds, err = s.sqlGiteaToCommonForgeCredentials(creds) gtCreds, err = s.sqlGiteaToCommonForgeCredentials(creds)
if err != nil { if err != nil {
return params.ForgeCredentials{}, errors.Wrap(err, "converting gitea credentials") return params.ForgeCredentials{}, fmt.Errorf("error converting gitea credentials: %w", err)
} }
return gtCreds, nil return gtCreds, nil
} }
@ -454,7 +455,7 @@ func (s *sqlDatabase) DeleteGiteaCredentials(ctx context.Context, id uint) (err
if !auth.IsAdmin(ctx) { if !auth.IsAdmin(ctx) {
userID, err := getUIDFromContext(ctx) userID, err := getUIDFromContext(ctx)
if err != nil { if err != nil {
return errors.Wrap(err, "deleting gitea credentials") return fmt.Errorf("error deleting gitea credentials: %w", err)
} }
q = q.Where("user_id = ?", userID) q = q.Where("user_id = ?", userID)
} }
@ -464,22 +465,22 @@ func (s *sqlDatabase) DeleteGiteaCredentials(ctx context.Context, id uint) (err
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return nil return nil
} }
return errors.Wrap(err, "fetching gitea credentials") return fmt.Errorf("error fetching gitea credentials: %w", err)
} }
if len(creds.Repositories) > 0 { if len(creds.Repositories) > 0 {
return errors.Wrap(runnerErrors.ErrBadRequest, "cannot delete credentials with repositories") return runnerErrors.NewBadRequestError("cannot delete credentials with repositories")
} }
if len(creds.Organizations) > 0 { if len(creds.Organizations) > 0 {
return errors.Wrap(runnerErrors.ErrBadRequest, "cannot delete credentials with organizations") return runnerErrors.NewBadRequestError("cannot delete credentials with organizations")
} }
if err := tx.Unscoped().Delete(&creds).Error; err != nil { if err := tx.Unscoped().Delete(&creds).Error; err != nil {
return errors.Wrap(err, "deleting gitea credentials") return fmt.Errorf("error deleting gitea credentials: %w", err)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return errors.Wrap(err, "deleting gitea credentials") return fmt.Errorf("error deleting gitea credentials: %w", err)
} }
return nil return nil
} }

View file

@ -236,7 +236,7 @@ func (s *GiteaTestSuite) TestCreateCredentialsFailsWhenEndpointDoesNotExist() {
_, err := s.db.CreateGiteaCredentials(ctx, params.CreateGiteaCredentialsParams{Endpoint: "non-existing"}) _, err := s.db.CreateGiteaCredentials(ctx, params.CreateGiteaCredentialsParams{Endpoint: "non-existing"})
s.Require().Error(err) s.Require().Error(err)
s.Require().ErrorIs(err, runnerErrors.ErrNotFound) s.Require().ErrorIs(err, runnerErrors.ErrNotFound)
s.Require().Regexp("endpoint not found", err.Error()) s.Require().Regexp("error creating gitea credentials: gitea endpoint \"non-existing\" not found", err.Error())
} }
func (s *GiteaTestSuite) TestCreateCredentialsFailsWhenAuthTypeIsInvalid() { func (s *GiteaTestSuite) TestCreateCredentialsFailsWhenAuthTypeIsInvalid() {
@ -807,7 +807,7 @@ func (s *GiteaTestSuite) TestUpdateEndpointURLsFailsIfCredentialsAreAssociated()
_, err = s.db.UpdateGiteaEndpoint(ctx, testEndpointName, updateEpParams) _, err = s.db.UpdateGiteaEndpoint(ctx, testEndpointName, updateEpParams)
s.Require().Error(err) s.Require().Error(err)
s.Require().ErrorIs(err, runnerErrors.ErrBadRequest) s.Require().ErrorIs(err, runnerErrors.ErrBadRequest)
s.Require().EqualError(err, "updating gitea endpoint: cannot update endpoint URLs with existing credentials: invalid request") s.Require().EqualError(err, "error updating gitea endpoint: cannot update endpoint URLs with existing credentials")
updateEpParams = params.UpdateGiteaEndpointParams{ updateEpParams = params.UpdateGiteaEndpointParams{
APIBaseURL: &newAPIBaseURL, APIBaseURL: &newAPIBaseURL,
@ -815,7 +815,7 @@ func (s *GiteaTestSuite) TestUpdateEndpointURLsFailsIfCredentialsAreAssociated()
_, err = s.db.UpdateGiteaEndpoint(ctx, testEndpointName, updateEpParams) _, err = s.db.UpdateGiteaEndpoint(ctx, testEndpointName, updateEpParams)
s.Require().Error(err) s.Require().Error(err)
s.Require().ErrorIs(err, runnerErrors.ErrBadRequest) s.Require().ErrorIs(err, runnerErrors.ErrBadRequest)
s.Require().EqualError(err, "updating gitea endpoint: cannot update endpoint URLs with existing credentials: invalid request") s.Require().EqualError(err, "error updating gitea endpoint: cannot update endpoint URLs with existing credentials")
updateEpParams = params.UpdateGiteaEndpointParams{ updateEpParams = params.UpdateGiteaEndpointParams{
Description: &newDescription, Description: &newDescription,

View file

@ -16,8 +16,9 @@ package sql
import ( import (
"context" "context"
"errors"
"fmt"
"github.com/pkg/errors"
"gorm.io/gorm" "gorm.io/gorm"
runnerErrors "github.com/cloudbase/garm-provider-common/errors" runnerErrors "github.com/cloudbase/garm-provider-common/errors"
@ -35,7 +36,7 @@ func (s *sqlDatabase) CreateGithubEndpoint(_ context.Context, param params.Creat
var endpoint GithubEndpoint var endpoint GithubEndpoint
err = s.conn.Transaction(func(tx *gorm.DB) error { err = s.conn.Transaction(func(tx *gorm.DB) error {
if err := tx.Where("name = ?", param.Name).First(&endpoint).Error; err == nil { if err := tx.Where("name = ?", param.Name).First(&endpoint).Error; err == nil {
return errors.Wrap(runnerErrors.ErrDuplicateEntity, "github endpoint already exists") return fmt.Errorf("error github endpoint already exists: %w", runnerErrors.ErrDuplicateEntity)
} }
endpoint = GithubEndpoint{ endpoint = GithubEndpoint{
Name: param.Name, Name: param.Name,
@ -48,16 +49,16 @@ func (s *sqlDatabase) CreateGithubEndpoint(_ context.Context, param params.Creat
} }
if err := tx.Create(&endpoint).Error; err != nil { if err := tx.Create(&endpoint).Error; err != nil {
return errors.Wrap(err, "creating github endpoint") return fmt.Errorf("error creating github endpoint: %w", err)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return params.ForgeEndpoint{}, errors.Wrap(err, "creating github endpoint") return params.ForgeEndpoint{}, fmt.Errorf("error creating github endpoint: %w", err)
} }
ghEndpoint, err = s.sqlToCommonGithubEndpoint(endpoint) ghEndpoint, err = s.sqlToCommonGithubEndpoint(endpoint)
if err != nil { if err != nil {
return params.ForgeEndpoint{}, errors.Wrap(err, "converting github endpoint") return params.ForgeEndpoint{}, fmt.Errorf("error converting github endpoint: %w", err)
} }
return ghEndpoint, nil return ghEndpoint, nil
} }
@ -66,14 +67,14 @@ func (s *sqlDatabase) ListGithubEndpoints(_ context.Context) ([]params.ForgeEndp
var endpoints []GithubEndpoint var endpoints []GithubEndpoint
err := s.conn.Where("endpoint_type = ?", params.GithubEndpointType).Find(&endpoints).Error err := s.conn.Where("endpoint_type = ?", params.GithubEndpointType).Find(&endpoints).Error
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching github endpoints") return nil, fmt.Errorf("error fetching github endpoints: %w", err)
} }
var ret []params.ForgeEndpoint var ret []params.ForgeEndpoint
for _, ep := range endpoints { for _, ep := range endpoints {
commonEp, err := s.sqlToCommonGithubEndpoint(ep) commonEp, err := s.sqlToCommonGithubEndpoint(ep)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "converting github endpoint") return nil, fmt.Errorf("error converting github endpoint: %w", err)
} }
ret = append(ret, commonEp) ret = append(ret, commonEp)
} }
@ -90,19 +91,19 @@ func (s *sqlDatabase) UpdateGithubEndpoint(_ context.Context, name string, param
err = s.conn.Transaction(func(tx *gorm.DB) error { err = s.conn.Transaction(func(tx *gorm.DB) error {
if err := tx.Where("name = ? and endpoint_type = ?", name, params.GithubEndpointType).First(&endpoint).Error; err != nil { if err := tx.Where("name = ? and endpoint_type = ?", name, params.GithubEndpointType).First(&endpoint).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return errors.Wrap(runnerErrors.ErrNotFound, "github endpoint not found") return fmt.Errorf("error github endpoint not found: %w", runnerErrors.ErrNotFound)
} }
return errors.Wrap(err, "fetching github endpoint") return fmt.Errorf("error fetching github endpoint: %w", err)
} }
var credsCount int64 var credsCount int64
if err := tx.Model(&GithubCredentials{}).Where("endpoint_name = ?", endpoint.Name).Count(&credsCount).Error; err != nil { if err := tx.Model(&GithubCredentials{}).Where("endpoint_name = ?", endpoint.Name).Count(&credsCount).Error; err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) { if !errors.Is(err, gorm.ErrRecordNotFound) {
return errors.Wrap(err, "fetching github credentials") return fmt.Errorf("error fetching github credentials: %w", err)
} }
} }
if credsCount > 0 && (param.APIBaseURL != nil || param.BaseURL != nil || param.UploadBaseURL != nil) { if credsCount > 0 && (param.APIBaseURL != nil || param.BaseURL != nil || param.UploadBaseURL != nil) {
return errors.Wrap(runnerErrors.ErrBadRequest, "cannot update endpoint URLs with existing credentials") return fmt.Errorf("cannot update endpoint URLs with existing credentials: %w", runnerErrors.ErrBadRequest)
} }
if param.APIBaseURL != nil { if param.APIBaseURL != nil {
@ -126,17 +127,17 @@ func (s *sqlDatabase) UpdateGithubEndpoint(_ context.Context, name string, param
} }
if err := tx.Save(&endpoint).Error; err != nil { if err := tx.Save(&endpoint).Error; err != nil {
return errors.Wrap(err, "updating github endpoint") return fmt.Errorf("error updating github endpoint: %w", err)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return params.ForgeEndpoint{}, errors.Wrap(err, "updating github endpoint") return params.ForgeEndpoint{}, fmt.Errorf("error updating github endpoint: %w", err)
} }
ghEndpoint, err = s.sqlToCommonGithubEndpoint(endpoint) ghEndpoint, err = s.sqlToCommonGithubEndpoint(endpoint)
if err != nil { if err != nil {
return params.ForgeEndpoint{}, errors.Wrap(err, "converting github endpoint") return params.ForgeEndpoint{}, fmt.Errorf("error converting github endpoint: %w", err)
} }
return ghEndpoint, nil return ghEndpoint, nil
} }
@ -147,9 +148,9 @@ func (s *sqlDatabase) GetGithubEndpoint(_ context.Context, name string) (params.
err := s.conn.Where("name = ? and endpoint_type = ?", name, params.GithubEndpointType).First(&endpoint).Error err := s.conn.Where("name = ? and endpoint_type = ?", name, params.GithubEndpointType).First(&endpoint).Error
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return params.ForgeEndpoint{}, errors.Wrap(runnerErrors.ErrNotFound, "github endpoint not found") return params.ForgeEndpoint{}, fmt.Errorf("github endpoint not found: %w", runnerErrors.ErrNotFound)
} }
return params.ForgeEndpoint{}, errors.Wrap(err, "fetching github endpoint") return params.ForgeEndpoint{}, fmt.Errorf("error fetching github endpoint: %w", err)
} }
return s.sqlToCommonGithubEndpoint(endpoint) return s.sqlToCommonGithubEndpoint(endpoint)
@ -167,48 +168,48 @@ func (s *sqlDatabase) DeleteGithubEndpoint(_ context.Context, name string) (err
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return nil return nil
} }
return errors.Wrap(err, "fetching github endpoint") return fmt.Errorf("error fetching github endpoint: %w", err)
} }
var credsCount int64 var credsCount int64
if err := tx.Model(&GithubCredentials{}).Where("endpoint_name = ?", endpoint.Name).Count(&credsCount).Error; err != nil { if err := tx.Model(&GithubCredentials{}).Where("endpoint_name = ?", endpoint.Name).Count(&credsCount).Error; err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) { if !errors.Is(err, gorm.ErrRecordNotFound) {
return errors.Wrap(err, "fetching github credentials") return fmt.Errorf("error fetching github credentials: %w", err)
} }
} }
var repoCnt int64 var repoCnt int64
if err := tx.Model(&Repository{}).Where("endpoint_name = ?", endpoint.Name).Count(&repoCnt).Error; err != nil { if err := tx.Model(&Repository{}).Where("endpoint_name = ?", endpoint.Name).Count(&repoCnt).Error; err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) { if !errors.Is(err, gorm.ErrRecordNotFound) {
return errors.Wrap(err, "fetching github repositories") return fmt.Errorf("error fetching github repositories: %w", err)
} }
} }
var orgCnt int64 var orgCnt int64
if err := tx.Model(&Organization{}).Where("endpoint_name = ?", endpoint.Name).Count(&orgCnt).Error; err != nil { if err := tx.Model(&Organization{}).Where("endpoint_name = ?", endpoint.Name).Count(&orgCnt).Error; err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) { if !errors.Is(err, gorm.ErrRecordNotFound) {
return errors.Wrap(err, "fetching github organizations") return fmt.Errorf("error fetching github organizations: %w", err)
} }
} }
var entCnt int64 var entCnt int64
if err := tx.Model(&Enterprise{}).Where("endpoint_name = ?", endpoint.Name).Count(&entCnt).Error; err != nil { if err := tx.Model(&Enterprise{}).Where("endpoint_name = ?", endpoint.Name).Count(&entCnt).Error; err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) { if !errors.Is(err, gorm.ErrRecordNotFound) {
return errors.Wrap(err, "fetching github enterprises") return fmt.Errorf("error fetching github enterprises: %w", err)
} }
} }
if credsCount > 0 || repoCnt > 0 || orgCnt > 0 || entCnt > 0 { if credsCount > 0 || repoCnt > 0 || orgCnt > 0 || entCnt > 0 {
return errors.Wrap(runnerErrors.ErrBadRequest, "cannot delete endpoint with associated entities") return fmt.Errorf("cannot delete endpoint with associated entities: %w", runnerErrors.ErrBadRequest)
} }
if err := tx.Unscoped().Delete(&endpoint).Error; err != nil { if err := tx.Unscoped().Delete(&endpoint).Error; err != nil {
return errors.Wrap(err, "deleting github endpoint") return fmt.Errorf("error deleting github endpoint: %w", err)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return errors.Wrap(err, "deleting github endpoint") return fmt.Errorf("error deleting github endpoint: %w", err)
} }
return nil return nil
} }
@ -216,10 +217,10 @@ func (s *sqlDatabase) DeleteGithubEndpoint(_ context.Context, name string) (err
func (s *sqlDatabase) CreateGithubCredentials(ctx context.Context, param params.CreateGithubCredentialsParams) (ghCreds params.ForgeCredentials, err error) { func (s *sqlDatabase) CreateGithubCredentials(ctx context.Context, param params.CreateGithubCredentialsParams) (ghCreds params.ForgeCredentials, err error) {
userID, err := getUIDFromContext(ctx) userID, err := getUIDFromContext(ctx)
if err != nil { if err != nil {
return params.ForgeCredentials{}, errors.Wrap(err, "creating github credentials") return params.ForgeCredentials{}, fmt.Errorf("error creating github credentials: %w", err)
} }
if param.Endpoint == "" { if param.Endpoint == "" {
return params.ForgeCredentials{}, errors.Wrap(runnerErrors.ErrBadRequest, "endpoint name is required") return params.ForgeCredentials{}, fmt.Errorf("endpoint name is required: %w", runnerErrors.ErrBadRequest)
} }
defer func() { defer func() {
@ -232,13 +233,13 @@ func (s *sqlDatabase) CreateGithubCredentials(ctx context.Context, param params.
var endpoint GithubEndpoint var endpoint GithubEndpoint
if err := tx.Where("name = ? and endpoint_type = ?", param.Endpoint, params.GithubEndpointType).First(&endpoint).Error; err != nil { if err := tx.Where("name = ? and endpoint_type = ?", param.Endpoint, params.GithubEndpointType).First(&endpoint).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return errors.Wrap(runnerErrors.ErrNotFound, "github endpoint not found") return fmt.Errorf("github endpoint not found: %w", runnerErrors.ErrNotFound)
} }
return errors.Wrap(err, "fetching github endpoint") return fmt.Errorf("error fetching github endpoint: %w", err)
} }
if err := tx.Where("name = ? and user_id = ?", param.Name, userID).First(&creds).Error; err == nil { if err := tx.Where("name = ? and user_id = ?", param.Name, userID).First(&creds).Error; err == nil {
return errors.Wrap(runnerErrors.ErrDuplicateEntity, "github credentials already exists") return fmt.Errorf("github credentials already exists: %w", runnerErrors.ErrDuplicateEntity)
} }
var data []byte var data []byte
@ -249,10 +250,10 @@ func (s *sqlDatabase) CreateGithubCredentials(ctx context.Context, param params.
case params.ForgeAuthTypeApp: case params.ForgeAuthTypeApp:
data, err = s.marshalAndSeal(param.App) data, err = s.marshalAndSeal(param.App)
default: default:
return errors.Wrap(runnerErrors.ErrBadRequest, "invalid auth type") return fmt.Errorf("invalid auth type: %w", runnerErrors.ErrBadRequest)
} }
if err != nil { if err != nil {
return errors.Wrap(err, "marshaling and sealing credentials") return fmt.Errorf("error marshaling and sealing credentials: %w", err)
} }
creds = GithubCredentials{ creds = GithubCredentials{
@ -265,7 +266,7 @@ func (s *sqlDatabase) CreateGithubCredentials(ctx context.Context, param params.
} }
if err := tx.Create(&creds).Error; err != nil { if err := tx.Create(&creds).Error; err != nil {
return errors.Wrap(err, "creating github credentials") return fmt.Errorf("error creating github credentials: %w", err)
} }
// Skip making an extra query. // Skip making an extra query.
creds.Endpoint = endpoint creds.Endpoint = endpoint
@ -273,11 +274,11 @@ func (s *sqlDatabase) CreateGithubCredentials(ctx context.Context, param params.
return nil return nil
}) })
if err != nil { if err != nil {
return params.ForgeCredentials{}, errors.Wrap(err, "creating github credentials") return params.ForgeCredentials{}, fmt.Errorf("error creating github credentials: %w", err)
} }
ghCreds, err = s.sqlToCommonForgeCredentials(creds) ghCreds, err = s.sqlToCommonForgeCredentials(creds)
if err != nil { if err != nil {
return params.ForgeCredentials{}, errors.Wrap(err, "converting github credentials") return params.ForgeCredentials{}, fmt.Errorf("error converting github credentials: %w", err)
} }
return ghCreds, nil return ghCreds, nil
} }
@ -298,16 +299,16 @@ func (s *sqlDatabase) getGithubCredentialsByName(ctx context.Context, tx *gorm.D
userID, err := getUIDFromContext(ctx) userID, err := getUIDFromContext(ctx)
if err != nil { if err != nil {
return GithubCredentials{}, errors.Wrap(err, "fetching github credentials") return GithubCredentials{}, fmt.Errorf("error fetching github credentials: %w", err)
} }
q = q.Where("user_id = ?", userID) q = q.Where("user_id = ?", userID)
err = q.Where("name = ?", name).First(&creds).Error err = q.Where("name = ?", name).First(&creds).Error
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return GithubCredentials{}, errors.Wrap(runnerErrors.ErrNotFound, "github credentials not found") return GithubCredentials{}, fmt.Errorf("github credentials not found: %w", runnerErrors.ErrNotFound)
} }
return GithubCredentials{}, errors.Wrap(err, "fetching github credentials") return GithubCredentials{}, fmt.Errorf("error fetching github credentials: %w", err)
} }
return creds, nil return creds, nil
@ -316,7 +317,7 @@ func (s *sqlDatabase) getGithubCredentialsByName(ctx context.Context, tx *gorm.D
func (s *sqlDatabase) GetGithubCredentialsByName(ctx context.Context, name string, detailed bool) (params.ForgeCredentials, error) { func (s *sqlDatabase) GetGithubCredentialsByName(ctx context.Context, name string, detailed bool) (params.ForgeCredentials, error) {
creds, err := s.getGithubCredentialsByName(ctx, s.conn, name, detailed) creds, err := s.getGithubCredentialsByName(ctx, s.conn, name, detailed)
if err != nil { if err != nil {
return params.ForgeCredentials{}, errors.Wrap(err, "fetching github credentials") return params.ForgeCredentials{}, fmt.Errorf("error fetching github credentials: %w", err)
} }
return s.sqlToCommonForgeCredentials(creds) return s.sqlToCommonForgeCredentials(creds)
} }
@ -338,7 +339,7 @@ func (s *sqlDatabase) GetGithubCredentials(ctx context.Context, id uint, detaile
if !auth.IsAdmin(ctx) { if !auth.IsAdmin(ctx) {
userID, err := getUIDFromContext(ctx) userID, err := getUIDFromContext(ctx)
if err != nil { if err != nil {
return params.ForgeCredentials{}, errors.Wrap(err, "fetching github credentials") return params.ForgeCredentials{}, fmt.Errorf("error fetching github credentials: %w", err)
} }
q = q.Where("user_id = ?", userID) q = q.Where("user_id = ?", userID)
} }
@ -346,9 +347,9 @@ func (s *sqlDatabase) GetGithubCredentials(ctx context.Context, id uint, detaile
err := q.Where("id = ?", id).First(&creds).Error err := q.Where("id = ?", id).First(&creds).Error
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return params.ForgeCredentials{}, errors.Wrap(runnerErrors.ErrNotFound, "github credentials not found") return params.ForgeCredentials{}, fmt.Errorf("github credentials not found: %w", runnerErrors.ErrNotFound)
} }
return params.ForgeCredentials{}, errors.Wrap(err, "fetching github credentials") return params.ForgeCredentials{}, fmt.Errorf("error fetching github credentials: %w", err)
} }
return s.sqlToCommonForgeCredentials(creds) return s.sqlToCommonForgeCredentials(creds)
@ -359,7 +360,7 @@ func (s *sqlDatabase) ListGithubCredentials(ctx context.Context) ([]params.Forge
if !auth.IsAdmin(ctx) { if !auth.IsAdmin(ctx) {
userID, err := getUIDFromContext(ctx) userID, err := getUIDFromContext(ctx)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching github credentials") return nil, fmt.Errorf("error fetching github credentials: %w", err)
} }
q = q.Where("user_id = ?", userID) q = q.Where("user_id = ?", userID)
} }
@ -367,14 +368,14 @@ func (s *sqlDatabase) ListGithubCredentials(ctx context.Context) ([]params.Forge
var creds []GithubCredentials var creds []GithubCredentials
err := q.Preload("Endpoint").Find(&creds).Error err := q.Preload("Endpoint").Find(&creds).Error
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching github credentials") return nil, fmt.Errorf("error fetching github credentials: %w", err)
} }
var ret []params.ForgeCredentials var ret []params.ForgeCredentials
for _, c := range creds { for _, c := range creds {
commonCreds, err := s.sqlToCommonForgeCredentials(c) commonCreds, err := s.sqlToCommonForgeCredentials(c)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "converting github credentials") return nil, fmt.Errorf("error converting github credentials: %w", err)
} }
ret = append(ret, commonCreds) ret = append(ret, commonCreds)
} }
@ -393,16 +394,16 @@ func (s *sqlDatabase) UpdateGithubCredentials(ctx context.Context, id uint, para
if !auth.IsAdmin(ctx) { if !auth.IsAdmin(ctx) {
userID, err := getUIDFromContext(ctx) userID, err := getUIDFromContext(ctx)
if err != nil { if err != nil {
return errors.Wrap(err, "updating github credentials") return fmt.Errorf("error updating github credentials: %w", err)
} }
q = q.Where("user_id = ?", userID) q = q.Where("user_id = ?", userID)
} }
if err := q.Where("id = ?", id).First(&creds).Error; err != nil { if err := q.Where("id = ?", id).First(&creds).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return errors.Wrap(runnerErrors.ErrNotFound, "github credentials not found") return fmt.Errorf("github credentials not found: %w", runnerErrors.ErrNotFound)
} }
return errors.Wrap(err, "fetching github credentials") return fmt.Errorf("error fetching github credentials: %w", err)
} }
if param.Name != nil { if param.Name != nil {
@ -421,7 +422,7 @@ func (s *sqlDatabase) UpdateGithubCredentials(ctx context.Context, id uint, para
} }
if param.App != nil { if param.App != nil {
return errors.Wrap(runnerErrors.ErrBadRequest, "cannot update app credentials for PAT") return fmt.Errorf("cannot update app credentials for PAT: %w", runnerErrors.ErrBadRequest)
} }
case params.ForgeAuthTypeApp: case params.ForgeAuthTypeApp:
if param.App != nil { if param.App != nil {
@ -429,33 +430,33 @@ func (s *sqlDatabase) UpdateGithubCredentials(ctx context.Context, id uint, para
} }
if param.PAT != nil { if param.PAT != nil {
return errors.Wrap(runnerErrors.ErrBadRequest, "cannot update PAT credentials for app") return fmt.Errorf("cannot update PAT credentials for app: %w", runnerErrors.ErrBadRequest)
} }
default: default:
// This should never happen, unless there was a bug in the DB migration code, // This should never happen, unless there was a bug in the DB migration code,
// or the DB was manually modified. // or the DB was manually modified.
return errors.Wrap(runnerErrors.ErrBadRequest, "invalid auth type") return fmt.Errorf("invalid auth type: %w", runnerErrors.ErrBadRequest)
} }
if err != nil { if err != nil {
return errors.Wrap(err, "marshaling and sealing credentials") return fmt.Errorf("error marshaling and sealing credentials: %w", err)
} }
if len(data) > 0 { if len(data) > 0 {
creds.Payload = data creds.Payload = data
} }
if err := tx.Save(&creds).Error; err != nil { if err := tx.Save(&creds).Error; err != nil {
return errors.Wrap(err, "updating github credentials") return fmt.Errorf("error updating github credentials: %w", err)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return params.ForgeCredentials{}, errors.Wrap(err, "updating github credentials") return params.ForgeCredentials{}, fmt.Errorf("error updating github credentials: %w", err)
} }
ghCreds, err = s.sqlToCommonForgeCredentials(creds) ghCreds, err = s.sqlToCommonForgeCredentials(creds)
if err != nil { if err != nil {
return params.ForgeCredentials{}, errors.Wrap(err, "converting github credentials") return params.ForgeCredentials{}, fmt.Errorf("error converting github credentials: %w", err)
} }
return ghCreds, nil return ghCreds, nil
} }
@ -475,7 +476,7 @@ func (s *sqlDatabase) DeleteGithubCredentials(ctx context.Context, id uint) (err
if !auth.IsAdmin(ctx) { if !auth.IsAdmin(ctx) {
userID, err := getUIDFromContext(ctx) userID, err := getUIDFromContext(ctx)
if err != nil { if err != nil {
return errors.Wrap(err, "deleting github credentials") return fmt.Errorf("error deleting github credentials: %w", err)
} }
q = q.Where("user_id = ?", userID) q = q.Where("user_id = ?", userID)
} }
@ -486,27 +487,27 @@ func (s *sqlDatabase) DeleteGithubCredentials(ctx context.Context, id uint) (err
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return nil return nil
} }
return errors.Wrap(err, "fetching github credentials") return fmt.Errorf("error fetching github credentials: %w", err)
} }
name = creds.Name name = creds.Name
if len(creds.Repositories) > 0 { if len(creds.Repositories) > 0 {
return errors.Wrap(runnerErrors.ErrBadRequest, "cannot delete credentials with repositories") return fmt.Errorf("cannot delete credentials with repositories: %w", runnerErrors.ErrBadRequest)
} }
if len(creds.Organizations) > 0 { if len(creds.Organizations) > 0 {
return errors.Wrap(runnerErrors.ErrBadRequest, "cannot delete credentials with organizations") return fmt.Errorf("cannot delete credentials with organizations: %w", runnerErrors.ErrBadRequest)
} }
if len(creds.Enterprises) > 0 { if len(creds.Enterprises) > 0 {
return errors.Wrap(runnerErrors.ErrBadRequest, "cannot delete credentials with enterprises") return fmt.Errorf("cannot delete credentials with enterprises: %w", runnerErrors.ErrBadRequest)
} }
if err := tx.Unscoped().Delete(&creds).Error; err != nil { if err := tx.Unscoped().Delete(&creds).Error; err != nil {
return errors.Wrap(err, "deleting github credentials") return fmt.Errorf("error deleting github credentials: %w", err)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return errors.Wrap(err, "deleting github credentials") return fmt.Errorf("error deleting github credentials: %w", err)
} }
return nil return nil
} }

View file

@ -265,7 +265,7 @@ func (s *GithubTestSuite) TestUpdateEndpointURLsFailsIfCredentialsAreAssociated(
_, err = s.db.UpdateGithubEndpoint(ctx, testEndpointName, updateEpParams) _, err = s.db.UpdateGithubEndpoint(ctx, testEndpointName, updateEpParams)
s.Require().Error(err) s.Require().Error(err)
s.Require().ErrorIs(err, runnerErrors.ErrBadRequest) s.Require().ErrorIs(err, runnerErrors.ErrBadRequest)
s.Require().EqualError(err, "updating github endpoint: cannot update endpoint URLs with existing credentials: invalid request") s.Require().EqualError(err, "error updating github endpoint: cannot update endpoint URLs with existing credentials: invalid request")
updateEpParams = params.UpdateGithubEndpointParams{ updateEpParams = params.UpdateGithubEndpointParams{
UploadBaseURL: &newUploadBaseURL, UploadBaseURL: &newUploadBaseURL,
@ -274,7 +274,7 @@ func (s *GithubTestSuite) TestUpdateEndpointURLsFailsIfCredentialsAreAssociated(
_, err = s.db.UpdateGithubEndpoint(ctx, testEndpointName, updateEpParams) _, err = s.db.UpdateGithubEndpoint(ctx, testEndpointName, updateEpParams)
s.Require().Error(err) s.Require().Error(err)
s.Require().ErrorIs(err, runnerErrors.ErrBadRequest) s.Require().ErrorIs(err, runnerErrors.ErrBadRequest)
s.Require().EqualError(err, "updating github endpoint: cannot update endpoint URLs with existing credentials: invalid request") s.Require().EqualError(err, "error updating github endpoint: cannot update endpoint URLs with existing credentials: invalid request")
updateEpParams = params.UpdateGithubEndpointParams{ updateEpParams = params.UpdateGithubEndpointParams{
APIBaseURL: &newAPIBaseURL, APIBaseURL: &newAPIBaseURL,
@ -282,7 +282,7 @@ func (s *GithubTestSuite) TestUpdateEndpointURLsFailsIfCredentialsAreAssociated(
_, err = s.db.UpdateGithubEndpoint(ctx, testEndpointName, updateEpParams) _, err = s.db.UpdateGithubEndpoint(ctx, testEndpointName, updateEpParams)
s.Require().Error(err) s.Require().Error(err)
s.Require().ErrorIs(err, runnerErrors.ErrBadRequest) s.Require().ErrorIs(err, runnerErrors.ErrBadRequest)
s.Require().EqualError(err, "updating github endpoint: cannot update endpoint URLs with existing credentials: invalid request") s.Require().EqualError(err, "error updating github endpoint: cannot update endpoint URLs with existing credentials: invalid request")
updateEpParams = params.UpdateGithubEndpointParams{ updateEpParams = params.UpdateGithubEndpointParams{
Description: &newDescription, Description: &newDescription,
@ -737,7 +737,7 @@ func (s *GithubTestSuite) TestUpdateGithubCredentialsFailIfWrongCredentialTypeIs
_, err = s.db.UpdateGithubCredentials(ctx, creds.ID, updateCredParams) _, err = s.db.UpdateGithubCredentials(ctx, creds.ID, updateCredParams)
s.Require().Error(err) s.Require().Error(err)
s.Require().ErrorIs(err, runnerErrors.ErrBadRequest) s.Require().ErrorIs(err, runnerErrors.ErrBadRequest)
s.Require().EqualError(err, "updating github credentials: cannot update app credentials for PAT: invalid request") s.Require().EqualError(err, "error updating github credentials: cannot update app credentials for PAT: invalid request")
credParamsWithApp := params.CreateGithubCredentialsParams{ credParamsWithApp := params.CreateGithubCredentialsParams{
Name: "test-credsApp", Name: "test-credsApp",
@ -764,7 +764,7 @@ func (s *GithubTestSuite) TestUpdateGithubCredentialsFailIfWrongCredentialTypeIs
_, err = s.db.UpdateGithubCredentials(ctx, credsApp.ID, updateCredParams) _, err = s.db.UpdateGithubCredentials(ctx, credsApp.ID, updateCredParams)
s.Require().Error(err) s.Require().Error(err)
s.Require().ErrorIs(err, runnerErrors.ErrBadRequest) s.Require().ErrorIs(err, runnerErrors.ErrBadRequest)
s.Require().EqualError(err, "updating github credentials: cannot update PAT credentials for app: invalid request") s.Require().EqualError(err, "error updating github credentials: cannot update PAT credentials for app: invalid request")
} }
func (s *GithubTestSuite) TestUpdateCredentialsFailsForNonExistingCredentials() { func (s *GithubTestSuite) TestUpdateCredentialsFailsForNonExistingCredentials() {

View file

@ -17,10 +17,11 @@ package sql
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"errors"
"fmt"
"log/slog" "log/slog"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/pkg/errors"
"gorm.io/datatypes" "gorm.io/datatypes"
"gorm.io/gorm" "gorm.io/gorm"
"gorm.io/gorm/clause" "gorm.io/gorm/clause"
@ -33,7 +34,7 @@ import (
func (s *sqlDatabase) CreateInstance(_ context.Context, poolID string, param params.CreateInstanceParams) (instance params.Instance, err error) { func (s *sqlDatabase) CreateInstance(_ context.Context, poolID string, param params.CreateInstanceParams) (instance params.Instance, err error) {
pool, err := s.getPoolByID(s.conn, poolID) pool, err := s.getPoolByID(s.conn, poolID)
if err != nil { if err != nil {
return params.Instance{}, errors.Wrap(err, "fetching pool") return params.Instance{}, fmt.Errorf("error fetching pool: %w", err)
} }
defer func() { defer func() {
@ -46,7 +47,7 @@ func (s *sqlDatabase) CreateInstance(_ context.Context, poolID string, param par
if len(param.AditionalLabels) > 0 { if len(param.AditionalLabels) > 0 {
labels, err = json.Marshal(param.AditionalLabels) labels, err = json.Marshal(param.AditionalLabels)
if err != nil { if err != nil {
return params.Instance{}, errors.Wrap(err, "marshalling labels") return params.Instance{}, fmt.Errorf("error marshalling labels: %w", err)
} }
} }
@ -54,7 +55,7 @@ func (s *sqlDatabase) CreateInstance(_ context.Context, poolID string, param par
if len(param.JitConfiguration) > 0 { if len(param.JitConfiguration) > 0 {
secret, err = s.marshalAndSeal(param.JitConfiguration) secret, err = s.marshalAndSeal(param.JitConfiguration)
if err != nil { if err != nil {
return params.Instance{}, errors.Wrap(err, "marshalling jit config") return params.Instance{}, fmt.Errorf("error marshalling jit config: %w", err)
} }
} }
@ -74,7 +75,7 @@ func (s *sqlDatabase) CreateInstance(_ context.Context, poolID string, param par
} }
q := s.conn.Create(&newInstance) q := s.conn.Create(&newInstance)
if q.Error != nil { if q.Error != nil {
return params.Instance{}, errors.Wrap(q.Error, "creating instance") return params.Instance{}, fmt.Errorf("error creating instance: %w", q.Error)
} }
return s.sqlToParamsInstance(newInstance) return s.sqlToParamsInstance(newInstance)
@ -83,7 +84,7 @@ func (s *sqlDatabase) CreateInstance(_ context.Context, poolID string, param par
func (s *sqlDatabase) getPoolInstanceByName(poolID string, instanceName string) (Instance, error) { func (s *sqlDatabase) getPoolInstanceByName(poolID string, instanceName string) (Instance, error) {
pool, err := s.getPoolByID(s.conn, poolID) pool, err := s.getPoolByID(s.conn, poolID)
if err != nil { if err != nil {
return Instance{}, errors.Wrap(err, "fetching pool") return Instance{}, fmt.Errorf("error fetching pool: %w", err)
} }
var instance Instance var instance Instance
@ -93,9 +94,9 @@ func (s *sqlDatabase) getPoolInstanceByName(poolID string, instanceName string)
First(&instance) First(&instance)
if q.Error != nil { if q.Error != nil {
if errors.Is(q.Error, gorm.ErrRecordNotFound) { if errors.Is(q.Error, gorm.ErrRecordNotFound) {
return Instance{}, errors.Wrap(runnerErrors.ErrNotFound, "fetching pool instance by name") return Instance{}, fmt.Errorf("error fetching pool instance by name: %w", runnerErrors.ErrNotFound)
} }
return Instance{}, errors.Wrap(q.Error, "fetching pool instance by name") return Instance{}, fmt.Errorf("error fetching pool instance by name: %w", q.Error)
} }
instance.Pool = pool instance.Pool = pool
@ -119,9 +120,9 @@ func (s *sqlDatabase) getInstanceByName(_ context.Context, instanceName string,
First(&instance) First(&instance)
if q.Error != nil { if q.Error != nil {
if errors.Is(q.Error, gorm.ErrRecordNotFound) { if errors.Is(q.Error, gorm.ErrRecordNotFound) {
return Instance{}, errors.Wrap(runnerErrors.ErrNotFound, "fetching instance by name") return Instance{}, fmt.Errorf("error fetching instance by name: %w", runnerErrors.ErrNotFound)
} }
return Instance{}, errors.Wrap(q.Error, "fetching instance by name") return Instance{}, fmt.Errorf("error fetching instance by name: %w", q.Error)
} }
return instance, nil return instance, nil
} }
@ -129,7 +130,7 @@ func (s *sqlDatabase) getInstanceByName(_ context.Context, instanceName string,
func (s *sqlDatabase) GetPoolInstanceByName(_ context.Context, poolID string, instanceName string) (params.Instance, error) { func (s *sqlDatabase) GetPoolInstanceByName(_ context.Context, poolID string, instanceName string) (params.Instance, error) {
instance, err := s.getPoolInstanceByName(poolID, instanceName) instance, err := s.getPoolInstanceByName(poolID, instanceName)
if err != nil { if err != nil {
return params.Instance{}, errors.Wrap(err, "fetching instance") return params.Instance{}, fmt.Errorf("error fetching instance: %w", err)
} }
return s.sqlToParamsInstance(instance) return s.sqlToParamsInstance(instance)
@ -138,7 +139,7 @@ func (s *sqlDatabase) GetPoolInstanceByName(_ context.Context, poolID string, in
func (s *sqlDatabase) GetInstanceByName(ctx context.Context, instanceName string) (params.Instance, error) { func (s *sqlDatabase) GetInstanceByName(ctx context.Context, instanceName string) (params.Instance, error) {
instance, err := s.getInstanceByName(ctx, instanceName, "StatusMessages", "Pool", "ScaleSet") instance, err := s.getInstanceByName(ctx, instanceName, "StatusMessages", "Pool", "ScaleSet")
if err != nil { if err != nil {
return params.Instance{}, errors.Wrap(err, "fetching instance") return params.Instance{}, fmt.Errorf("error fetching instance: %w", err)
} }
return s.sqlToParamsInstance(instance) return s.sqlToParamsInstance(instance)
@ -150,7 +151,7 @@ func (s *sqlDatabase) DeleteInstance(_ context.Context, poolID string, instanceN
if errors.Is(err, runnerErrors.ErrNotFound) { if errors.Is(err, runnerErrors.ErrNotFound) {
return nil return nil
} }
return errors.Wrap(err, "deleting instance") return fmt.Errorf("error deleting instance: %w", err)
} }
defer func() { defer func() {
@ -182,7 +183,7 @@ func (s *sqlDatabase) DeleteInstance(_ context.Context, poolID string, instanceN
if errors.Is(q.Error, gorm.ErrRecordNotFound) { if errors.Is(q.Error, gorm.ErrRecordNotFound) {
return nil return nil
} }
return errors.Wrap(q.Error, "deleting instance") return fmt.Errorf("error deleting instance: %w", q.Error)
} }
return nil return nil
} }
@ -193,7 +194,7 @@ func (s *sqlDatabase) DeleteInstanceByName(ctx context.Context, instanceName str
if errors.Is(err, runnerErrors.ErrNotFound) { if errors.Is(err, runnerErrors.ErrNotFound) {
return nil return nil
} }
return errors.Wrap(err, "deleting instance") return fmt.Errorf("error deleting instance: %w", err)
} }
defer func() { defer func() {
@ -224,7 +225,7 @@ func (s *sqlDatabase) DeleteInstanceByName(ctx context.Context, instanceName str
if errors.Is(q.Error, gorm.ErrRecordNotFound) { if errors.Is(q.Error, gorm.ErrRecordNotFound) {
return nil return nil
} }
return errors.Wrap(q.Error, "deleting instance") return fmt.Errorf("error deleting instance: %w", q.Error)
} }
return nil return nil
} }
@ -232,7 +233,7 @@ func (s *sqlDatabase) DeleteInstanceByName(ctx context.Context, instanceName str
func (s *sqlDatabase) AddInstanceEvent(ctx context.Context, instanceName string, event params.EventType, eventLevel params.EventLevel, statusMessage string) error { func (s *sqlDatabase) AddInstanceEvent(ctx context.Context, instanceName string, event params.EventType, eventLevel params.EventLevel, statusMessage string) error {
instance, err := s.getInstanceByName(ctx, instanceName) instance, err := s.getInstanceByName(ctx, instanceName)
if err != nil { if err != nil {
return errors.Wrap(err, "updating instance") return fmt.Errorf("error updating instance: %w", err)
} }
msg := InstanceStatusUpdate{ msg := InstanceStatusUpdate{
@ -242,7 +243,7 @@ func (s *sqlDatabase) AddInstanceEvent(ctx context.Context, instanceName string,
} }
if err := s.conn.Model(&instance).Association("StatusMessages").Append(&msg); err != nil { if err := s.conn.Model(&instance).Association("StatusMessages").Append(&msg); err != nil {
return errors.Wrap(err, "adding status message") return fmt.Errorf("error adding status message: %w", err)
} }
return nil return nil
} }
@ -250,7 +251,7 @@ func (s *sqlDatabase) AddInstanceEvent(ctx context.Context, instanceName string,
func (s *sqlDatabase) UpdateInstance(ctx context.Context, instanceName string, param params.UpdateInstanceParams) (params.Instance, error) { func (s *sqlDatabase) UpdateInstance(ctx context.Context, instanceName string, param params.UpdateInstanceParams) (params.Instance, error) {
instance, err := s.getInstanceByName(ctx, instanceName, "Pool", "ScaleSet") instance, err := s.getInstanceByName(ctx, instanceName, "Pool", "ScaleSet")
if err != nil { if err != nil {
return params.Instance{}, errors.Wrap(err, "updating instance") return params.Instance{}, fmt.Errorf("error updating instance: %w", err)
} }
if param.AgentID != 0 { if param.AgentID != 0 {
@ -287,7 +288,7 @@ func (s *sqlDatabase) UpdateInstance(ctx context.Context, instanceName string, p
if param.JitConfiguration != nil { if param.JitConfiguration != nil {
secret, err := s.marshalAndSeal(param.JitConfiguration) secret, err := s.marshalAndSeal(param.JitConfiguration)
if err != nil { if err != nil {
return params.Instance{}, errors.Wrap(err, "marshalling jit config") return params.Instance{}, fmt.Errorf("error marshalling jit config: %w", err)
} }
instance.JitConfiguration = secret instance.JitConfiguration = secret
} }
@ -296,7 +297,7 @@ func (s *sqlDatabase) UpdateInstance(ctx context.Context, instanceName string, p
q := s.conn.Save(&instance) q := s.conn.Save(&instance)
if q.Error != nil { if q.Error != nil {
return params.Instance{}, errors.Wrap(q.Error, "updating instance") return params.Instance{}, fmt.Errorf("error updating instance: %w", q.Error)
} }
if len(param.Addresses) > 0 { if len(param.Addresses) > 0 {
@ -308,12 +309,12 @@ func (s *sqlDatabase) UpdateInstance(ctx context.Context, instanceName string, p
}) })
} }
if err := s.conn.Model(&instance).Association("Addresses").Replace(addrs); err != nil { if err := s.conn.Model(&instance).Association("Addresses").Replace(addrs); err != nil {
return params.Instance{}, errors.Wrap(err, "updating addresses") return params.Instance{}, fmt.Errorf("error updating addresses: %w", err)
} }
} }
inst, err := s.sqlToParamsInstance(instance) inst, err := s.sqlToParamsInstance(instance)
if err != nil { if err != nil {
return params.Instance{}, errors.Wrap(err, "converting instance") return params.Instance{}, fmt.Errorf("error converting instance: %w", err)
} }
s.sendNotify(common.InstanceEntityType, common.UpdateOperation, inst) s.sendNotify(common.InstanceEntityType, common.UpdateOperation, inst)
return inst, nil return inst, nil
@ -322,7 +323,7 @@ func (s *sqlDatabase) UpdateInstance(ctx context.Context, instanceName string, p
func (s *sqlDatabase) ListPoolInstances(_ context.Context, poolID string) ([]params.Instance, error) { func (s *sqlDatabase) ListPoolInstances(_ context.Context, poolID string) ([]params.Instance, error) {
u, err := uuid.Parse(poolID) u, err := uuid.Parse(poolID)
if err != nil { if err != nil {
return nil, errors.Wrap(runnerErrors.ErrBadRequest, "parsing id") return nil, fmt.Errorf("error parsing id: %w", runnerErrors.ErrBadRequest)
} }
var instances []Instance var instances []Instance
@ -332,14 +333,14 @@ func (s *sqlDatabase) ListPoolInstances(_ context.Context, poolID string) ([]par
Where("pool_id = ?", u) Where("pool_id = ?", u)
if err := query.Find(&instances); err.Error != nil { if err := query.Find(&instances); err.Error != nil {
return nil, errors.Wrap(err.Error, "fetching instances") return nil, fmt.Errorf("error fetching instances: %w", err.Error)
} }
ret := make([]params.Instance, len(instances)) ret := make([]params.Instance, len(instances))
for idx, inst := range instances { for idx, inst := range instances {
ret[idx], err = s.sqlToParamsInstance(inst) ret[idx], err = s.sqlToParamsInstance(inst)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "converting instance") return nil, fmt.Errorf("error converting instance: %w", err)
} }
} }
return ret, nil return ret, nil
@ -354,14 +355,14 @@ func (s *sqlDatabase) ListAllInstances(_ context.Context) ([]params.Instance, er
Preload("Job"). Preload("Job").
Find(&instances) Find(&instances)
if q.Error != nil { if q.Error != nil {
return nil, errors.Wrap(q.Error, "fetching instances") return nil, fmt.Errorf("error fetching instances: %w", q.Error)
} }
ret := make([]params.Instance, len(instances)) ret := make([]params.Instance, len(instances))
var err error var err error
for idx, instance := range instances { for idx, instance := range instances {
ret[idx], err = s.sqlToParamsInstance(instance) ret[idx], err = s.sqlToParamsInstance(instance)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "converting instance") return nil, fmt.Errorf("error converting instance: %w", err)
} }
} }
return ret, nil return ret, nil
@ -370,13 +371,13 @@ func (s *sqlDatabase) ListAllInstances(_ context.Context) ([]params.Instance, er
func (s *sqlDatabase) PoolInstanceCount(_ context.Context, poolID string) (int64, error) { func (s *sqlDatabase) PoolInstanceCount(_ context.Context, poolID string) (int64, error) {
pool, err := s.getPoolByID(s.conn, poolID) pool, err := s.getPoolByID(s.conn, poolID)
if err != nil { if err != nil {
return 0, errors.Wrap(err, "fetching pool") return 0, fmt.Errorf("error fetching pool: %w", err)
} }
var cnt int64 var cnt int64
q := s.conn.Model(&Instance{}).Where("pool_id = ?", pool.ID).Count(&cnt) q := s.conn.Model(&Instance{}).Where("pool_id = ?", pool.ID).Count(&cnt)
if q.Error != nil { if q.Error != nil {
return 0, errors.Wrap(q.Error, "fetching instance count") return 0, fmt.Errorf("error fetching instance count: %w", q.Error)
} }
return cnt, nil return cnt, nil
} }

View file

@ -210,7 +210,7 @@ func (s *InstancesTestSuite) TestCreateInstance() {
func (s *InstancesTestSuite) TestCreateInstanceInvalidPoolID() { func (s *InstancesTestSuite) TestCreateInstanceInvalidPoolID() {
_, err := s.Store.CreateInstance(s.adminCtx, "dummy-pool-id", params.CreateInstanceParams{}) _, err := s.Store.CreateInstance(s.adminCtx, "dummy-pool-id", params.CreateInstanceParams{})
s.Require().Equal("fetching pool: parsing id: invalid request", err.Error()) s.Require().Equal("error fetching pool: error parsing id: invalid request", err.Error())
} }
func (s *InstancesTestSuite) TestCreateInstanceDBCreateErr() { func (s *InstancesTestSuite) TestCreateInstanceDBCreateErr() {
@ -233,7 +233,7 @@ func (s *InstancesTestSuite) TestCreateInstanceDBCreateErr() {
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("creating instance: mocked insert instance error", err.Error()) s.Require().Equal("error creating instance: mocked insert instance error", err.Error())
} }
func (s *InstancesTestSuite) TestGetPoolInstanceByName() { func (s *InstancesTestSuite) TestGetPoolInstanceByName() {
@ -252,7 +252,7 @@ func (s *InstancesTestSuite) TestGetPoolInstanceByName() {
func (s *InstancesTestSuite) TestGetPoolInstanceByNameNotFound() { func (s *InstancesTestSuite) TestGetPoolInstanceByNameNotFound() {
_, err := s.Store.GetPoolInstanceByName(s.adminCtx, s.Fixtures.Pool.ID, "not-existent-instance-name") _, err := s.Store.GetPoolInstanceByName(s.adminCtx, s.Fixtures.Pool.ID, "not-existent-instance-name")
s.Require().Equal("fetching instance: fetching pool instance by name: not found", err.Error()) s.Require().Equal("error fetching instance: error fetching pool instance by name: not found", err.Error())
} }
func (s *InstancesTestSuite) TestGetInstanceByName() { func (s *InstancesTestSuite) TestGetInstanceByName() {
@ -271,7 +271,7 @@ func (s *InstancesTestSuite) TestGetInstanceByName() {
func (s *InstancesTestSuite) TestGetInstanceByNameFetchInstanceFailed() { func (s *InstancesTestSuite) TestGetInstanceByNameFetchInstanceFailed() {
_, err := s.Store.GetInstanceByName(s.adminCtx, "not-existent-instance-name") _, err := s.Store.GetInstanceByName(s.adminCtx, "not-existent-instance-name")
s.Require().Equal("fetching instance: fetching instance by name: not found", err.Error()) s.Require().Equal("error fetching instance: error fetching instance by name: not found", err.Error())
} }
func (s *InstancesTestSuite) TestDeleteInstance() { func (s *InstancesTestSuite) TestDeleteInstance() {
@ -282,7 +282,7 @@ func (s *InstancesTestSuite) TestDeleteInstance() {
s.Require().Nil(err) s.Require().Nil(err)
_, err = s.Store.GetPoolInstanceByName(s.adminCtx, s.Fixtures.Pool.ID, storeInstance.Name) _, err = s.Store.GetPoolInstanceByName(s.adminCtx, s.Fixtures.Pool.ID, storeInstance.Name)
s.Require().Equal("fetching instance: fetching pool instance by name: not found", err.Error()) s.Require().Equal("error fetching instance: error fetching pool instance by name: not found", err.Error())
err = s.Store.DeleteInstance(s.adminCtx, s.Fixtures.Pool.ID, storeInstance.Name) err = s.Store.DeleteInstance(s.adminCtx, s.Fixtures.Pool.ID, storeInstance.Name)
s.Require().Nil(err) s.Require().Nil(err)
@ -296,7 +296,7 @@ func (s *InstancesTestSuite) TestDeleteInstanceByName() {
s.Require().Nil(err) s.Require().Nil(err)
_, err = s.Store.GetPoolInstanceByName(s.adminCtx, s.Fixtures.Pool.ID, storeInstance.Name) _, err = s.Store.GetPoolInstanceByName(s.adminCtx, s.Fixtures.Pool.ID, storeInstance.Name)
s.Require().Equal("fetching instance: fetching pool instance by name: not found", err.Error()) s.Require().Equal("error fetching instance: error fetching pool instance by name: not found", err.Error())
err = s.Store.DeleteInstanceByName(s.adminCtx, storeInstance.Name) err = s.Store.DeleteInstanceByName(s.adminCtx, storeInstance.Name)
s.Require().Nil(err) s.Require().Nil(err)
@ -305,7 +305,7 @@ func (s *InstancesTestSuite) TestDeleteInstanceByName() {
func (s *InstancesTestSuite) TestDeleteInstanceInvalidPoolID() { func (s *InstancesTestSuite) TestDeleteInstanceInvalidPoolID() {
err := s.Store.DeleteInstance(s.adminCtx, "dummy-pool-id", "dummy-instance-name") err := s.Store.DeleteInstance(s.adminCtx, "dummy-pool-id", "dummy-instance-name")
s.Require().Equal("deleting instance: fetching pool: parsing id: invalid request", err.Error()) s.Require().Equal("error deleting instance: error fetching pool: error parsing id: invalid request", err.Error())
} }
func (s *InstancesTestSuite) TestDeleteInstanceDBRecordNotFoundErr() { func (s *InstancesTestSuite) TestDeleteInstanceDBRecordNotFoundErr() {
@ -380,7 +380,7 @@ func (s *InstancesTestSuite) TestDeleteInstanceDBDeleteErr() {
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("deleting instance: mocked delete instance error", err.Error()) s.Require().Equal("error deleting instance: mocked delete instance error", err.Error())
} }
func (s *InstancesTestSuite) TestAddInstanceEvent() { func (s *InstancesTestSuite) TestAddInstanceEvent() {
@ -431,7 +431,7 @@ func (s *InstancesTestSuite) TestAddInstanceEventDBUpdateErr() {
err := s.StoreSQLMocked.AddInstanceEvent(s.adminCtx, instance.Name, params.StatusEvent, params.EventInfo, statusMsg) err := s.StoreSQLMocked.AddInstanceEvent(s.adminCtx, instance.Name, params.StatusEvent, params.EventInfo, statusMsg)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("adding status message: mocked add status message error", err.Error()) s.Require().Equal("error adding status message: mocked add status message error", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -476,7 +476,7 @@ func (s *InstancesTestSuite) TestUpdateInstanceDBUpdateInstanceErr() {
_, err := s.StoreSQLMocked.UpdateInstance(s.adminCtx, instance.Name, s.Fixtures.UpdateInstanceParams) _, err := s.StoreSQLMocked.UpdateInstance(s.adminCtx, instance.Name, s.Fixtures.UpdateInstanceParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("updating instance: mocked update instance error", err.Error()) s.Require().Equal("error updating instance: mocked update instance error", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -522,7 +522,7 @@ func (s *InstancesTestSuite) TestUpdateInstanceDBUpdateAddressErr() {
_, err := s.StoreSQLMocked.UpdateInstance(s.adminCtx, instance.Name, s.Fixtures.UpdateInstanceParams) _, err := s.StoreSQLMocked.UpdateInstance(s.adminCtx, instance.Name, s.Fixtures.UpdateInstanceParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("updating addresses: update addresses mock error", err.Error()) s.Require().Equal("error updating addresses: update addresses mock error", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -536,7 +536,7 @@ func (s *InstancesTestSuite) TestListPoolInstances() {
func (s *InstancesTestSuite) TestListPoolInstancesInvalidPoolID() { func (s *InstancesTestSuite) TestListPoolInstancesInvalidPoolID() {
_, err := s.Store.ListPoolInstances(s.adminCtx, "dummy-pool-id") _, err := s.Store.ListPoolInstances(s.adminCtx, "dummy-pool-id")
s.Require().Equal("parsing id: invalid request", err.Error()) s.Require().Equal("error parsing id: invalid request", err.Error())
} }
func (s *InstancesTestSuite) TestListAllInstances() { func (s *InstancesTestSuite) TestListAllInstances() {
@ -555,7 +555,7 @@ func (s *InstancesTestSuite) TestListAllInstancesDBFetchErr() {
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching instances: fetch instances mock error", err.Error()) s.Require().Equal("error fetching instances: fetch instances mock error", err.Error())
} }
func (s *InstancesTestSuite) TestPoolInstanceCount() { func (s *InstancesTestSuite) TestPoolInstanceCount() {
@ -568,7 +568,7 @@ func (s *InstancesTestSuite) TestPoolInstanceCount() {
func (s *InstancesTestSuite) TestPoolInstanceCountInvalidPoolID() { func (s *InstancesTestSuite) TestPoolInstanceCountInvalidPoolID() {
_, err := s.Store.PoolInstanceCount(s.adminCtx, "dummy-pool-id") _, err := s.Store.PoolInstanceCount(s.adminCtx, "dummy-pool-id")
s.Require().Equal("fetching pool: parsing id: invalid request", err.Error()) s.Require().Equal("error fetching pool: error parsing id: invalid request", err.Error())
} }
func (s *InstancesTestSuite) TestPoolInstanceCountDBCountErr() { func (s *InstancesTestSuite) TestPoolInstanceCountDBCountErr() {
@ -587,7 +587,7 @@ func (s *InstancesTestSuite) TestPoolInstanceCountDBCountErr() {
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching instance count: count mock error", err.Error()) s.Require().Equal("error fetching instance count: count mock error", err.Error())
} }
func TestInstTestSuite(t *testing.T) { func TestInstTestSuite(t *testing.T) {

View file

@ -17,10 +17,11 @@ package sql
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"errors"
"fmt"
"log/slog" "log/slog"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/pkg/errors"
"gorm.io/gorm" "gorm.io/gorm"
"gorm.io/gorm/clause" "gorm.io/gorm/clause"
@ -35,7 +36,7 @@ func sqlWorkflowJobToParamsJob(job WorkflowJob) (params.Job, error) {
labels := []string{} labels := []string{}
if job.Labels != nil { if job.Labels != nil {
if err := json.Unmarshal(job.Labels, &labels); err != nil { if err := json.Unmarshal(job.Labels, &labels); err != nil {
return params.Job{}, errors.Wrap(err, "unmarshaling labels") return params.Job{}, fmt.Errorf("error unmarshaling labels: %w", err)
} }
} }
@ -73,7 +74,7 @@ func sqlWorkflowJobToParamsJob(job WorkflowJob) (params.Job, error) {
func (s *sqlDatabase) paramsJobToWorkflowJob(ctx context.Context, job params.Job) (WorkflowJob, error) { func (s *sqlDatabase) paramsJobToWorkflowJob(ctx context.Context, job params.Job) (WorkflowJob, error) {
asJSON, err := json.Marshal(job.Labels) asJSON, err := json.Marshal(job.Labels)
if err != nil { if err != nil {
return WorkflowJob{}, errors.Wrap(err, "marshaling labels") return WorkflowJob{}, fmt.Errorf("error marshaling labels: %w", err)
} }
workflofJob := WorkflowJob{ workflofJob := WorkflowJob{
@ -118,11 +119,11 @@ func (s *sqlDatabase) DeleteJob(_ context.Context, jobID int64) (err error) {
if errors.Is(q.Error, gorm.ErrRecordNotFound) { if errors.Is(q.Error, gorm.ErrRecordNotFound) {
return nil return nil
} }
return errors.Wrap(q.Error, "fetching job") return fmt.Errorf("error fetching job: %w", q.Error)
} }
removedJob, err := sqlWorkflowJobToParamsJob(workflowJob) removedJob, err := sqlWorkflowJobToParamsJob(workflowJob)
if err != nil { if err != nil {
return errors.Wrap(err, "converting job") return fmt.Errorf("error converting job: %w", err)
} }
defer func() { defer func() {
@ -137,7 +138,7 @@ func (s *sqlDatabase) DeleteJob(_ context.Context, jobID int64) (err error) {
if errors.Is(q.Error, gorm.ErrRecordNotFound) { if errors.Is(q.Error, gorm.ErrRecordNotFound) {
return nil return nil
} }
return errors.Wrap(q.Error, "deleting job") return fmt.Errorf("error deleting job: %w", q.Error)
} }
return nil return nil
} }
@ -145,7 +146,7 @@ func (s *sqlDatabase) DeleteJob(_ context.Context, jobID int64) (err error) {
func (s *sqlDatabase) LockJob(_ context.Context, jobID int64, entityID string) error { func (s *sqlDatabase) LockJob(_ context.Context, jobID int64, entityID string) error {
entityUUID, err := uuid.Parse(entityID) entityUUID, err := uuid.Parse(entityID)
if err != nil { if err != nil {
return errors.Wrap(err, "parsing entity id") return fmt.Errorf("error parsing entity id: %w", err)
} }
var workflowJob WorkflowJob var workflowJob WorkflowJob
q := s.conn.Preload("Instance").Where("id = ?", jobID).First(&workflowJob) q := s.conn.Preload("Instance").Where("id = ?", jobID).First(&workflowJob)
@ -154,7 +155,7 @@ func (s *sqlDatabase) LockJob(_ context.Context, jobID int64, entityID string) e
if errors.Is(q.Error, gorm.ErrRecordNotFound) { if errors.Is(q.Error, gorm.ErrRecordNotFound) {
return runnerErrors.ErrNotFound return runnerErrors.ErrNotFound
} }
return errors.Wrap(q.Error, "fetching job") return fmt.Errorf("error fetching job: %w", q.Error)
} }
if workflowJob.LockedBy.String() == entityID { if workflowJob.LockedBy.String() == entityID {
@ -169,12 +170,12 @@ func (s *sqlDatabase) LockJob(_ context.Context, jobID int64, entityID string) e
workflowJob.LockedBy = entityUUID workflowJob.LockedBy = entityUUID
if err := s.conn.Save(&workflowJob).Error; err != nil { if err := s.conn.Save(&workflowJob).Error; err != nil {
return errors.Wrap(err, "saving job") return fmt.Errorf("error saving job: %w", err)
} }
asParams, err := sqlWorkflowJobToParamsJob(workflowJob) asParams, err := sqlWorkflowJobToParamsJob(workflowJob)
if err != nil { if err != nil {
return errors.Wrap(err, "converting job") return fmt.Errorf("error converting job: %w", err)
} }
s.sendNotify(common.JobEntityType, common.UpdateOperation, asParams) s.sendNotify(common.JobEntityType, common.UpdateOperation, asParams)
@ -189,7 +190,7 @@ func (s *sqlDatabase) BreakLockJobIsQueued(_ context.Context, jobID int64) (err
if errors.Is(q.Error, gorm.ErrRecordNotFound) { if errors.Is(q.Error, gorm.ErrRecordNotFound) {
return nil return nil
} }
return errors.Wrap(q.Error, "fetching job") return fmt.Errorf("error fetching job: %w", q.Error)
} }
if workflowJob.LockedBy == uuid.Nil { if workflowJob.LockedBy == uuid.Nil {
@ -199,11 +200,11 @@ func (s *sqlDatabase) BreakLockJobIsQueued(_ context.Context, jobID int64) (err
workflowJob.LockedBy = uuid.Nil workflowJob.LockedBy = uuid.Nil
if err := s.conn.Save(&workflowJob).Error; err != nil { if err := s.conn.Save(&workflowJob).Error; err != nil {
return errors.Wrap(err, "saving job") return fmt.Errorf("error saving job: %w", err)
} }
asParams, err := sqlWorkflowJobToParamsJob(workflowJob) asParams, err := sqlWorkflowJobToParamsJob(workflowJob)
if err != nil { if err != nil {
return errors.Wrap(err, "converting job") return fmt.Errorf("error converting job: %w", err)
} }
s.sendNotify(common.JobEntityType, common.UpdateOperation, asParams) s.sendNotify(common.JobEntityType, common.UpdateOperation, asParams)
return nil return nil
@ -217,7 +218,7 @@ func (s *sqlDatabase) UnlockJob(_ context.Context, jobID int64, entityID string)
if errors.Is(q.Error, gorm.ErrRecordNotFound) { if errors.Is(q.Error, gorm.ErrRecordNotFound) {
return runnerErrors.ErrNotFound return runnerErrors.ErrNotFound
} }
return errors.Wrap(q.Error, "fetching job") return fmt.Errorf("error fetching job: %w", q.Error)
} }
if workflowJob.LockedBy == uuid.Nil { if workflowJob.LockedBy == uuid.Nil {
@ -231,12 +232,12 @@ func (s *sqlDatabase) UnlockJob(_ context.Context, jobID int64, entityID string)
workflowJob.LockedBy = uuid.Nil workflowJob.LockedBy = uuid.Nil
if err := s.conn.Save(&workflowJob).Error; err != nil { if err := s.conn.Save(&workflowJob).Error; err != nil {
return errors.Wrap(err, "saving job") return fmt.Errorf("error saving job: %w", err)
} }
asParams, err := sqlWorkflowJobToParamsJob(workflowJob) asParams, err := sqlWorkflowJobToParamsJob(workflowJob)
if err != nil { if err != nil {
return errors.Wrap(err, "converting job") return fmt.Errorf("error converting job: %w", err)
} }
s.sendNotify(common.JobEntityType, common.UpdateOperation, asParams) s.sendNotify(common.JobEntityType, common.UpdateOperation, asParams)
return nil return nil
@ -256,7 +257,7 @@ func (s *sqlDatabase) CreateOrUpdateJob(ctx context.Context, job params.Job) (pa
if q.Error != nil { if q.Error != nil {
if !errors.Is(q.Error, gorm.ErrRecordNotFound) { if !errors.Is(q.Error, gorm.ErrRecordNotFound) {
return params.Job{}, errors.Wrap(q.Error, "fetching job") return params.Job{}, fmt.Errorf("error fetching job: %w", q.Error)
} }
} }
var operation common.OperationType var operation common.OperationType
@ -302,23 +303,23 @@ func (s *sqlDatabase) CreateOrUpdateJob(ctx context.Context, job params.Job) (pa
workflowJob.EnterpriseID = job.EnterpriseID workflowJob.EnterpriseID = job.EnterpriseID
} }
if err := s.conn.Save(&workflowJob).Error; err != nil { if err := s.conn.Save(&workflowJob).Error; err != nil {
return params.Job{}, errors.Wrap(err, "saving job") return params.Job{}, fmt.Errorf("error saving job: %w", err)
} }
} else { } else {
operation = common.CreateOperation operation = common.CreateOperation
workflowJob, err = s.paramsJobToWorkflowJob(ctx, job) workflowJob, err = s.paramsJobToWorkflowJob(ctx, job)
if err != nil { if err != nil {
return params.Job{}, errors.Wrap(err, "converting job") return params.Job{}, fmt.Errorf("error converting job: %w", err)
} }
if err := s.conn.Create(&workflowJob).Error; err != nil { if err := s.conn.Create(&workflowJob).Error; err != nil {
return params.Job{}, errors.Wrap(err, "creating job") return params.Job{}, fmt.Errorf("error creating job: %w", err)
} }
} }
asParams, err := sqlWorkflowJobToParamsJob(workflowJob) asParams, err := sqlWorkflowJobToParamsJob(workflowJob)
if err != nil { if err != nil {
return params.Job{}, errors.Wrap(err, "converting job") return params.Job{}, fmt.Errorf("error converting job: %w", err)
} }
s.sendNotify(common.JobEntityType, operation, asParams) s.sendNotify(common.JobEntityType, operation, asParams)
@ -338,7 +339,7 @@ func (s *sqlDatabase) ListJobsByStatus(_ context.Context, status params.JobStatu
for idx, job := range jobs { for idx, job := range jobs {
jobParam, err := sqlWorkflowJobToParamsJob(job) jobParam, err := sqlWorkflowJobToParamsJob(job)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "converting job") return nil, fmt.Errorf("error converting job: %w", err)
} }
ret[idx] = jobParam ret[idx] = jobParam
} }
@ -379,7 +380,7 @@ func (s *sqlDatabase) ListEntityJobsByStatus(_ context.Context, entityType param
for idx, job := range jobs { for idx, job := range jobs {
jobParam, err := sqlWorkflowJobToParamsJob(job) jobParam, err := sqlWorkflowJobToParamsJob(job)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "converting job") return nil, fmt.Errorf("error converting job: %w", err)
} }
ret[idx] = jobParam ret[idx] = jobParam
} }
@ -401,7 +402,7 @@ func (s *sqlDatabase) ListAllJobs(_ context.Context) ([]params.Job, error) {
for idx, job := range jobs { for idx, job := range jobs {
jobParam, err := sqlWorkflowJobToParamsJob(job) jobParam, err := sqlWorkflowJobToParamsJob(job)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "converting job") return nil, fmt.Errorf("error converting job: %w", err)
} }
ret[idx] = jobParam ret[idx] = jobParam
} }

View file

@ -15,10 +15,10 @@
package sql package sql
import ( import (
"fmt"
"time" "time"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/pkg/errors"
"gorm.io/datatypes" "gorm.io/datatypes"
"gorm.io/gorm" "gorm.io/gorm"
@ -40,7 +40,7 @@ func (b *Base) BeforeCreate(_ *gorm.DB) error {
} }
newID, err := uuid.NewRandom() newID, err := uuid.NewRandom()
if err != nil { if err != nil {
return errors.Wrap(err, "generating id") return fmt.Errorf("error generating id: %w", err)
} }
b.ID = newID b.ID = newID
return nil return nil

View file

@ -16,11 +16,11 @@ package sql
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"log/slog" "log/slog"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/pkg/errors"
"gorm.io/gorm" "gorm.io/gorm"
runnerErrors "github.com/cloudbase/garm-provider-common/errors" runnerErrors "github.com/cloudbase/garm-provider-common/errors"
@ -35,7 +35,7 @@ func (s *sqlDatabase) CreateOrganization(ctx context.Context, name string, crede
} }
secret, err := util.Seal([]byte(webhookSecret), []byte(s.cfg.Passphrase)) secret, err := util.Seal([]byte(webhookSecret), []byte(s.cfg.Passphrase))
if err != nil { if err != nil {
return params.Organization{}, errors.Wrap(err, "encoding secret") return params.Organization{}, fmt.Errorf("error encoding secret: %w", err)
} }
defer func() { defer func() {
@ -56,23 +56,23 @@ func (s *sqlDatabase) CreateOrganization(ctx context.Context, name string, crede
case params.GiteaEndpointType: case params.GiteaEndpointType:
newOrg.GiteaCredentialsID = &credentials.ID newOrg.GiteaCredentialsID = &credentials.ID
default: default:
return errors.Wrap(runnerErrors.ErrBadRequest, "unsupported credentials type") return fmt.Errorf("unsupported credentials type: %w", runnerErrors.ErrBadRequest)
} }
newOrg.EndpointName = &credentials.Endpoint.Name newOrg.EndpointName = &credentials.Endpoint.Name
q := tx.Create(&newOrg) q := tx.Create(&newOrg)
if q.Error != nil { if q.Error != nil {
return errors.Wrap(q.Error, "creating org") return fmt.Errorf("error creating org: %w", q.Error)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return params.Organization{}, errors.Wrap(err, "creating org") return params.Organization{}, fmt.Errorf("error creating org: %w", err)
} }
ret, err := s.GetOrganizationByID(ctx, newOrg.ID.String()) ret, err := s.GetOrganizationByID(ctx, newOrg.ID.String())
if err != nil { if err != nil {
return params.Organization{}, errors.Wrap(err, "creating org") return params.Organization{}, fmt.Errorf("error creating org: %w", err)
} }
return ret, nil return ret, nil
@ -81,12 +81,12 @@ func (s *sqlDatabase) CreateOrganization(ctx context.Context, name string, crede
func (s *sqlDatabase) GetOrganization(ctx context.Context, name, endpointName string) (params.Organization, error) { func (s *sqlDatabase) GetOrganization(ctx context.Context, name, endpointName string) (params.Organization, error) {
org, err := s.getOrg(ctx, name, endpointName) org, err := s.getOrg(ctx, name, endpointName)
if err != nil { if err != nil {
return params.Organization{}, errors.Wrap(err, "fetching org") return params.Organization{}, fmt.Errorf("error fetching org: %w", err)
} }
param, err := s.sqlToCommonOrganization(org, true) param, err := s.sqlToCommonOrganization(org, true)
if err != nil { if err != nil {
return params.Organization{}, errors.Wrap(err, "fetching org") return params.Organization{}, fmt.Errorf("error fetching org: %w", err)
} }
return param, nil return param, nil
@ -110,7 +110,7 @@ func (s *sqlDatabase) ListOrganizations(_ context.Context, filter params.Organiz
} }
q = q.Find(&orgs) q = q.Find(&orgs)
if q.Error != nil { if q.Error != nil {
return []params.Organization{}, errors.Wrap(q.Error, "fetching org from database") return []params.Organization{}, fmt.Errorf("error fetching org from database: %w", q.Error)
} }
ret := make([]params.Organization, len(orgs)) ret := make([]params.Organization, len(orgs))
@ -118,7 +118,7 @@ func (s *sqlDatabase) ListOrganizations(_ context.Context, filter params.Organiz
var err error var err error
ret[idx], err = s.sqlToCommonOrganization(val, true) ret[idx], err = s.sqlToCommonOrganization(val, true)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching org") return nil, fmt.Errorf("error fetching org: %w", err)
} }
} }
@ -128,7 +128,7 @@ func (s *sqlDatabase) ListOrganizations(_ context.Context, filter params.Organiz
func (s *sqlDatabase) DeleteOrganization(ctx context.Context, orgID string) (err error) { func (s *sqlDatabase) DeleteOrganization(ctx context.Context, orgID string) (err error) {
org, err := s.getOrgByID(ctx, s.conn, orgID, "Endpoint", "Credentials", "Credentials.Endpoint", "GiteaCredentials", "GiteaCredentials.Endpoint") org, err := s.getOrgByID(ctx, s.conn, orgID, "Endpoint", "Credentials", "Credentials.Endpoint", "GiteaCredentials", "GiteaCredentials.Endpoint")
if err != nil { if err != nil {
return errors.Wrap(err, "fetching org") return fmt.Errorf("error fetching org: %w", err)
} }
defer func(org Organization) { defer func(org Organization) {
@ -144,7 +144,7 @@ func (s *sqlDatabase) DeleteOrganization(ctx context.Context, orgID string) (err
q := s.conn.Unscoped().Delete(&org) q := s.conn.Unscoped().Delete(&org)
if q.Error != nil && !errors.Is(q.Error, gorm.ErrRecordNotFound) { if q.Error != nil && !errors.Is(q.Error, gorm.ErrRecordNotFound) {
return errors.Wrap(q.Error, "deleting org") return fmt.Errorf("error deleting org: %w", q.Error)
} }
return nil return nil
@ -162,23 +162,23 @@ func (s *sqlDatabase) UpdateOrganization(ctx context.Context, orgID string, para
var err error var err error
org, err = s.getOrgByID(ctx, tx, orgID) org, err = s.getOrgByID(ctx, tx, orgID)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching org") return fmt.Errorf("error fetching org: %w", err)
} }
if org.EndpointName == nil { if org.EndpointName == nil {
return errors.Wrap(runnerErrors.ErrUnprocessable, "org has no endpoint") return fmt.Errorf("error org has no endpoint: %w", runnerErrors.ErrUnprocessable)
} }
if param.CredentialsName != "" { if param.CredentialsName != "" {
creds, err = s.getGithubCredentialsByName(ctx, tx, param.CredentialsName, false) creds, err = s.getGithubCredentialsByName(ctx, tx, param.CredentialsName, false)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching credentials") return fmt.Errorf("error fetching credentials: %w", err)
} }
if creds.EndpointName == nil { if creds.EndpointName == nil {
return errors.Wrap(runnerErrors.ErrUnprocessable, "credentials have no endpoint") return fmt.Errorf("error credentials have no endpoint: %w", runnerErrors.ErrUnprocessable)
} }
if *creds.EndpointName != *org.EndpointName { if *creds.EndpointName != *org.EndpointName {
return errors.Wrap(runnerErrors.ErrBadRequest, "endpoint mismatch") return fmt.Errorf("error endpoint mismatch: %w", runnerErrors.ErrBadRequest)
} }
org.CredentialsID = &creds.ID org.CredentialsID = &creds.ID
} }
@ -197,22 +197,22 @@ func (s *sqlDatabase) UpdateOrganization(ctx context.Context, orgID string, para
q := tx.Save(&org) q := tx.Save(&org)
if q.Error != nil { if q.Error != nil {
return errors.Wrap(q.Error, "saving org") return fmt.Errorf("error saving org: %w", q.Error)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return params.Organization{}, errors.Wrap(err, "saving org") return params.Organization{}, fmt.Errorf("error saving org: %w", err)
} }
org, err = s.getOrgByID(ctx, s.conn, orgID, "Endpoint", "Credentials", "Credentials.Endpoint", "GiteaCredentials", "GiteaCredentials.Endpoint") org, err = s.getOrgByID(ctx, s.conn, orgID, "Endpoint", "Credentials", "Credentials.Endpoint", "GiteaCredentials", "GiteaCredentials.Endpoint")
if err != nil { if err != nil {
return params.Organization{}, errors.Wrap(err, "updating enterprise") return params.Organization{}, fmt.Errorf("error updating enterprise: %w", err)
} }
paramOrg, err = s.sqlToCommonOrganization(org, true) paramOrg, err = s.sqlToCommonOrganization(org, true)
if err != nil { if err != nil {
return params.Organization{}, errors.Wrap(err, "saving org") return params.Organization{}, fmt.Errorf("error saving org: %w", err)
} }
return paramOrg, nil return paramOrg, nil
} }
@ -229,12 +229,12 @@ func (s *sqlDatabase) GetOrganizationByID(ctx context.Context, orgID string) (pa
} }
org, err := s.getOrgByID(ctx, s.conn, orgID, preloadList...) org, err := s.getOrgByID(ctx, s.conn, orgID, preloadList...)
if err != nil { if err != nil {
return params.Organization{}, errors.Wrap(err, "fetching org") return params.Organization{}, fmt.Errorf("error fetching org: %w", err)
} }
param, err := s.sqlToCommonOrganization(org, true) param, err := s.sqlToCommonOrganization(org, true)
if err != nil { if err != nil {
return params.Organization{}, errors.Wrap(err, "fetching org") return params.Organization{}, fmt.Errorf("error fetching org: %w", err)
} }
return param, nil return param, nil
} }
@ -242,7 +242,7 @@ func (s *sqlDatabase) GetOrganizationByID(ctx context.Context, orgID string) (pa
func (s *sqlDatabase) getOrgByID(_ context.Context, db *gorm.DB, id string, preload ...string) (Organization, error) { func (s *sqlDatabase) getOrgByID(_ context.Context, db *gorm.DB, id string, preload ...string) (Organization, error) {
u, err := uuid.Parse(id) u, err := uuid.Parse(id)
if err != nil { if err != nil {
return Organization{}, errors.Wrap(runnerErrors.ErrBadRequest, "parsing id") return Organization{}, fmt.Errorf("error parsing id: %w", runnerErrors.ErrBadRequest)
} }
var org Organization var org Organization
@ -258,7 +258,7 @@ func (s *sqlDatabase) getOrgByID(_ context.Context, db *gorm.DB, id string, prel
if errors.Is(q.Error, gorm.ErrRecordNotFound) { if errors.Is(q.Error, gorm.ErrRecordNotFound) {
return Organization{}, runnerErrors.ErrNotFound return Organization{}, runnerErrors.ErrNotFound
} }
return Organization{}, errors.Wrap(q.Error, "fetching org from database") return Organization{}, fmt.Errorf("error fetching org from database: %w", q.Error)
} }
return org, nil return org, nil
} }
@ -277,7 +277,7 @@ func (s *sqlDatabase) getOrg(_ context.Context, name, endpointName string) (Orga
if errors.Is(q.Error, gorm.ErrRecordNotFound) { if errors.Is(q.Error, gorm.ErrRecordNotFound) {
return Organization{}, runnerErrors.ErrNotFound return Organization{}, runnerErrors.ErrNotFound
} }
return Organization{}, errors.Wrap(q.Error, "fetching org from database") return Organization{}, fmt.Errorf("error fetching org from database: %w", q.Error)
} }
return org, nil return org, nil
} }

View file

@ -251,7 +251,7 @@ func (s *OrgTestSuite) TestCreateOrganizationInvalidForgeType() {
s.Fixtures.CreateOrgParams.WebhookSecret, s.Fixtures.CreateOrgParams.WebhookSecret,
params.PoolBalancerTypeRoundRobin) params.PoolBalancerTypeRoundRobin)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("creating org: unsupported credentials type: invalid request", err.Error()) s.Require().Equal("error creating org: unsupported credentials type: invalid request", err.Error())
} }
func (s *OrgTestSuite) TestCreateOrganizationInvalidDBPassphrase() { func (s *OrgTestSuite) TestCreateOrganizationInvalidDBPassphrase() {
@ -275,7 +275,7 @@ func (s *OrgTestSuite) TestCreateOrganizationInvalidDBPassphrase() {
params.PoolBalancerTypeRoundRobin) params.PoolBalancerTypeRoundRobin)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("encoding secret: invalid passphrase length (expected length 32 characters)", err.Error()) s.Require().Equal("error encoding secret: invalid passphrase length (expected length 32 characters)", err.Error())
} }
func (s *OrgTestSuite) TestCreateOrganizationDBCreateErr() { func (s *OrgTestSuite) TestCreateOrganizationDBCreateErr() {
@ -293,7 +293,7 @@ func (s *OrgTestSuite) TestCreateOrganizationDBCreateErr() {
params.PoolBalancerTypeRoundRobin) params.PoolBalancerTypeRoundRobin)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("creating org: creating org: creating org mock error", err.Error()) s.Require().Equal("error creating org: error creating org: creating org mock error", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -316,7 +316,7 @@ func (s *OrgTestSuite) TestGetOrganizationNotFound() {
_, err := s.Store.GetOrganization(s.adminCtx, "dummy-name", "github.com") _, err := s.Store.GetOrganization(s.adminCtx, "dummy-name", "github.com")
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching org: not found", err.Error()) s.Require().Equal("error fetching org: not found", err.Error())
} }
func (s *OrgTestSuite) TestGetOrganizationDBDecryptingErr() { func (s *OrgTestSuite) TestGetOrganizationDBDecryptingErr() {
@ -328,7 +328,7 @@ func (s *OrgTestSuite) TestGetOrganizationDBDecryptingErr() {
_, err := s.StoreSQLMocked.GetOrganization(s.adminCtx, s.Fixtures.Orgs[0].Name, s.Fixtures.Orgs[0].Endpoint.Name) _, err := s.StoreSQLMocked.GetOrganization(s.adminCtx, s.Fixtures.Orgs[0].Name, s.Fixtures.Orgs[0].Endpoint.Name)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching org: missing secret", err.Error()) s.Require().Equal("error fetching org: missing secret", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -404,7 +404,7 @@ func (s *OrgTestSuite) TestListOrganizationsDBFetchErr() {
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching org from database: fetching user from database mock error", err.Error()) s.Require().Equal("error fetching org from database: fetching user from database mock error", err.Error())
} }
func (s *OrgTestSuite) TestDeleteOrganization() { func (s *OrgTestSuite) TestDeleteOrganization() {
@ -413,14 +413,14 @@ func (s *OrgTestSuite) TestDeleteOrganization() {
s.Require().Nil(err) s.Require().Nil(err)
_, err = s.Store.GetOrganizationByID(s.adminCtx, s.Fixtures.Orgs[0].ID) _, err = s.Store.GetOrganizationByID(s.adminCtx, s.Fixtures.Orgs[0].ID)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching org: not found", err.Error()) s.Require().Equal("error fetching org: not found", err.Error())
} }
func (s *OrgTestSuite) TestDeleteOrganizationInvalidOrgID() { func (s *OrgTestSuite) TestDeleteOrganizationInvalidOrgID() {
err := s.Store.DeleteOrganization(s.adminCtx, "dummy-org-id") err := s.Store.DeleteOrganization(s.adminCtx, "dummy-org-id")
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching org: parsing id: invalid request", err.Error()) s.Require().Equal("error fetching org: error parsing id: invalid request", err.Error())
} }
func (s *OrgTestSuite) TestDeleteOrganizationDBDeleteErr() { func (s *OrgTestSuite) TestDeleteOrganizationDBDeleteErr() {
@ -439,7 +439,7 @@ func (s *OrgTestSuite) TestDeleteOrganizationDBDeleteErr() {
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("deleting org: mocked delete org error", err.Error()) s.Require().Equal("error deleting org: mocked delete org error", err.Error())
} }
func (s *OrgTestSuite) TestUpdateOrganization() { func (s *OrgTestSuite) TestUpdateOrganization() {
@ -454,7 +454,7 @@ func (s *OrgTestSuite) TestUpdateOrganizationInvalidOrgID() {
_, err := s.Store.UpdateOrganization(s.adminCtx, "dummy-org-id", s.Fixtures.UpdateRepoParams) _, err := s.Store.UpdateOrganization(s.adminCtx, "dummy-org-id", s.Fixtures.UpdateRepoParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("saving org: fetching org: parsing id: invalid request", err.Error()) s.Require().Equal("error saving org: error fetching org: error parsing id: invalid request", err.Error())
} }
func (s *OrgTestSuite) TestUpdateOrganizationDBEncryptErr() { func (s *OrgTestSuite) TestUpdateOrganizationDBEncryptErr() {
@ -479,7 +479,7 @@ func (s *OrgTestSuite) TestUpdateOrganizationDBEncryptErr() {
_, err := s.StoreSQLMocked.UpdateOrganization(s.adminCtx, s.Fixtures.Orgs[0].ID, s.Fixtures.UpdateRepoParams) _, err := s.StoreSQLMocked.UpdateOrganization(s.adminCtx, s.Fixtures.Orgs[0].ID, s.Fixtures.UpdateRepoParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("saving org: saving org: failed to encrypt string: invalid passphrase length (expected length 32 characters)", err.Error()) s.Require().Equal("error saving org: saving org: failed to encrypt string: invalid passphrase length (expected length 32 characters)", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -507,7 +507,7 @@ func (s *OrgTestSuite) TestUpdateOrganizationDBSaveErr() {
_, err := s.StoreSQLMocked.UpdateOrganization(s.adminCtx, s.Fixtures.Orgs[0].ID, s.Fixtures.UpdateRepoParams) _, err := s.StoreSQLMocked.UpdateOrganization(s.adminCtx, s.Fixtures.Orgs[0].ID, s.Fixtures.UpdateRepoParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("saving org: saving org: saving org mock error", err.Error()) s.Require().Equal("error saving org: error saving org: saving org mock error", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -535,7 +535,7 @@ func (s *OrgTestSuite) TestUpdateOrganizationDBDecryptingErr() {
_, err := s.StoreSQLMocked.UpdateOrganization(s.adminCtx, s.Fixtures.Orgs[0].ID, s.Fixtures.UpdateRepoParams) _, err := s.StoreSQLMocked.UpdateOrganization(s.adminCtx, s.Fixtures.Orgs[0].ID, s.Fixtures.UpdateRepoParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("saving org: saving org: failed to encrypt string: invalid passphrase length (expected length 32 characters)", err.Error()) s.Require().Equal("error saving org: saving org: failed to encrypt string: invalid passphrase length (expected length 32 characters)", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -550,7 +550,7 @@ func (s *OrgTestSuite) TestGetOrganizationByIDInvalidOrgID() {
_, err := s.Store.GetOrganizationByID(s.adminCtx, "dummy-org-id") _, err := s.Store.GetOrganizationByID(s.adminCtx, "dummy-org-id")
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching org: parsing id: invalid request", err.Error()) s.Require().Equal("error fetching org: error parsing id: invalid request", err.Error())
} }
func (s *OrgTestSuite) TestGetOrganizationByIDDBDecryptingErr() { func (s *OrgTestSuite) TestGetOrganizationByIDDBDecryptingErr() {
@ -571,7 +571,7 @@ func (s *OrgTestSuite) TestGetOrganizationByIDDBDecryptingErr() {
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching org: missing secret", err.Error()) s.Require().Equal("error fetching org: missing secret", err.Error())
} }
func (s *OrgTestSuite) TestCreateOrganizationPool() { func (s *OrgTestSuite) TestCreateOrganizationPool() {
@ -610,7 +610,7 @@ func (s *OrgTestSuite) TestCreateOrganizationPoolInvalidOrgID() {
_, err := s.Store.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams) _, err := s.Store.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("parsing id: invalid request", err.Error()) s.Require().Equal("error parsing id: invalid request", err.Error())
} }
func (s *OrgTestSuite) TestCreateOrganizationPoolDBFetchTagErr() { func (s *OrgTestSuite) TestCreateOrganizationPoolDBFetchTagErr() {
@ -628,7 +628,7 @@ func (s *OrgTestSuite) TestCreateOrganizationPoolDBFetchTagErr() {
_, err = s.StoreSQLMocked.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams) _, err = s.StoreSQLMocked.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("creating tag: fetching tag from database: mocked fetching tag error", err.Error()) s.Require().Equal("error creating tag: error fetching tag from database: mocked fetching tag error", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -656,7 +656,7 @@ func (s *OrgTestSuite) TestCreateOrganizationPoolDBAddingPoolErr() {
_, err = s.StoreSQLMocked.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams) _, err = s.StoreSQLMocked.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("creating pool: mocked adding pool error", err.Error()) s.Require().Equal("error creating pool: mocked adding pool error", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -687,7 +687,7 @@ func (s *OrgTestSuite) TestCreateOrganizationPoolDBSaveTagErr() {
_, err = s.StoreSQLMocked.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams) _, err = s.StoreSQLMocked.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("associating tags: mocked saving tag error", err.Error()) s.Require().Equal("error associating tags: mocked saving tag error", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -728,7 +728,7 @@ func (s *OrgTestSuite) TestCreateOrganizationPoolDBFetchPoolErr() {
_, err = s.StoreSQLMocked.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams) _, err = s.StoreSQLMocked.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching pool: not found", err.Error()) s.Require().Equal("error fetching pool: not found", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -758,7 +758,7 @@ func (s *OrgTestSuite) TestListOrgPoolsInvalidOrgID() {
_, err := s.Store.ListEntityPools(s.adminCtx, entity) _, err := s.Store.ListEntityPools(s.adminCtx, entity)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching pools: parsing id: invalid request", err.Error()) s.Require().Equal("error fetching pools: error parsing id: invalid request", err.Error())
} }
func (s *OrgTestSuite) TestGetOrganizationPool() { func (s *OrgTestSuite) TestGetOrganizationPool() {
@ -783,7 +783,7 @@ func (s *OrgTestSuite) TestGetOrganizationPoolInvalidOrgID() {
_, err := s.Store.GetEntityPool(s.adminCtx, entity, "dummy-pool-id") _, err := s.Store.GetEntityPool(s.adminCtx, entity, "dummy-pool-id")
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching pool: parsing id: invalid request", err.Error()) s.Require().Equal("fetching pool: error parsing id: invalid request", err.Error())
} }
func (s *OrgTestSuite) TestDeleteOrganizationPool() { func (s *OrgTestSuite) TestDeleteOrganizationPool() {
@ -798,7 +798,7 @@ func (s *OrgTestSuite) TestDeleteOrganizationPool() {
s.Require().Nil(err) s.Require().Nil(err)
_, err = s.Store.GetEntityPool(s.adminCtx, entity, pool.ID) _, err = s.Store.GetEntityPool(s.adminCtx, entity, pool.ID)
s.Require().Equal("fetching pool: finding pool: not found", err.Error()) s.Require().Equal("fetching pool: error finding pool: not found", err.Error())
} }
func (s *OrgTestSuite) TestDeleteOrganizationPoolInvalidOrgID() { func (s *OrgTestSuite) TestDeleteOrganizationPoolInvalidOrgID() {
@ -809,7 +809,7 @@ func (s *OrgTestSuite) TestDeleteOrganizationPoolInvalidOrgID() {
err := s.Store.DeleteEntityPool(s.adminCtx, entity, "dummy-pool-id") err := s.Store.DeleteEntityPool(s.adminCtx, entity, "dummy-pool-id")
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("parsing id: invalid request", err.Error()) s.Require().Equal("error parsing id: invalid request", err.Error())
} }
func (s *OrgTestSuite) TestDeleteOrganizationPoolDBDeleteErr() { func (s *OrgTestSuite) TestDeleteOrganizationPoolDBDeleteErr() {
@ -831,7 +831,7 @@ func (s *OrgTestSuite) TestDeleteOrganizationPoolDBDeleteErr() {
err = s.StoreSQLMocked.DeleteEntityPool(s.adminCtx, entity, pool.ID) err = s.StoreSQLMocked.DeleteEntityPool(s.adminCtx, entity, pool.ID)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("removing pool: mocked deleting pool error", err.Error()) s.Require().Equal("error removing pool: mocked deleting pool error", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -866,7 +866,7 @@ func (s *OrgTestSuite) TestListOrgInstancesInvalidOrgID() {
_, err := s.Store.ListEntityInstances(s.adminCtx, entity) _, err := s.Store.ListEntityInstances(s.adminCtx, entity)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching entity: parsing id: invalid request", err.Error()) s.Require().Equal("error fetching entity: error parsing id: invalid request", err.Error())
} }
func (s *OrgTestSuite) TestUpdateOrganizationPool() { func (s *OrgTestSuite) TestUpdateOrganizationPool() {
@ -916,7 +916,7 @@ func (s *OrgTestSuite) TestUpdateOrganizationPoolInvalidOrgID() {
_, err := s.Store.UpdateEntityPool(s.adminCtx, entity, "dummy-pool-id", s.Fixtures.UpdatePoolParams) _, err := s.Store.UpdateEntityPool(s.adminCtx, entity, "dummy-pool-id", s.Fixtures.UpdatePoolParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching pool: parsing id: invalid request", err.Error()) s.Require().Equal("error fetching pool: error parsing id: invalid request", err.Error())
} }
func TestOrgTestSuite(t *testing.T) { func TestOrgTestSuite(t *testing.T) {

View file

@ -16,10 +16,10 @@ package sql
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/pkg/errors"
"gorm.io/datatypes" "gorm.io/datatypes"
"gorm.io/gorm" "gorm.io/gorm"
@ -48,7 +48,7 @@ func (s *sqlDatabase) ListAllPools(_ context.Context) ([]params.Pool, error) {
Omit("extra_specs"). Omit("extra_specs").
Find(&pools) Find(&pools)
if q.Error != nil { if q.Error != nil {
return nil, errors.Wrap(q.Error, "fetching all pools") return nil, fmt.Errorf("error fetching all pools: %w", q.Error)
} }
ret := make([]params.Pool, len(pools)) ret := make([]params.Pool, len(pools))
@ -56,7 +56,7 @@ func (s *sqlDatabase) ListAllPools(_ context.Context) ([]params.Pool, error) {
for idx, val := range pools { for idx, val := range pools {
ret[idx], err = s.sqlToCommonPool(val) ret[idx], err = s.sqlToCommonPool(val)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "converting pool") return nil, fmt.Errorf("error converting pool: %w", err)
} }
} }
return ret, nil return ret, nil
@ -75,7 +75,7 @@ func (s *sqlDatabase) GetPoolByID(_ context.Context, poolID string) (params.Pool
} }
pool, err := s.getPoolByID(s.conn, poolID, preloadList...) pool, err := s.getPoolByID(s.conn, poolID, preloadList...)
if err != nil { if err != nil {
return params.Pool{}, errors.Wrap(err, "fetching pool by ID") return params.Pool{}, fmt.Errorf("error fetching pool by ID: %w", err)
} }
return s.sqlToCommonPool(pool) return s.sqlToCommonPool(pool)
} }
@ -83,7 +83,7 @@ func (s *sqlDatabase) GetPoolByID(_ context.Context, poolID string) (params.Pool
func (s *sqlDatabase) DeletePoolByID(_ context.Context, poolID string) (err error) { func (s *sqlDatabase) DeletePoolByID(_ context.Context, poolID string) (err error) {
pool, err := s.getPoolByID(s.conn, poolID) pool, err := s.getPoolByID(s.conn, poolID)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching pool by ID") return fmt.Errorf("error fetching pool by ID: %w", err)
} }
defer func() { defer func() {
@ -93,7 +93,7 @@ func (s *sqlDatabase) DeletePoolByID(_ context.Context, poolID string) (err erro
}() }()
if q := s.conn.Unscoped().Delete(&pool); q.Error != nil { if q := s.conn.Unscoped().Delete(&pool); q.Error != nil {
return errors.Wrap(q.Error, "removing pool") return fmt.Errorf("error removing pool: %w", q.Error)
} }
return nil return nil
@ -101,12 +101,12 @@ func (s *sqlDatabase) DeletePoolByID(_ context.Context, poolID string) (err erro
func (s *sqlDatabase) getEntityPool(tx *gorm.DB, entityType params.ForgeEntityType, entityID, poolID string, preload ...string) (Pool, error) { func (s *sqlDatabase) getEntityPool(tx *gorm.DB, entityType params.ForgeEntityType, entityID, poolID string, preload ...string) (Pool, error) {
if entityID == "" { if entityID == "" {
return Pool{}, errors.Wrap(runnerErrors.ErrBadRequest, "missing entity id") return Pool{}, fmt.Errorf("error missing entity id: %w", runnerErrors.ErrBadRequest)
} }
u, err := uuid.Parse(poolID) u, err := uuid.Parse(poolID)
if err != nil { if err != nil {
return Pool{}, errors.Wrap(runnerErrors.ErrBadRequest, "parsing id") return Pool{}, fmt.Errorf("error parsing id: %w", runnerErrors.ErrBadRequest)
} }
var fieldName string var fieldName string
@ -140,9 +140,9 @@ func (s *sqlDatabase) getEntityPool(tx *gorm.DB, entityType params.ForgeEntityTy
First(&pool).Error First(&pool).Error
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return Pool{}, errors.Wrap(runnerErrors.ErrNotFound, "finding pool") return Pool{}, fmt.Errorf("error finding pool: %w", runnerErrors.ErrNotFound)
} }
return Pool{}, errors.Wrap(err, "fetching pool") return Pool{}, fmt.Errorf("error fetching pool: %w", err)
} }
return pool, nil return pool, nil
@ -150,11 +150,11 @@ func (s *sqlDatabase) getEntityPool(tx *gorm.DB, entityType params.ForgeEntityTy
func (s *sqlDatabase) listEntityPools(tx *gorm.DB, entityType params.ForgeEntityType, entityID string, preload ...string) ([]Pool, error) { func (s *sqlDatabase) listEntityPools(tx *gorm.DB, entityType params.ForgeEntityType, entityID string, preload ...string) ([]Pool, error) {
if _, err := uuid.Parse(entityID); err != nil { if _, err := uuid.Parse(entityID); err != nil {
return nil, errors.Wrap(runnerErrors.ErrBadRequest, "parsing id") return nil, fmt.Errorf("error parsing id: %w", runnerErrors.ErrBadRequest)
} }
if err := s.hasGithubEntity(tx, entityType, entityID); err != nil { if err := s.hasGithubEntity(tx, entityType, entityID); err != nil {
return nil, errors.Wrap(err, "checking entity existence") return nil, fmt.Errorf("error checking entity existence: %w", err)
} }
var preloadEntity string var preloadEntity string
@ -191,7 +191,7 @@ func (s *sqlDatabase) listEntityPools(tx *gorm.DB, entityType params.ForgeEntity
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return []Pool{}, nil return []Pool{}, nil
} }
return nil, errors.Wrap(err, "fetching pool") return nil, fmt.Errorf("error fetching pool: %w", err)
} }
return pools, nil return pools, nil
@ -203,7 +203,7 @@ func (s *sqlDatabase) findPoolByTags(id string, poolType params.ForgeEntityType,
} }
u, err := uuid.Parse(id) u, err := uuid.Parse(id)
if err != nil { if err != nil {
return nil, errors.Wrap(runnerErrors.ErrBadRequest, "parsing id") return nil, fmt.Errorf("error parsing id: %w", runnerErrors.ErrBadRequest)
} }
var fieldName string var fieldName string
@ -233,7 +233,7 @@ func (s *sqlDatabase) findPoolByTags(id string, poolType params.ForgeEntityType,
if errors.Is(q.Error, gorm.ErrRecordNotFound) { if errors.Is(q.Error, gorm.ErrRecordNotFound) {
return nil, runnerErrors.ErrNotFound return nil, runnerErrors.ErrNotFound
} }
return nil, errors.Wrap(q.Error, "fetching pool") return nil, fmt.Errorf("error fetching pool: %w", q.Error)
} }
if len(pools) == 0 { if len(pools) == 0 {
@ -244,7 +244,7 @@ func (s *sqlDatabase) findPoolByTags(id string, poolType params.ForgeEntityType,
for idx, val := range pools { for idx, val := range pools {
ret[idx], err = s.sqlToCommonPool(val) ret[idx], err = s.sqlToCommonPool(val)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "converting pool") return nil, fmt.Errorf("error converting pool: %w", err)
} }
} }
@ -261,7 +261,7 @@ func (s *sqlDatabase) FindPoolsMatchingAllTags(_ context.Context, entityType par
if errors.Is(err, runnerErrors.ErrNotFound) { if errors.Is(err, runnerErrors.ErrNotFound) {
return []params.Pool{}, nil return []params.Pool{}, nil
} }
return nil, errors.Wrap(err, "fetching pools") return nil, fmt.Errorf("error fetching pools: %w", err)
} }
return pools, nil return pools, nil
@ -298,7 +298,7 @@ func (s *sqlDatabase) CreateEntityPool(_ context.Context, entity params.ForgeEnt
entityID, err := uuid.Parse(entity.ID) entityID, err := uuid.Parse(entity.ID)
if err != nil { if err != nil {
return params.Pool{}, errors.Wrap(runnerErrors.ErrBadRequest, "parsing id") return params.Pool{}, fmt.Errorf("error parsing id: %w", runnerErrors.ErrBadRequest)
} }
switch entity.EntityType { switch entity.EntityType {
@ -311,26 +311,26 @@ func (s *sqlDatabase) CreateEntityPool(_ context.Context, entity params.ForgeEnt
} }
err = s.conn.Transaction(func(tx *gorm.DB) error { err = s.conn.Transaction(func(tx *gorm.DB) error {
if err := s.hasGithubEntity(tx, entity.EntityType, entity.ID); err != nil { if err := s.hasGithubEntity(tx, entity.EntityType, entity.ID); err != nil {
return errors.Wrap(err, "checking entity existence") return fmt.Errorf("error checking entity existence: %w", err)
} }
tags := []Tag{} tags := []Tag{}
for _, val := range param.Tags { for _, val := range param.Tags {
t, err := s.getOrCreateTag(tx, val) t, err := s.getOrCreateTag(tx, val)
if err != nil { if err != nil {
return errors.Wrap(err, "creating tag") return fmt.Errorf("error creating tag: %w", err)
} }
tags = append(tags, t) tags = append(tags, t)
} }
q := tx.Create(&newPool) q := tx.Create(&newPool)
if q.Error != nil { if q.Error != nil {
return errors.Wrap(q.Error, "creating pool") return fmt.Errorf("error creating pool: %w", q.Error)
} }
for i := range tags { for i := range tags {
if err := tx.Model(&newPool).Association("Tags").Append(&tags[i]); err != nil { if err := tx.Model(&newPool).Association("Tags").Append(&tags[i]); err != nil {
return errors.Wrap(err, "associating tags") return fmt.Errorf("error associating tags: %w", err)
} }
} }
return nil return nil
@ -341,7 +341,7 @@ func (s *sqlDatabase) CreateEntityPool(_ context.Context, entity params.ForgeEnt
dbPool, err := s.getPoolByID(s.conn, newPool.ID.String(), "Tags", "Instances", "Enterprise", "Organization", "Repository") dbPool, err := s.getPoolByID(s.conn, newPool.ID.String(), "Tags", "Instances", "Enterprise", "Organization", "Repository")
if err != nil { if err != nil {
return params.Pool{}, errors.Wrap(err, "fetching pool") return params.Pool{}, fmt.Errorf("error fetching pool: %w", err)
} }
return s.sqlToCommonPool(dbPool) return s.sqlToCommonPool(dbPool)
@ -358,7 +358,7 @@ func (s *sqlDatabase) GetEntityPool(_ context.Context, entity params.ForgeEntity
func (s *sqlDatabase) DeleteEntityPool(_ context.Context, entity params.ForgeEntity, poolID string) (err error) { func (s *sqlDatabase) DeleteEntityPool(_ context.Context, entity params.ForgeEntity, poolID string) (err error) {
entityID, err := uuid.Parse(entity.ID) entityID, err := uuid.Parse(entity.ID)
if err != nil { if err != nil {
return errors.Wrap(runnerErrors.ErrBadRequest, "parsing id") return fmt.Errorf("error parsing id: %w", runnerErrors.ErrBadRequest)
} }
defer func() { defer func() {
@ -372,7 +372,7 @@ func (s *sqlDatabase) DeleteEntityPool(_ context.Context, entity params.ForgeEnt
poolUUID, err := uuid.Parse(poolID) poolUUID, err := uuid.Parse(poolID)
if err != nil { if err != nil {
return errors.Wrap(runnerErrors.ErrBadRequest, "parsing pool id") return fmt.Errorf("error parsing pool id: %w", runnerErrors.ErrBadRequest)
} }
var fieldName string var fieldName string
switch entity.EntityType { switch entity.EntityType {
@ -387,7 +387,7 @@ func (s *sqlDatabase) DeleteEntityPool(_ context.Context, entity params.ForgeEnt
} }
condition := fmt.Sprintf("id = ? and %s = ?", fieldName) condition := fmt.Sprintf("id = ? and %s = ?", fieldName)
if err := s.conn.Unscoped().Where(condition, poolUUID, entityID).Delete(&Pool{}).Error; err != nil { if err := s.conn.Unscoped().Where(condition, poolUUID, entityID).Delete(&Pool{}).Error; err != nil {
return errors.Wrap(err, "removing pool") return fmt.Errorf("error removing pool: %w", err)
} }
return nil return nil
} }
@ -401,12 +401,12 @@ func (s *sqlDatabase) UpdateEntityPool(ctx context.Context, entity params.ForgeE
err = s.conn.Transaction(func(tx *gorm.DB) error { err = s.conn.Transaction(func(tx *gorm.DB) error {
pool, err := s.getEntityPool(tx, entity.EntityType, entity.ID, poolID, "Tags", "Instances") pool, err := s.getEntityPool(tx, entity.EntityType, entity.ID, poolID, "Tags", "Instances")
if err != nil { if err != nil {
return errors.Wrap(err, "fetching pool") return fmt.Errorf("error fetching pool: %w", err)
} }
updatedPool, err = s.updatePool(tx, pool, param) updatedPool, err = s.updatePool(tx, pool, param)
if err != nil { if err != nil {
return errors.Wrap(err, "updating pool") return fmt.Errorf("error updating pool: %w", err)
} }
return nil return nil
}) })
@ -424,14 +424,14 @@ func (s *sqlDatabase) UpdateEntityPool(ctx context.Context, entity params.ForgeE
func (s *sqlDatabase) ListEntityPools(_ context.Context, entity params.ForgeEntity) ([]params.Pool, error) { func (s *sqlDatabase) ListEntityPools(_ context.Context, entity params.ForgeEntity) ([]params.Pool, error) {
pools, err := s.listEntityPools(s.conn, entity.EntityType, entity.ID, "Tags") pools, err := s.listEntityPools(s.conn, entity.EntityType, entity.ID, "Tags")
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching pools") return nil, fmt.Errorf("error fetching pools: %w", err)
} }
ret := make([]params.Pool, len(pools)) ret := make([]params.Pool, len(pools))
for idx, pool := range pools { for idx, pool := range pools {
ret[idx], err = s.sqlToCommonPool(pool) ret[idx], err = s.sqlToCommonPool(pool)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching pool") return nil, fmt.Errorf("error fetching pool: %w", err)
} }
} }
@ -441,7 +441,7 @@ func (s *sqlDatabase) ListEntityPools(_ context.Context, entity params.ForgeEnti
func (s *sqlDatabase) ListEntityInstances(_ context.Context, entity params.ForgeEntity) ([]params.Instance, error) { func (s *sqlDatabase) ListEntityInstances(_ context.Context, entity params.ForgeEntity) ([]params.Instance, error) {
pools, err := s.listEntityPools(s.conn, entity.EntityType, entity.ID, "Instances", "Instances.Job") pools, err := s.listEntityPools(s.conn, entity.EntityType, entity.ID, "Instances", "Instances.Job")
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching entity") return nil, fmt.Errorf("error fetching entity: %w", err)
} }
ret := []params.Instance{} ret := []params.Instance{}
for _, pool := range pools { for _, pool := range pools {
@ -451,7 +451,7 @@ func (s *sqlDatabase) ListEntityInstances(_ context.Context, entity params.Forge
instance.Pool = pool instance.Pool = pool
paramsInstance, err := s.sqlToParamsInstance(instance) paramsInstance, err := s.sqlToParamsInstance(instance)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching instance") return nil, fmt.Errorf("error fetching instance: %w", err)
} }
ret = append(ret, paramsInstance) ret = append(ret, paramsInstance)
} }

View file

@ -157,7 +157,7 @@ func (s *PoolsTestSuite) TestListAllPoolsDBFetchErr() {
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching all pools: mocked fetching all pools error", err.Error()) s.Require().Equal("error fetching all pools: mocked fetching all pools error", err.Error())
} }
func (s *PoolsTestSuite) TestGetPoolByID() { func (s *PoolsTestSuite) TestGetPoolByID() {
@ -171,7 +171,7 @@ func (s *PoolsTestSuite) TestGetPoolByIDInvalidPoolID() {
_, err := s.Store.GetPoolByID(s.adminCtx, "dummy-pool-id") _, err := s.Store.GetPoolByID(s.adminCtx, "dummy-pool-id")
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching pool by ID: parsing id: invalid request", err.Error()) s.Require().Equal("error fetching pool by ID: error parsing id: invalid request", err.Error())
} }
func (s *PoolsTestSuite) TestDeletePoolByID() { func (s *PoolsTestSuite) TestDeletePoolByID() {
@ -179,14 +179,14 @@ func (s *PoolsTestSuite) TestDeletePoolByID() {
s.Require().Nil(err) s.Require().Nil(err)
_, err = s.Store.GetPoolByID(s.adminCtx, s.Fixtures.Pools[0].ID) _, err = s.Store.GetPoolByID(s.adminCtx, s.Fixtures.Pools[0].ID)
s.Require().Equal("fetching pool by ID: not found", err.Error()) s.Require().Equal("error fetching pool by ID: not found", err.Error())
} }
func (s *PoolsTestSuite) TestDeletePoolByIDInvalidPoolID() { func (s *PoolsTestSuite) TestDeletePoolByIDInvalidPoolID() {
err := s.Store.DeletePoolByID(s.adminCtx, "dummy-pool-id") err := s.Store.DeletePoolByID(s.adminCtx, "dummy-pool-id")
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching pool by ID: parsing id: invalid request", err.Error()) s.Require().Equal("error fetching pool by ID: error parsing id: invalid request", err.Error())
} }
func (s *PoolsTestSuite) TestDeletePoolByIDDBRemoveErr() { func (s *PoolsTestSuite) TestDeletePoolByIDDBRemoveErr() {
@ -204,7 +204,7 @@ func (s *PoolsTestSuite) TestDeletePoolByIDDBRemoveErr() {
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("removing pool: mocked removing pool error", err.Error()) s.Require().Equal("error removing pool: mocked removing pool error", err.Error())
} }
func (s *PoolsTestSuite) TestEntityPoolOperations() { func (s *PoolsTestSuite) TestEntityPoolOperations() {

View file

@ -16,11 +16,11 @@ package sql
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"log/slog" "log/slog"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/pkg/errors"
"gorm.io/gorm" "gorm.io/gorm"
runnerErrors "github.com/cloudbase/garm-provider-common/errors" runnerErrors "github.com/cloudbase/garm-provider-common/errors"
@ -57,23 +57,23 @@ func (s *sqlDatabase) CreateRepository(ctx context.Context, owner, name string,
case params.GiteaEndpointType: case params.GiteaEndpointType:
newRepo.GiteaCredentialsID = &credentials.ID newRepo.GiteaCredentialsID = &credentials.ID
default: default:
return errors.Wrap(runnerErrors.ErrBadRequest, "unsupported credentials type") return runnerErrors.NewBadRequestError("unsupported credentials type")
} }
newRepo.EndpointName = &credentials.Endpoint.Name newRepo.EndpointName = &credentials.Endpoint.Name
q := tx.Create(&newRepo) q := tx.Create(&newRepo)
if q.Error != nil { if q.Error != nil {
return errors.Wrap(q.Error, "creating repository") return fmt.Errorf("error creating repository: %w", q.Error)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return params.Repository{}, errors.Wrap(err, "creating repository") return params.Repository{}, fmt.Errorf("error creating repository: %w", err)
} }
ret, err := s.GetRepositoryByID(ctx, newRepo.ID.String()) ret, err := s.GetRepositoryByID(ctx, newRepo.ID.String())
if err != nil { if err != nil {
return params.Repository{}, errors.Wrap(err, "creating repository") return params.Repository{}, fmt.Errorf("error creating repository: %w", err)
} }
return ret, nil return ret, nil
@ -82,12 +82,12 @@ func (s *sqlDatabase) CreateRepository(ctx context.Context, owner, name string,
func (s *sqlDatabase) GetRepository(ctx context.Context, owner, name, endpointName string) (params.Repository, error) { func (s *sqlDatabase) GetRepository(ctx context.Context, owner, name, endpointName string) (params.Repository, error) {
repo, err := s.getRepo(ctx, owner, name, endpointName) repo, err := s.getRepo(ctx, owner, name, endpointName)
if err != nil { if err != nil {
return params.Repository{}, errors.Wrap(err, "fetching repo") return params.Repository{}, fmt.Errorf("error fetching repo: %w", err)
} }
param, err := s.sqlToCommonRepository(repo, true) param, err := s.sqlToCommonRepository(repo, true)
if err != nil { if err != nil {
return params.Repository{}, errors.Wrap(err, "fetching repo") return params.Repository{}, fmt.Errorf("error fetching repo: %w", err)
} }
return param, nil return param, nil
@ -112,7 +112,7 @@ func (s *sqlDatabase) ListRepositories(_ context.Context, filter params.Reposito
} }
q = q.Find(&repos) q = q.Find(&repos)
if q.Error != nil { if q.Error != nil {
return []params.Repository{}, errors.Wrap(q.Error, "fetching user from database") return []params.Repository{}, fmt.Errorf("error fetching user from database: %w", q.Error)
} }
ret := make([]params.Repository, len(repos)) ret := make([]params.Repository, len(repos))
@ -120,7 +120,7 @@ func (s *sqlDatabase) ListRepositories(_ context.Context, filter params.Reposito
var err error var err error
ret[idx], err = s.sqlToCommonRepository(val, true) ret[idx], err = s.sqlToCommonRepository(val, true)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching repositories") return nil, fmt.Errorf("error fetching repositories: %w", err)
} }
} }
@ -130,7 +130,7 @@ func (s *sqlDatabase) ListRepositories(_ context.Context, filter params.Reposito
func (s *sqlDatabase) DeleteRepository(ctx context.Context, repoID string) (err error) { func (s *sqlDatabase) DeleteRepository(ctx context.Context, repoID string) (err error) {
repo, err := s.getRepoByID(ctx, s.conn, repoID, "Endpoint", "Credentials", "Credentials.Endpoint", "GiteaCredentials", "GiteaCredentials.Endpoint") repo, err := s.getRepoByID(ctx, s.conn, repoID, "Endpoint", "Credentials", "Credentials.Endpoint", "GiteaCredentials", "GiteaCredentials.Endpoint")
if err != nil { if err != nil {
return errors.Wrap(err, "fetching repo") return fmt.Errorf("error fetching repo: %w", err)
} }
defer func(repo Repository) { defer func(repo Repository) {
@ -146,7 +146,7 @@ func (s *sqlDatabase) DeleteRepository(ctx context.Context, repoID string) (err
q := s.conn.Unscoped().Delete(&repo) q := s.conn.Unscoped().Delete(&repo)
if q.Error != nil && !errors.Is(q.Error, gorm.ErrRecordNotFound) { if q.Error != nil && !errors.Is(q.Error, gorm.ErrRecordNotFound) {
return errors.Wrap(q.Error, "deleting repo") return fmt.Errorf("error deleting repo: %w", q.Error)
} }
return nil return nil
@ -164,23 +164,23 @@ func (s *sqlDatabase) UpdateRepository(ctx context.Context, repoID string, param
var err error var err error
repo, err = s.getRepoByID(ctx, tx, repoID) repo, err = s.getRepoByID(ctx, tx, repoID)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching repo") return fmt.Errorf("error fetching repo: %w", err)
} }
if repo.EndpointName == nil { if repo.EndpointName == nil {
return errors.Wrap(runnerErrors.ErrUnprocessable, "repository has no endpoint") return runnerErrors.NewUnprocessableError("repository has no endpoint")
} }
if param.CredentialsName != "" { if param.CredentialsName != "" {
creds, err = s.getGithubCredentialsByName(ctx, tx, param.CredentialsName, false) creds, err = s.getGithubCredentialsByName(ctx, tx, param.CredentialsName, false)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching credentials") return fmt.Errorf("error fetching credentials: %w", err)
} }
if creds.EndpointName == nil { if creds.EndpointName == nil {
return errors.Wrap(runnerErrors.ErrUnprocessable, "credentials have no endpoint") return runnerErrors.NewUnprocessableError("credentials have no endpoint")
} }
if *creds.EndpointName != *repo.EndpointName { if *creds.EndpointName != *repo.EndpointName {
return errors.Wrap(runnerErrors.ErrBadRequest, "endpoint mismatch") return runnerErrors.NewBadRequestError("endpoint mismatch")
} }
repo.CredentialsID = &creds.ID repo.CredentialsID = &creds.ID
} }
@ -199,23 +199,23 @@ func (s *sqlDatabase) UpdateRepository(ctx context.Context, repoID string, param
q := tx.Save(&repo) q := tx.Save(&repo)
if q.Error != nil { if q.Error != nil {
return errors.Wrap(q.Error, "saving repo") return fmt.Errorf("error saving repo: %w", q.Error)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return params.Repository{}, errors.Wrap(err, "saving repo") return params.Repository{}, fmt.Errorf("error saving repo: %w", err)
} }
repo, err = s.getRepoByID(ctx, s.conn, repoID, "Endpoint", "Credentials", "Credentials.Endpoint", "GiteaCredentials", "GiteaCredentials.Endpoint") repo, err = s.getRepoByID(ctx, s.conn, repoID, "Endpoint", "Credentials", "Credentials.Endpoint", "GiteaCredentials", "GiteaCredentials.Endpoint")
if err != nil { if err != nil {
return params.Repository{}, errors.Wrap(err, "updating enterprise") return params.Repository{}, fmt.Errorf("error updating enterprise: %w", err)
} }
newParams, err = s.sqlToCommonRepository(repo, true) newParams, err = s.sqlToCommonRepository(repo, true)
if err != nil { if err != nil {
return params.Repository{}, errors.Wrap(err, "saving repo") return params.Repository{}, fmt.Errorf("error saving repo: %w", err)
} }
return newParams, nil return newParams, nil
} }
@ -232,12 +232,12 @@ func (s *sqlDatabase) GetRepositoryByID(ctx context.Context, repoID string) (par
} }
repo, err := s.getRepoByID(ctx, s.conn, repoID, preloadList...) repo, err := s.getRepoByID(ctx, s.conn, repoID, preloadList...)
if err != nil { if err != nil {
return params.Repository{}, errors.Wrap(err, "fetching repo") return params.Repository{}, fmt.Errorf("error fetching repo: %w", err)
} }
param, err := s.sqlToCommonRepository(repo, true) param, err := s.sqlToCommonRepository(repo, true)
if err != nil { if err != nil {
return params.Repository{}, errors.Wrap(err, "fetching repo") return params.Repository{}, fmt.Errorf("error fetching repo: %w", err)
} }
return param, nil return param, nil
} }
@ -259,7 +259,7 @@ func (s *sqlDatabase) getRepo(_ context.Context, owner, name, endpointName strin
if errors.Is(q.Error, gorm.ErrRecordNotFound) { if errors.Is(q.Error, gorm.ErrRecordNotFound) {
return Repository{}, runnerErrors.ErrNotFound return Repository{}, runnerErrors.ErrNotFound
} }
return Repository{}, errors.Wrap(q.Error, "fetching repository from database") return Repository{}, fmt.Errorf("error fetching repository from database: %w", q.Error)
} }
return repo, nil return repo, nil
} }
@ -267,7 +267,7 @@ func (s *sqlDatabase) getRepo(_ context.Context, owner, name, endpointName strin
func (s *sqlDatabase) getRepoByID(_ context.Context, tx *gorm.DB, id string, preload ...string) (Repository, error) { func (s *sqlDatabase) getRepoByID(_ context.Context, tx *gorm.DB, id string, preload ...string) (Repository, error) {
u, err := uuid.Parse(id) u, err := uuid.Parse(id)
if err != nil { if err != nil {
return Repository{}, errors.Wrap(runnerErrors.ErrBadRequest, "parsing id") return Repository{}, runnerErrors.NewBadRequestError("error parsing id: %s", err)
} }
var repo Repository var repo Repository
@ -283,7 +283,7 @@ func (s *sqlDatabase) getRepoByID(_ context.Context, tx *gorm.DB, id string, pre
if errors.Is(q.Error, gorm.ErrRecordNotFound) { if errors.Is(q.Error, gorm.ErrRecordNotFound) {
return Repository{}, runnerErrors.ErrNotFound return Repository{}, runnerErrors.ErrNotFound
} }
return Repository{}, errors.Wrap(q.Error, "fetching repository from database") return Repository{}, fmt.Errorf("error fetching repository from database: %w", q.Error)
} }
return repo, nil return repo, nil
} }

View file

@ -284,7 +284,7 @@ func (s *RepoTestSuite) TestCreateRepositoryInvalidForgeType() {
) )
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("creating repository: unsupported credentials type: invalid request", err.Error()) s.Require().Equal("error creating repository: unsupported credentials type", err.Error())
} }
func (s *RepoTestSuite) TestCreateRepositoryInvalidDBPassphrase() { func (s *RepoTestSuite) TestCreateRepositoryInvalidDBPassphrase() {
@ -330,7 +330,7 @@ func (s *RepoTestSuite) TestCreateRepositoryInvalidDBCreateErr() {
) )
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("creating repository: creating repository: creating repo mock error", err.Error()) s.Require().Equal("error creating repository: error creating repository: creating repo mock error", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -355,7 +355,7 @@ func (s *RepoTestSuite) TestGetRepositoryNotFound() {
_, err := s.Store.GetRepository(s.adminCtx, "dummy-owner", "dummy-name", "github.com") _, err := s.Store.GetRepository(s.adminCtx, "dummy-owner", "dummy-name", "github.com")
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching repo: not found", err.Error()) s.Require().Equal("error fetching repo: not found", err.Error())
} }
func (s *RepoTestSuite) TestGetRepositoryDBDecryptingErr() { func (s *RepoTestSuite) TestGetRepositoryDBDecryptingErr() {
@ -371,7 +371,7 @@ func (s *RepoTestSuite) TestGetRepositoryDBDecryptingErr() {
_, err := s.StoreSQLMocked.GetRepository(s.adminCtx, s.Fixtures.Repos[0].Owner, s.Fixtures.Repos[0].Name, s.Fixtures.Repos[0].Endpoint.Name) _, err := s.StoreSQLMocked.GetRepository(s.adminCtx, s.Fixtures.Repos[0].Owner, s.Fixtures.Repos[0].Name, s.Fixtures.Repos[0].Endpoint.Name)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching repo: missing secret", err.Error()) s.Require().Equal("error fetching repo: missing secret", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -471,7 +471,7 @@ func (s *RepoTestSuite) TestListRepositoriesDBFetchErr() {
_, err := s.StoreSQLMocked.ListRepositories(s.adminCtx, params.RepositoryFilter{}) _, err := s.StoreSQLMocked.ListRepositories(s.adminCtx, params.RepositoryFilter{})
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching user from database: fetching user from database mock error", err.Error()) s.Require().Equal("error fetching user from database: fetching user from database mock error", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -485,7 +485,7 @@ func (s *RepoTestSuite) TestListRepositoriesDBDecryptingErr() {
_, err := s.StoreSQLMocked.ListRepositories(s.adminCtx, params.RepositoryFilter{}) _, err := s.StoreSQLMocked.ListRepositories(s.adminCtx, params.RepositoryFilter{})
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching repositories: decrypting secret: invalid passphrase length (expected length 32 characters)", err.Error()) s.Require().Equal("error fetching repositories: error decrypting secret: invalid passphrase length (expected length 32 characters)", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -495,14 +495,14 @@ func (s *RepoTestSuite) TestDeleteRepository() {
s.Require().Nil(err) s.Require().Nil(err)
_, err = s.Store.GetRepositoryByID(s.adminCtx, s.Fixtures.Repos[0].ID) _, err = s.Store.GetRepositoryByID(s.adminCtx, s.Fixtures.Repos[0].ID)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching repo: not found", err.Error()) s.Require().Equal("error fetching repo: not found", err.Error())
} }
func (s *RepoTestSuite) TestDeleteRepositoryInvalidRepoID() { func (s *RepoTestSuite) TestDeleteRepositoryInvalidRepoID() {
err := s.Store.DeleteRepository(s.adminCtx, "dummy-repo-id") err := s.Store.DeleteRepository(s.adminCtx, "dummy-repo-id")
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching repo: parsing id: invalid request", err.Error()) s.Require().Equal("error fetching repo: error parsing id: invalid UUID length: 13", err.Error())
} }
func (s *RepoTestSuite) TestDeleteRepositoryDBRemoveErr() { func (s *RepoTestSuite) TestDeleteRepositoryDBRemoveErr() {
@ -520,7 +520,7 @@ func (s *RepoTestSuite) TestDeleteRepositoryDBRemoveErr() {
err := s.StoreSQLMocked.DeleteRepository(s.adminCtx, s.Fixtures.Repos[0].ID) err := s.StoreSQLMocked.DeleteRepository(s.adminCtx, s.Fixtures.Repos[0].ID)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("deleting repo: mocked deleting repo error", err.Error()) s.Require().Equal("error deleting repo: mocked deleting repo error", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -536,7 +536,7 @@ func (s *RepoTestSuite) TestUpdateRepositoryInvalidRepoID() {
_, err := s.Store.UpdateRepository(s.adminCtx, "dummy-repo-id", s.Fixtures.UpdateRepoParams) _, err := s.Store.UpdateRepository(s.adminCtx, "dummy-repo-id", s.Fixtures.UpdateRepoParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("saving repo: fetching repo: parsing id: invalid request", err.Error()) s.Require().Equal("error saving repo: error fetching repo: error parsing id: invalid UUID length: 13", err.Error())
} }
func (s *RepoTestSuite) TestUpdateRepositoryDBEncryptErr() { func (s *RepoTestSuite) TestUpdateRepositoryDBEncryptErr() {
@ -561,7 +561,7 @@ func (s *RepoTestSuite) TestUpdateRepositoryDBEncryptErr() {
_, err := s.StoreSQLMocked.UpdateRepository(s.adminCtx, s.Fixtures.Repos[0].ID, s.Fixtures.UpdateRepoParams) _, err := s.StoreSQLMocked.UpdateRepository(s.adminCtx, s.Fixtures.Repos[0].ID, s.Fixtures.UpdateRepoParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("saving repo: saving repo: failed to encrypt string: invalid passphrase length (expected length 32 characters)", err.Error()) s.Require().Equal("error saving repo: saving repo: failed to encrypt string: invalid passphrase length (expected length 32 characters)", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -589,7 +589,7 @@ func (s *RepoTestSuite) TestUpdateRepositoryDBSaveErr() {
_, err := s.StoreSQLMocked.UpdateRepository(s.adminCtx, s.Fixtures.Repos[0].ID, s.Fixtures.UpdateRepoParams) _, err := s.StoreSQLMocked.UpdateRepository(s.adminCtx, s.Fixtures.Repos[0].ID, s.Fixtures.UpdateRepoParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("saving repo: saving repo: saving repo mock error", err.Error()) s.Require().Equal("error saving repo: error saving repo: saving repo mock error", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -616,7 +616,7 @@ func (s *RepoTestSuite) TestUpdateRepositoryDBDecryptingErr() {
_, err := s.StoreSQLMocked.UpdateRepository(s.adminCtx, s.Fixtures.Repos[0].ID, s.Fixtures.UpdateRepoParams) _, err := s.StoreSQLMocked.UpdateRepository(s.adminCtx, s.Fixtures.Repos[0].ID, s.Fixtures.UpdateRepoParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("saving repo: saving repo: failed to encrypt string: invalid passphrase length (expected length 32 characters)", err.Error()) s.Require().Equal("error saving repo: saving repo: failed to encrypt string: invalid passphrase length (expected length 32 characters)", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -631,7 +631,7 @@ func (s *RepoTestSuite) TestGetRepositoryByIDInvalidRepoID() {
_, err := s.Store.GetRepositoryByID(s.adminCtx, "dummy-repo-id") _, err := s.Store.GetRepositoryByID(s.adminCtx, "dummy-repo-id")
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching repo: parsing id: invalid request", err.Error()) s.Require().Equal("error fetching repo: error parsing id: invalid UUID length: 13", err.Error())
} }
func (s *RepoTestSuite) TestGetRepositoryByIDDBDecryptingErr() { func (s *RepoTestSuite) TestGetRepositoryByIDDBDecryptingErr() {
@ -651,7 +651,7 @@ func (s *RepoTestSuite) TestGetRepositoryByIDDBDecryptingErr() {
_, err := s.StoreSQLMocked.GetRepositoryByID(s.adminCtx, s.Fixtures.Repos[0].ID) _, err := s.StoreSQLMocked.GetRepositoryByID(s.adminCtx, s.Fixtures.Repos[0].ID)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching repo: missing secret", err.Error()) s.Require().Equal("error fetching repo: missing secret", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -690,7 +690,7 @@ func (s *RepoTestSuite) TestCreateRepositoryPoolInvalidRepoID() {
_, err := s.Store.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams) _, err := s.Store.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("parsing id: invalid request", err.Error()) s.Require().Equal("error parsing id: invalid request", err.Error())
} }
func (s *RepoTestSuite) TestCreateRepositoryPoolDBFetchTagErr() { func (s *RepoTestSuite) TestCreateRepositoryPoolDBFetchTagErr() {
@ -709,7 +709,7 @@ func (s *RepoTestSuite) TestCreateRepositoryPoolDBFetchTagErr() {
_, err = s.StoreSQLMocked.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams) _, err = s.StoreSQLMocked.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("creating tag: fetching tag from database: mocked fetching tag error", err.Error()) s.Require().Equal("error creating tag: error fetching tag from database: mocked fetching tag error", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -738,7 +738,7 @@ func (s *RepoTestSuite) TestCreateRepositoryPoolDBAddingPoolErr() {
_, err = s.StoreSQLMocked.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams) _, err = s.StoreSQLMocked.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("creating pool: mocked adding pool error", err.Error()) s.Require().Equal("error creating pool: mocked adding pool error", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -769,7 +769,7 @@ func (s *RepoTestSuite) TestCreateRepositoryPoolDBSaveTagErr() {
_, err = s.StoreSQLMocked.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams) _, err = s.StoreSQLMocked.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("associating tags: mocked saving tag error", err.Error()) s.Require().Equal("error associating tags: mocked saving tag error", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -810,7 +810,7 @@ func (s *RepoTestSuite) TestCreateRepositoryPoolDBFetchPoolErr() {
_, err = s.StoreSQLMocked.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams) _, err = s.StoreSQLMocked.CreateEntityPool(s.adminCtx, entity, s.Fixtures.CreatePoolParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching pool: not found", err.Error()) s.Require().Equal("error fetching pool: not found", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -841,7 +841,7 @@ func (s *RepoTestSuite) TestListRepoPoolsInvalidRepoID() {
_, err := s.Store.ListEntityPools(s.adminCtx, entity) _, err := s.Store.ListEntityPools(s.adminCtx, entity)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching pools: parsing id: invalid request", err.Error()) s.Require().Equal("error fetching pools: error parsing id: invalid request", err.Error())
} }
func (s *RepoTestSuite) TestGetRepositoryPool() { func (s *RepoTestSuite) TestGetRepositoryPool() {
@ -866,7 +866,7 @@ func (s *RepoTestSuite) TestGetRepositoryPoolInvalidRepoID() {
_, err := s.Store.GetEntityPool(s.adminCtx, entity, "dummy-pool-id") _, err := s.Store.GetEntityPool(s.adminCtx, entity, "dummy-pool-id")
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching pool: parsing id: invalid request", err.Error()) s.Require().Equal("fetching pool: error parsing id: invalid request", err.Error())
} }
func (s *RepoTestSuite) TestDeleteRepositoryPool() { func (s *RepoTestSuite) TestDeleteRepositoryPool() {
@ -881,7 +881,7 @@ func (s *RepoTestSuite) TestDeleteRepositoryPool() {
s.Require().Nil(err) s.Require().Nil(err)
_, err = s.Store.GetEntityPool(s.adminCtx, entity, pool.ID) _, err = s.Store.GetEntityPool(s.adminCtx, entity, pool.ID)
s.Require().Equal("fetching pool: finding pool: not found", err.Error()) s.Require().Equal("fetching pool: error finding pool: not found", err.Error())
} }
func (s *RepoTestSuite) TestDeleteRepositoryPoolInvalidRepoID() { func (s *RepoTestSuite) TestDeleteRepositoryPoolInvalidRepoID() {
@ -892,7 +892,7 @@ func (s *RepoTestSuite) TestDeleteRepositoryPoolInvalidRepoID() {
err := s.Store.DeleteEntityPool(s.adminCtx, entity, "dummy-pool-id") err := s.Store.DeleteEntityPool(s.adminCtx, entity, "dummy-pool-id")
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("parsing id: invalid request", err.Error()) s.Require().Equal("error parsing id: invalid request", err.Error())
} }
func (s *RepoTestSuite) TestDeleteRepositoryPoolDBDeleteErr() { func (s *RepoTestSuite) TestDeleteRepositoryPoolDBDeleteErr() {
@ -913,7 +913,7 @@ func (s *RepoTestSuite) TestDeleteRepositoryPoolDBDeleteErr() {
err = s.StoreSQLMocked.DeleteEntityPool(s.adminCtx, entity, pool.ID) err = s.StoreSQLMocked.DeleteEntityPool(s.adminCtx, entity, pool.ID)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("removing pool: mocked deleting pool error", err.Error()) s.Require().Equal("error removing pool: mocked deleting pool error", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -948,7 +948,7 @@ func (s *RepoTestSuite) TestListRepoInstancesInvalidRepoID() {
_, err := s.Store.ListEntityInstances(s.adminCtx, entity) _, err := s.Store.ListEntityInstances(s.adminCtx, entity)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching entity: parsing id: invalid request", err.Error()) s.Require().Equal("error fetching entity: error parsing id: invalid request", err.Error())
} }
func (s *RepoTestSuite) TestUpdateRepositoryPool() { func (s *RepoTestSuite) TestUpdateRepositoryPool() {
@ -976,7 +976,7 @@ func (s *RepoTestSuite) TestUpdateRepositoryPoolInvalidRepoID() {
_, err := s.Store.UpdateEntityPool(s.adminCtx, entity, "dummy-repo-id", s.Fixtures.UpdatePoolParams) _, err := s.Store.UpdateEntityPool(s.adminCtx, entity, "dummy-repo-id", s.Fixtures.UpdatePoolParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching pool: parsing id: invalid request", err.Error()) s.Require().Equal("error fetching pool: error parsing id: invalid request", err.Error())
} }
func (s *RepoTestSuite) TestAddRepoEntityEvent() { func (s *RepoTestSuite) TestAddRepoEntityEvent() {

View file

@ -16,8 +16,7 @@ package sql
import ( import (
"context" "context"
"fmt"
"github.com/pkg/errors"
"github.com/cloudbase/garm/database/common" "github.com/cloudbase/garm/database/common"
"github.com/cloudbase/garm/params" "github.com/cloudbase/garm/params"
@ -26,7 +25,7 @@ import (
func (s *sqlDatabase) CreateScaleSetInstance(_ context.Context, scaleSetID uint, param params.CreateInstanceParams) (instance params.Instance, err error) { func (s *sqlDatabase) CreateScaleSetInstance(_ context.Context, scaleSetID uint, param params.CreateInstanceParams) (instance params.Instance, err error) {
scaleSet, err := s.getScaleSetByID(s.conn, scaleSetID) scaleSet, err := s.getScaleSetByID(s.conn, scaleSetID)
if err != nil { if err != nil {
return params.Instance{}, errors.Wrap(err, "fetching scale set") return params.Instance{}, fmt.Errorf("error fetching scale set: %w", err)
} }
defer func() { defer func() {
@ -39,7 +38,7 @@ func (s *sqlDatabase) CreateScaleSetInstance(_ context.Context, scaleSetID uint,
if len(param.JitConfiguration) > 0 { if len(param.JitConfiguration) > 0 {
secret, err = s.marshalAndSeal(param.JitConfiguration) secret, err = s.marshalAndSeal(param.JitConfiguration)
if err != nil { if err != nil {
return params.Instance{}, errors.Wrap(err, "marshalling jit config") return params.Instance{}, fmt.Errorf("error marshalling jit config: %w", err)
} }
} }
@ -58,7 +57,7 @@ func (s *sqlDatabase) CreateScaleSetInstance(_ context.Context, scaleSetID uint,
} }
q := s.conn.Create(&newInstance) q := s.conn.Create(&newInstance)
if q.Error != nil { if q.Error != nil {
return params.Instance{}, errors.Wrap(q.Error, "creating instance") return params.Instance{}, fmt.Errorf("error creating instance: %w", q.Error)
} }
return s.sqlToParamsInstance(newInstance) return s.sqlToParamsInstance(newInstance)
@ -72,7 +71,7 @@ func (s *sqlDatabase) ListScaleSetInstances(_ context.Context, scalesetID uint)
Where("scale_set_fk_id = ?", scalesetID) Where("scale_set_fk_id = ?", scalesetID)
if err := query.Find(&instances); err.Error != nil { if err := query.Find(&instances); err.Error != nil {
return nil, errors.Wrap(err.Error, "fetching instances") return nil, fmt.Errorf("error fetching instances: %w", err.Error)
} }
var err error var err error
@ -80,7 +79,7 @@ func (s *sqlDatabase) ListScaleSetInstances(_ context.Context, scalesetID uint)
for idx, inst := range instances { for idx, inst := range instances {
ret[idx], err = s.sqlToParamsInstance(inst) ret[idx], err = s.sqlToParamsInstance(inst)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "converting instance") return nil, fmt.Errorf("error converting instance: %w", err)
} }
} }
return ret, nil return ret, nil

View file

@ -16,10 +16,10 @@ package sql
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/pkg/errors"
"gorm.io/datatypes" "gorm.io/datatypes"
"gorm.io/gorm" "gorm.io/gorm"
@ -42,7 +42,7 @@ func (s *sqlDatabase) ListAllScaleSets(_ context.Context) ([]params.ScaleSet, er
Omit("status_messages"). Omit("status_messages").
Find(&scaleSets) Find(&scaleSets)
if q.Error != nil { if q.Error != nil {
return nil, errors.Wrap(q.Error, "fetching all scale sets") return nil, fmt.Errorf("error fetching all scale sets: %w", q.Error)
} }
ret := make([]params.ScaleSet, len(scaleSets)) ret := make([]params.ScaleSet, len(scaleSets))
@ -50,7 +50,7 @@ func (s *sqlDatabase) ListAllScaleSets(_ context.Context) ([]params.ScaleSet, er
for idx, val := range scaleSets { for idx, val := range scaleSets {
ret[idx], err = s.sqlToCommonScaleSet(val) ret[idx], err = s.sqlToCommonScaleSet(val)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "converting scale sets") return nil, fmt.Errorf("error converting scale sets: %w", err)
} }
} }
return ret, nil return ret, nil
@ -91,7 +91,7 @@ func (s *sqlDatabase) CreateEntityScaleSet(_ context.Context, entity params.Forg
entityID, err := uuid.Parse(entity.ID) entityID, err := uuid.Parse(entity.ID)
if err != nil { if err != nil {
return params.ScaleSet{}, errors.Wrap(runnerErrors.ErrBadRequest, "parsing id") return params.ScaleSet{}, fmt.Errorf("error parsing id: %w", runnerErrors.ErrBadRequest)
} }
switch entity.EntityType { switch entity.EntityType {
@ -104,12 +104,12 @@ func (s *sqlDatabase) CreateEntityScaleSet(_ context.Context, entity params.Forg
} }
err = s.conn.Transaction(func(tx *gorm.DB) error { err = s.conn.Transaction(func(tx *gorm.DB) error {
if err := s.hasGithubEntity(tx, entity.EntityType, entity.ID); err != nil { if err := s.hasGithubEntity(tx, entity.EntityType, entity.ID); err != nil {
return errors.Wrap(err, "checking entity existence") return fmt.Errorf("error checking entity existence: %w", err)
} }
q := tx.Create(&newScaleSet) q := tx.Create(&newScaleSet)
if q.Error != nil { if q.Error != nil {
return errors.Wrap(q.Error, "creating scale set") return fmt.Errorf("error creating scale set: %w", q.Error)
} }
return nil return nil
@ -120,7 +120,7 @@ func (s *sqlDatabase) CreateEntityScaleSet(_ context.Context, entity params.Forg
dbScaleSet, err := s.getScaleSetByID(s.conn, newScaleSet.ID, "Instances", "Enterprise", "Organization", "Repository") dbScaleSet, err := s.getScaleSetByID(s.conn, newScaleSet.ID, "Instances", "Enterprise", "Organization", "Repository")
if err != nil { if err != nil {
return params.ScaleSet{}, errors.Wrap(err, "fetching scale set") return params.ScaleSet{}, fmt.Errorf("error fetching scale set: %w", err)
} }
return s.sqlToCommonScaleSet(dbScaleSet) return s.sqlToCommonScaleSet(dbScaleSet)
@ -128,11 +128,11 @@ func (s *sqlDatabase) CreateEntityScaleSet(_ context.Context, entity params.Forg
func (s *sqlDatabase) listEntityScaleSets(tx *gorm.DB, entityType params.ForgeEntityType, entityID string, preload ...string) ([]ScaleSet, error) { func (s *sqlDatabase) listEntityScaleSets(tx *gorm.DB, entityType params.ForgeEntityType, entityID string, preload ...string) ([]ScaleSet, error) {
if _, err := uuid.Parse(entityID); err != nil { if _, err := uuid.Parse(entityID); err != nil {
return nil, errors.Wrap(runnerErrors.ErrBadRequest, "parsing id") return nil, fmt.Errorf("error parsing id: %w", runnerErrors.ErrBadRequest)
} }
if err := s.hasGithubEntity(tx, entityType, entityID); err != nil { if err := s.hasGithubEntity(tx, entityType, entityID); err != nil {
return nil, errors.Wrap(err, "checking entity existence") return nil, fmt.Errorf("error checking entity existence: %w", err)
} }
var preloadEntity string var preloadEntity string
@ -170,7 +170,7 @@ func (s *sqlDatabase) listEntityScaleSets(tx *gorm.DB, entityType params.ForgeEn
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return []ScaleSet{}, nil return []ScaleSet{}, nil
} }
return nil, errors.Wrap(err, "fetching scale sets") return nil, fmt.Errorf("error fetching scale sets: %w", err)
} }
return scaleSets, nil return scaleSets, nil
@ -179,14 +179,14 @@ func (s *sqlDatabase) listEntityScaleSets(tx *gorm.DB, entityType params.ForgeEn
func (s *sqlDatabase) ListEntityScaleSets(_ context.Context, entity params.ForgeEntity) ([]params.ScaleSet, error) { func (s *sqlDatabase) ListEntityScaleSets(_ context.Context, entity params.ForgeEntity) ([]params.ScaleSet, error) {
scaleSets, err := s.listEntityScaleSets(s.conn, entity.EntityType, entity.ID) scaleSets, err := s.listEntityScaleSets(s.conn, entity.EntityType, entity.ID)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching scale sets") return nil, fmt.Errorf("error fetching scale sets: %w", err)
} }
ret := make([]params.ScaleSet, len(scaleSets)) ret := make([]params.ScaleSet, len(scaleSets))
for idx, set := range scaleSets { for idx, set := range scaleSets {
ret[idx], err = s.sqlToCommonScaleSet(set) ret[idx], err = s.sqlToCommonScaleSet(set)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "conbverting scale set") return nil, fmt.Errorf("error conbverting scale set: %w", err)
} }
} }
@ -202,22 +202,22 @@ func (s *sqlDatabase) UpdateEntityScaleSet(ctx context.Context, entity params.Fo
err = s.conn.Transaction(func(tx *gorm.DB) error { err = s.conn.Transaction(func(tx *gorm.DB) error {
scaleSet, err := s.getEntityScaleSet(tx, entity.EntityType, entity.ID, scaleSetID, "Instances") scaleSet, err := s.getEntityScaleSet(tx, entity.EntityType, entity.ID, scaleSetID, "Instances")
if err != nil { if err != nil {
return errors.Wrap(err, "fetching scale set") return fmt.Errorf("error fetching scale set: %w", err)
} }
old, err := s.sqlToCommonScaleSet(scaleSet) old, err := s.sqlToCommonScaleSet(scaleSet)
if err != nil { if err != nil {
return errors.Wrap(err, "converting scale set") return fmt.Errorf("error converting scale set: %w", err)
} }
updatedScaleSet, err = s.updateScaleSet(tx, scaleSet, param) updatedScaleSet, err = s.updateScaleSet(tx, scaleSet, param)
if err != nil { if err != nil {
return errors.Wrap(err, "updating scale set") return fmt.Errorf("error updating scale set: %w", err)
} }
if callback != nil { if callback != nil {
if err := callback(old, updatedScaleSet); err != nil { if err := callback(old, updatedScaleSet); err != nil {
return errors.Wrap(err, "executing update callback") return fmt.Errorf("error executing update callback: %w", err)
} }
} }
return nil return nil
@ -235,11 +235,11 @@ func (s *sqlDatabase) UpdateEntityScaleSet(ctx context.Context, entity params.Fo
func (s *sqlDatabase) getEntityScaleSet(tx *gorm.DB, entityType params.ForgeEntityType, entityID string, scaleSetID uint, preload ...string) (ScaleSet, error) { func (s *sqlDatabase) getEntityScaleSet(tx *gorm.DB, entityType params.ForgeEntityType, entityID string, scaleSetID uint, preload ...string) (ScaleSet, error) {
if entityID == "" { if entityID == "" {
return ScaleSet{}, errors.Wrap(runnerErrors.ErrBadRequest, "missing entity id") return ScaleSet{}, fmt.Errorf("error missing entity id: %w", runnerErrors.ErrBadRequest)
} }
if scaleSetID == 0 { if scaleSetID == 0 {
return ScaleSet{}, errors.Wrap(runnerErrors.ErrBadRequest, "missing scaleset id") return ScaleSet{}, fmt.Errorf("error missing scaleset id: %w", runnerErrors.ErrBadRequest)
} }
var fieldName string var fieldName string
@ -273,9 +273,9 @@ func (s *sqlDatabase) getEntityScaleSet(tx *gorm.DB, entityType params.ForgeEnti
First(&scaleSet).Error First(&scaleSet).Error
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return ScaleSet{}, errors.Wrap(runnerErrors.ErrNotFound, "finding scale set") return ScaleSet{}, fmt.Errorf("error finding scale set: %w", runnerErrors.ErrNotFound)
} }
return ScaleSet{}, errors.Wrap(err, "fetching scale set") return ScaleSet{}, fmt.Errorf("error fetching scale set: %w", err)
} }
return scaleSet, nil return scaleSet, nil
@ -343,7 +343,7 @@ func (s *sqlDatabase) updateScaleSet(tx *gorm.DB, scaleSet ScaleSet, param param
} }
if q := tx.Save(&scaleSet); q.Error != nil { if q := tx.Save(&scaleSet); q.Error != nil {
return params.ScaleSet{}, errors.Wrap(q.Error, "saving database entry") return params.ScaleSet{}, fmt.Errorf("error saving database entry: %w", q.Error)
} }
return s.sqlToCommonScaleSet(scaleSet) return s.sqlToCommonScaleSet(scaleSet)
@ -362,7 +362,7 @@ func (s *sqlDatabase) GetScaleSetByID(_ context.Context, scaleSet uint) (params.
"Repository.Endpoint", "Repository.Endpoint",
) )
if err != nil { if err != nil {
return params.ScaleSet{}, errors.Wrap(err, "fetching scale set by ID") return params.ScaleSet{}, fmt.Errorf("error fetching scale set by ID: %w", err)
} }
return s.sqlToCommonScaleSet(set) return s.sqlToCommonScaleSet(set)
} }
@ -377,7 +377,7 @@ func (s *sqlDatabase) DeleteScaleSetByID(_ context.Context, scaleSetID uint) (er
err = s.conn.Transaction(func(tx *gorm.DB) error { err = s.conn.Transaction(func(tx *gorm.DB) error {
dbSet, err := s.getScaleSetByID(tx, scaleSetID, "Instances", "Enterprise", "Organization", "Repository") dbSet, err := s.getScaleSetByID(tx, scaleSetID, "Instances", "Enterprise", "Organization", "Repository")
if err != nil { if err != nil {
return errors.Wrap(err, "fetching scale set") return fmt.Errorf("error fetching scale set: %w", err)
} }
if len(dbSet.Instances) > 0 { if len(dbSet.Instances) > 0 {
@ -385,16 +385,16 @@ func (s *sqlDatabase) DeleteScaleSetByID(_ context.Context, scaleSetID uint) (er
} }
scaleSet, err = s.sqlToCommonScaleSet(dbSet) scaleSet, err = s.sqlToCommonScaleSet(dbSet)
if err != nil { if err != nil {
return errors.Wrap(err, "converting scale set") return fmt.Errorf("error converting scale set: %w", err)
} }
if q := tx.Unscoped().Delete(&dbSet); q.Error != nil { if q := tx.Unscoped().Delete(&dbSet); q.Error != nil {
return errors.Wrap(q.Error, "deleting scale set") return fmt.Errorf("error deleting scale set: %w", q.Error)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return errors.Wrap(err, "removing scale set") return fmt.Errorf("error removing scale set: %w", err)
} }
return nil return nil
} }
@ -409,19 +409,19 @@ func (s *sqlDatabase) SetScaleSetLastMessageID(_ context.Context, scaleSetID uin
if err := s.conn.Transaction(func(tx *gorm.DB) error { if err := s.conn.Transaction(func(tx *gorm.DB) error {
dbSet, err := s.getScaleSetByID(tx, scaleSetID, "Instances", "Enterprise", "Organization", "Repository") dbSet, err := s.getScaleSetByID(tx, scaleSetID, "Instances", "Enterprise", "Organization", "Repository")
if err != nil { if err != nil {
return errors.Wrap(err, "fetching scale set") return fmt.Errorf("error fetching scale set: %w", err)
} }
dbSet.LastMessageID = lastMessageID dbSet.LastMessageID = lastMessageID
if err := tx.Save(&dbSet).Error; err != nil { if err := tx.Save(&dbSet).Error; err != nil {
return errors.Wrap(err, "saving database entry") return fmt.Errorf("error saving database entry: %w", err)
} }
scaleSet, err = s.sqlToCommonScaleSet(dbSet) scaleSet, err = s.sqlToCommonScaleSet(dbSet)
if err != nil { if err != nil {
return errors.Wrap(err, "converting scale set") return fmt.Errorf("error converting scale set: %w", err)
} }
return nil return nil
}); err != nil { }); err != nil {
return errors.Wrap(err, "setting last message ID") return fmt.Errorf("error setting last message ID: %w", err)
} }
return nil return nil
} }
@ -436,19 +436,19 @@ func (s *sqlDatabase) SetScaleSetDesiredRunnerCount(_ context.Context, scaleSetI
if err := s.conn.Transaction(func(tx *gorm.DB) error { if err := s.conn.Transaction(func(tx *gorm.DB) error {
dbSet, err := s.getScaleSetByID(tx, scaleSetID, "Instances", "Enterprise", "Organization", "Repository") dbSet, err := s.getScaleSetByID(tx, scaleSetID, "Instances", "Enterprise", "Organization", "Repository")
if err != nil { if err != nil {
return errors.Wrap(err, "fetching scale set") return fmt.Errorf("error fetching scale set: %w", err)
} }
dbSet.DesiredRunnerCount = desiredRunnerCount dbSet.DesiredRunnerCount = desiredRunnerCount
if err := tx.Save(&dbSet).Error; err != nil { if err := tx.Save(&dbSet).Error; err != nil {
return errors.Wrap(err, "saving database entry") return fmt.Errorf("error saving database entry: %w", err)
} }
scaleSet, err = s.sqlToCommonScaleSet(dbSet) scaleSet, err = s.sqlToCommonScaleSet(dbSet)
if err != nil { if err != nil {
return errors.Wrap(err, "converting scale set") return fmt.Errorf("error converting scale set: %w", err)
} }
return nil return nil
}); err != nil { }); err != nil {
return errors.Wrap(err, "setting desired runner count") return fmt.Errorf("error setting desired runner count: %w", err)
} }
return nil return nil
} }

View file

@ -16,12 +16,12 @@ package sql
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"log/slog" "log/slog"
"net/url" "net/url"
"strings" "strings"
"github.com/pkg/errors"
"gorm.io/driver/mysql" "gorm.io/driver/mysql"
"gorm.io/driver/sqlite" "gorm.io/driver/sqlite"
"gorm.io/gorm" "gorm.io/gorm"
@ -46,7 +46,7 @@ const (
func newDBConn(dbCfg config.Database) (conn *gorm.DB, err error) { func newDBConn(dbCfg config.Database) (conn *gorm.DB, err error) {
dbType, connURI, err := dbCfg.GormParams() dbType, connURI, err := dbCfg.GormParams()
if err != nil { if err != nil {
return nil, errors.Wrap(err, "getting DB URI string") return nil, fmt.Errorf("error getting DB URI string: %w", err)
} }
gormConfig := &gorm.Config{} gormConfig := &gorm.Config{}
@ -61,7 +61,7 @@ func newDBConn(dbCfg config.Database) (conn *gorm.DB, err error) {
conn, err = gorm.Open(sqlite.Open(connURI), gormConfig) conn, err = gorm.Open(sqlite.Open(connURI), gormConfig)
} }
if err != nil { if err != nil {
return nil, errors.Wrap(err, "connecting to database") return nil, fmt.Errorf("error connecting to database: %w", err)
} }
if dbCfg.Debug { if dbCfg.Debug {
@ -73,11 +73,11 @@ func newDBConn(dbCfg config.Database) (conn *gorm.DB, err error) {
func NewSQLDatabase(ctx context.Context, cfg config.Database) (common.Store, error) { func NewSQLDatabase(ctx context.Context, cfg config.Database) (common.Store, error) {
conn, err := newDBConn(cfg) conn, err := newDBConn(cfg)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "creating DB connection") return nil, fmt.Errorf("error creating DB connection: %w", err)
} }
producer, err := watcher.RegisterProducer(ctx, "sql") producer, err := watcher.RegisterProducer(ctx, "sql")
if err != nil { if err != nil {
return nil, errors.Wrap(err, "registering producer") return nil, fmt.Errorf("error registering producer: %w", err)
} }
db := &sqlDatabase{ db := &sqlDatabase{
conn: conn, conn: conn,
@ -87,7 +87,7 @@ func NewSQLDatabase(ctx context.Context, cfg config.Database) (common.Store, err
} }
if err := db.migrateDB(); err != nil { if err := db.migrateDB(); err != nil {
return nil, errors.Wrap(err, "migrating database") return nil, fmt.Errorf("error migrating database: %w", err)
} }
return db, nil return db, nil
} }
@ -221,14 +221,14 @@ func (s *sqlDatabase) ensureGithubEndpoint() error {
var epCount int64 var epCount int64
if err := s.conn.Model(&GithubEndpoint{}).Count(&epCount).Error; err != nil { if err := s.conn.Model(&GithubEndpoint{}).Count(&epCount).Error; err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) { if !errors.Is(err, gorm.ErrRecordNotFound) {
return errors.Wrap(err, "counting github endpoints") return fmt.Errorf("error counting github endpoints: %w", err)
} }
} }
if epCount == 0 { if epCount == 0 {
if _, err := s.CreateGithubEndpoint(context.Background(), createEndpointParams); err != nil { if _, err := s.CreateGithubEndpoint(context.Background(), createEndpointParams); err != nil {
if !errors.Is(err, runnerErrors.ErrDuplicateEntity) { if !errors.Is(err, runnerErrors.ErrDuplicateEntity) {
return errors.Wrap(err, "creating default github endpoint") return fmt.Errorf("error creating default github endpoint: %w", err)
} }
} }
} }
@ -246,7 +246,7 @@ func (s *sqlDatabase) migrateCredentialsToDB() (err error) {
// Admin user doesn't exist. This is a new deploy. Nothing to migrate. // Admin user doesn't exist. This is a new deploy. Nothing to migrate.
return nil return nil
} }
return errors.Wrap(err, "getting admin user") return fmt.Errorf("error getting admin user: %w", err)
} }
// Impersonate the admin user. We're migrating from config credentials to // Impersonate the admin user. We're migrating from config credentials to
@ -259,7 +259,7 @@ func (s *sqlDatabase) migrateCredentialsToDB() (err error) {
slog.Info("migrating credentials to DB") slog.Info("migrating credentials to DB")
slog.Info("creating github endpoints table") slog.Info("creating github endpoints table")
if err := s.conn.AutoMigrate(&GithubEndpoint{}); err != nil { if err := s.conn.AutoMigrate(&GithubEndpoint{}); err != nil {
return errors.Wrap(err, "migrating github endpoints") return fmt.Errorf("error migrating github endpoints: %w", err)
} }
defer func() { defer func() {
@ -271,7 +271,7 @@ func (s *sqlDatabase) migrateCredentialsToDB() (err error) {
slog.Info("creating github credentials table") slog.Info("creating github credentials table")
if err := s.conn.AutoMigrate(&GithubCredentials{}); err != nil { if err := s.conn.AutoMigrate(&GithubCredentials{}); err != nil {
return errors.Wrap(err, "migrating github credentials") return fmt.Errorf("error migrating github credentials: %w", err)
} }
defer func() { defer func() {
@ -291,12 +291,12 @@ func (s *sqlDatabase) migrateCredentialsToDB() (err error) {
slog.Info("importing credential", "name", cred.Name) slog.Info("importing credential", "name", cred.Name)
parsed, err := url.Parse(cred.BaseEndpoint()) parsed, err := url.Parse(cred.BaseEndpoint())
if err != nil { if err != nil {
return errors.Wrap(err, "parsing base URL") return fmt.Errorf("error parsing base URL: %w", err)
} }
certBundle, err := cred.CACertBundle() certBundle, err := cred.CACertBundle()
if err != nil { if err != nil {
return errors.Wrap(err, "getting CA cert bundle") return fmt.Errorf("error getting CA cert bundle: %w", err)
} }
hostname := parsed.Hostname() hostname := parsed.Hostname()
createParams := params.CreateGithubEndpointParams{ createParams := params.CreateGithubEndpointParams{
@ -312,11 +312,11 @@ func (s *sqlDatabase) migrateCredentialsToDB() (err error) {
endpoint, err = s.GetGithubEndpoint(adminCtx, hostname) endpoint, err = s.GetGithubEndpoint(adminCtx, hostname)
if err != nil { if err != nil {
if !errors.Is(err, runnerErrors.ErrNotFound) { if !errors.Is(err, runnerErrors.ErrNotFound) {
return errors.Wrap(err, "getting github endpoint") return fmt.Errorf("error getting github endpoint: %w", err)
} }
endpoint, err = s.CreateGithubEndpoint(adminCtx, createParams) endpoint, err = s.CreateGithubEndpoint(adminCtx, createParams)
if err != nil { if err != nil {
return errors.Wrap(err, "creating default github endpoint") return fmt.Errorf("error creating default github endpoint: %w", err)
} }
} }
@ -330,7 +330,7 @@ func (s *sqlDatabase) migrateCredentialsToDB() (err error) {
case params.ForgeAuthTypeApp: case params.ForgeAuthTypeApp:
keyBytes, err := cred.App.PrivateKeyBytes() keyBytes, err := cred.App.PrivateKeyBytes()
if err != nil { if err != nil {
return errors.Wrap(err, "getting private key bytes") return fmt.Errorf("error getting private key bytes: %w", err)
} }
credParams.App = params.GithubApp{ credParams.App = params.GithubApp{
AppID: cred.App.AppID, AppID: cred.App.AppID,
@ -339,7 +339,7 @@ func (s *sqlDatabase) migrateCredentialsToDB() (err error) {
} }
if err := credParams.App.Validate(); err != nil { if err := credParams.App.Validate(); err != nil {
return errors.Wrap(err, "validating app credentials") return fmt.Errorf("error validating app credentials: %w", err)
} }
case params.ForgeAuthTypePAT: case params.ForgeAuthTypePAT:
token := cred.PAT.OAuth2Token token := cred.PAT.OAuth2Token
@ -356,19 +356,19 @@ func (s *sqlDatabase) migrateCredentialsToDB() (err error) {
creds, err := s.CreateGithubCredentials(adminCtx, credParams) creds, err := s.CreateGithubCredentials(adminCtx, credParams)
if err != nil { if err != nil {
return errors.Wrap(err, "creating github credentials") return fmt.Errorf("error creating github credentials: %w", err)
} }
if err := s.conn.Exec("update repositories set credentials_id = ?,endpoint_name = ? where credentials_name = ?", creds.ID, creds.Endpoint.Name, creds.Name).Error; err != nil { if err := s.conn.Exec("update repositories set credentials_id = ?,endpoint_name = ? where credentials_name = ?", creds.ID, creds.Endpoint.Name, creds.Name).Error; err != nil {
return errors.Wrap(err, "updating repositories") return fmt.Errorf("error updating repositories: %w", err)
} }
if err := s.conn.Exec("update organizations set credentials_id = ?,endpoint_name = ? where credentials_name = ?", creds.ID, creds.Endpoint.Name, creds.Name).Error; err != nil { if err := s.conn.Exec("update organizations set credentials_id = ?,endpoint_name = ? where credentials_name = ?", creds.ID, creds.Endpoint.Name, creds.Name).Error; err != nil {
return errors.Wrap(err, "updating organizations") return fmt.Errorf("error updating organizations: %w", err)
} }
if err := s.conn.Exec("update enterprises set credentials_id = ?,endpoint_name = ? where credentials_name = ?", creds.ID, creds.Endpoint.Name, creds.Name).Error; err != nil { if err := s.conn.Exec("update enterprises set credentials_id = ?,endpoint_name = ? where credentials_name = ?", creds.ID, creds.Endpoint.Name, creds.Name).Error; err != nil {
return errors.Wrap(err, "updating enterprises") return fmt.Errorf("error updating enterprises: %w", err)
} }
} }
return nil return nil
@ -380,10 +380,10 @@ func (s *sqlDatabase) migrateWorkflow() error {
// Remove jobs that are not in "queued" status. We really only care about queued jobs. Once they transition // Remove jobs that are not in "queued" status. We really only care about queued jobs. Once they transition
// to something else, we don't really consume them anyway. // to something else, we don't really consume them anyway.
if err := s.conn.Exec("delete from workflow_jobs where status is not 'queued'").Error; err != nil { if err := s.conn.Exec("delete from workflow_jobs where status is not 'queued'").Error; err != nil {
return errors.Wrap(err, "updating workflow_jobs") return fmt.Errorf("error updating workflow_jobs: %w", err)
} }
if err := s.conn.Migrator().DropColumn(&WorkflowJob{}, "runner_name"); err != nil { if err := s.conn.Migrator().DropColumn(&WorkflowJob{}, "runner_name"); err != nil {
return errors.Wrap(err, "updating workflow_jobs") return fmt.Errorf("error updating workflow_jobs: %w", err)
} }
} }
} }
@ -404,34 +404,34 @@ func (s *sqlDatabase) migrateDB() error {
} }
if err := s.cascadeMigration(); err != nil { if err := s.cascadeMigration(); err != nil {
return errors.Wrap(err, "running cascade migration") return fmt.Errorf("error running cascade migration: %w", err)
} }
if s.conn.Migrator().HasTable(&Pool{}) { if s.conn.Migrator().HasTable(&Pool{}) {
if err := s.conn.Exec("update pools set repo_id=NULL where repo_id='00000000-0000-0000-0000-000000000000'").Error; err != nil { if err := s.conn.Exec("update pools set repo_id=NULL where repo_id='00000000-0000-0000-0000-000000000000'").Error; err != nil {
return errors.Wrap(err, "updating pools") return fmt.Errorf("error updating pools %w", err)
} }
if err := s.conn.Exec("update pools set org_id=NULL where org_id='00000000-0000-0000-0000-000000000000'").Error; err != nil { if err := s.conn.Exec("update pools set org_id=NULL where org_id='00000000-0000-0000-0000-000000000000'").Error; err != nil {
return errors.Wrap(err, "updating pools") return fmt.Errorf("error updating pools: %w", err)
} }
if err := s.conn.Exec("update pools set enterprise_id=NULL where enterprise_id='00000000-0000-0000-0000-000000000000'").Error; err != nil { if err := s.conn.Exec("update pools set enterprise_id=NULL where enterprise_id='00000000-0000-0000-0000-000000000000'").Error; err != nil {
return errors.Wrap(err, "updating pools") return fmt.Errorf("error updating pools: %w", err)
} }
} }
if err := s.migrateWorkflow(); err != nil { if err := s.migrateWorkflow(); err != nil {
return errors.Wrap(err, "migrating workflows") return fmt.Errorf("error migrating workflows: %w", err)
} }
if s.conn.Migrator().HasTable(&GithubEndpoint{}) { if s.conn.Migrator().HasTable(&GithubEndpoint{}) {
if !s.conn.Migrator().HasColumn(&GithubEndpoint{}, "endpoint_type") { if !s.conn.Migrator().HasColumn(&GithubEndpoint{}, "endpoint_type") {
if err := s.conn.Migrator().AutoMigrate(&GithubEndpoint{}); err != nil { if err := s.conn.Migrator().AutoMigrate(&GithubEndpoint{}); err != nil {
return errors.Wrap(err, "migrating github endpoints") return fmt.Errorf("error migrating github endpoints: %w", err)
} }
if err := s.conn.Exec("update github_endpoints set endpoint_type = 'github' where endpoint_type is null").Error; err != nil { if err := s.conn.Exec("update github_endpoints set endpoint_type = 'github' where endpoint_type is null").Error; err != nil {
return errors.Wrap(err, "updating github endpoints") return fmt.Errorf("error updating github endpoints: %w", err)
} }
} }
} }
@ -467,7 +467,7 @@ func (s *sqlDatabase) migrateDB() error {
&WorkflowJob{}, &WorkflowJob{},
&ScaleSet{}, &ScaleSet{},
); err != nil { ); err != nil {
return errors.Wrap(err, "running auto migrate") return fmt.Errorf("error running auto migrate: %w", err)
} }
s.conn.Exec("PRAGMA foreign_keys = ON") s.conn.Exec("PRAGMA foreign_keys = ON")
@ -475,23 +475,23 @@ func (s *sqlDatabase) migrateDB() error {
var controller ControllerInfo var controller ControllerInfo
if err := s.conn.First(&controller).Error; err != nil { if err := s.conn.First(&controller).Error; err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) { if !errors.Is(err, gorm.ErrRecordNotFound) {
return errors.Wrap(err, "updating controller info") return fmt.Errorf("error updating controller info: %w", err)
} }
} else { } else {
controller.MinimumJobAgeBackoff = 30 controller.MinimumJobAgeBackoff = 30
if err := s.conn.Save(&controller).Error; err != nil { if err := s.conn.Save(&controller).Error; err != nil {
return errors.Wrap(err, "updating controller info") return fmt.Errorf("error updating controller info: %w", err)
} }
} }
} }
if err := s.ensureGithubEndpoint(); err != nil { if err := s.ensureGithubEndpoint(); err != nil {
return errors.Wrap(err, "ensuring github endpoint") return fmt.Errorf("error ensuring github endpoint: %w", err)
} }
if needsCredentialMigration { if needsCredentialMigration {
if err := s.migrateCredentialsToDB(); err != nil { if err := s.migrateCredentialsToDB(); err != nil {
return errors.Wrap(err, "migrating credentials") return fmt.Errorf("error migrating credentials: %w", err)
} }
} }
return nil return nil

View file

@ -16,9 +16,9 @@ package sql
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"github.com/pkg/errors"
"gorm.io/gorm" "gorm.io/gorm"
runnerErrors "github.com/cloudbase/garm-provider-common/errors" runnerErrors "github.com/cloudbase/garm-provider-common/errors"
@ -39,7 +39,7 @@ func (s *sqlDatabase) getUserByUsernameOrEmail(tx *gorm.DB, user string) (User,
if errors.Is(q.Error, gorm.ErrRecordNotFound) { if errors.Is(q.Error, gorm.ErrRecordNotFound) {
return User{}, runnerErrors.ErrNotFound return User{}, runnerErrors.ErrNotFound
} }
return User{}, errors.Wrap(q.Error, "fetching user") return User{}, fmt.Errorf("error fetching user: %w", q.Error)
} }
return dbUser, nil return dbUser, nil
} }
@ -51,7 +51,7 @@ func (s *sqlDatabase) getUserByID(tx *gorm.DB, userID string) (User, error) {
if errors.Is(q.Error, gorm.ErrRecordNotFound) { if errors.Is(q.Error, gorm.ErrRecordNotFound) {
return User{}, runnerErrors.ErrNotFound return User{}, runnerErrors.ErrNotFound
} }
return User{}, errors.Wrap(q.Error, "fetching user") return User{}, fmt.Errorf("error fetching user: %w", q.Error)
} }
return dbUser, nil return dbUser, nil
} }
@ -82,12 +82,12 @@ func (s *sqlDatabase) CreateUser(_ context.Context, user params.NewUserParams) (
q := tx.Save(&newUser) q := tx.Save(&newUser)
if q.Error != nil { if q.Error != nil {
return errors.Wrap(q.Error, "creating user") return fmt.Errorf("error creating user: %w", q.Error)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return params.User{}, errors.Wrap(err, "creating user") return params.User{}, fmt.Errorf("error creating user: %w", err)
} }
return s.sqlToParamsUser(newUser), nil return s.sqlToParamsUser(newUser), nil
} }
@ -105,7 +105,7 @@ func (s *sqlDatabase) HasAdminUser(_ context.Context) bool {
func (s *sqlDatabase) GetUser(_ context.Context, user string) (params.User, error) { func (s *sqlDatabase) GetUser(_ context.Context, user string) (params.User, error) {
dbUser, err := s.getUserByUsernameOrEmail(s.conn, user) dbUser, err := s.getUserByUsernameOrEmail(s.conn, user)
if err != nil { if err != nil {
return params.User{}, errors.Wrap(err, "fetching user") return params.User{}, fmt.Errorf("error fetching user: %w", err)
} }
return s.sqlToParamsUser(dbUser), nil return s.sqlToParamsUser(dbUser), nil
} }
@ -113,7 +113,7 @@ func (s *sqlDatabase) GetUser(_ context.Context, user string) (params.User, erro
func (s *sqlDatabase) GetUserByID(_ context.Context, userID string) (params.User, error) { func (s *sqlDatabase) GetUserByID(_ context.Context, userID string) (params.User, error) {
dbUser, err := s.getUserByID(s.conn, userID) dbUser, err := s.getUserByID(s.conn, userID)
if err != nil { if err != nil {
return params.User{}, errors.Wrap(err, "fetching user") return params.User{}, fmt.Errorf("error fetching user: %w", err)
} }
return s.sqlToParamsUser(dbUser), nil return s.sqlToParamsUser(dbUser), nil
} }
@ -124,7 +124,7 @@ func (s *sqlDatabase) UpdateUser(_ context.Context, user string, param params.Up
err = s.conn.Transaction(func(tx *gorm.DB) error { err = s.conn.Transaction(func(tx *gorm.DB) error {
dbUser, err = s.getUserByUsernameOrEmail(tx, user) dbUser, err = s.getUserByUsernameOrEmail(tx, user)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching user") return fmt.Errorf("error fetching user: %w", err)
} }
if param.FullName != "" { if param.FullName != "" {
@ -141,12 +141,12 @@ func (s *sqlDatabase) UpdateUser(_ context.Context, user string, param params.Up
} }
if q := tx.Save(&dbUser); q.Error != nil { if q := tx.Save(&dbUser); q.Error != nil {
return errors.Wrap(q.Error, "saving user") return fmt.Errorf("error saving user: %w", q.Error)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return params.User{}, errors.Wrap(err, "updating user") return params.User{}, fmt.Errorf("error updating user: %w", err)
} }
return s.sqlToParamsUser(dbUser), nil return s.sqlToParamsUser(dbUser), nil
} }
@ -159,7 +159,7 @@ func (s *sqlDatabase) GetAdminUser(_ context.Context) (params.User, error) {
if errors.Is(q.Error, gorm.ErrRecordNotFound) { if errors.Is(q.Error, gorm.ErrRecordNotFound) {
return params.User{}, runnerErrors.ErrNotFound return params.User{}, runnerErrors.ErrNotFound
} }
return params.User{}, errors.Wrap(q.Error, "fetching admin user") return params.User{}, fmt.Errorf("error fetching admin user: %w", q.Error)
} }
return s.sqlToParamsUser(user), nil return s.sqlToParamsUser(user), nil
} }

View file

@ -161,7 +161,7 @@ func (s *UserTestSuite) TestCreateUserUsernameAlreadyExist() {
_, err := s.Store.CreateUser(context.Background(), s.Fixtures.NewUserParams) _, err := s.Store.CreateUser(context.Background(), s.Fixtures.NewUserParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal(("creating user: username already exists"), err.Error()) s.Require().Equal(("error creating user: username already exists"), err.Error())
} }
func (s *UserTestSuite) TestCreateUserEmailAlreadyExist() { func (s *UserTestSuite) TestCreateUserEmailAlreadyExist() {
@ -170,7 +170,7 @@ func (s *UserTestSuite) TestCreateUserEmailAlreadyExist() {
_, err := s.Store.CreateUser(context.Background(), s.Fixtures.NewUserParams) _, err := s.Store.CreateUser(context.Background(), s.Fixtures.NewUserParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal(("creating user: email already exists"), err.Error()) s.Require().Equal(("error creating user: email already exists"), err.Error())
} }
func (s *UserTestSuite) TestCreateUserDBCreateErr() { func (s *UserTestSuite) TestCreateUserDBCreateErr() {
@ -191,7 +191,7 @@ func (s *UserTestSuite) TestCreateUserDBCreateErr() {
_, err := s.StoreSQLMocked.CreateUser(context.Background(), s.Fixtures.NewUserParams) _, err := s.StoreSQLMocked.CreateUser(context.Background(), s.Fixtures.NewUserParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("creating user: creating user: creating user mock error", err.Error()) s.Require().Equal("error creating user: error creating user: creating user mock error", err.Error())
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
} }
@ -230,7 +230,7 @@ func (s *UserTestSuite) TestGetUserNotFound() {
_, err := s.Store.GetUser(context.Background(), "dummy-user") _, err := s.Store.GetUser(context.Background(), "dummy-user")
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching user: not found", err.Error()) s.Require().Equal("error fetching user: not found", err.Error())
} }
func (s *UserTestSuite) TestGetUserByID() { func (s *UserTestSuite) TestGetUserByID() {
@ -244,7 +244,7 @@ func (s *UserTestSuite) TestGetUserByIDNotFound() {
_, err := s.Store.GetUserByID(context.Background(), "dummy-user-id") _, err := s.Store.GetUserByID(context.Background(), "dummy-user-id")
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching user: not found", err.Error()) s.Require().Equal("error fetching user: not found", err.Error())
} }
func (s *UserTestSuite) TestUpdateUser() { func (s *UserTestSuite) TestUpdateUser() {
@ -260,7 +260,7 @@ func (s *UserTestSuite) TestUpdateUserNotFound() {
_, err := s.Store.UpdateUser(context.Background(), "dummy-user", s.Fixtures.UpdateUserParams) _, err := s.Store.UpdateUser(context.Background(), "dummy-user", s.Fixtures.UpdateUserParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("updating user: fetching user: not found", err.Error()) s.Require().Equal("error updating user: error fetching user: not found", err.Error())
} }
func (s *UserTestSuite) TestUpdateUserDBSaveErr() { func (s *UserTestSuite) TestUpdateUserDBSaveErr() {
@ -278,7 +278,7 @@ func (s *UserTestSuite) TestUpdateUserDBSaveErr() {
s.assertSQLMockExpectations() s.assertSQLMockExpectations()
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("updating user: saving user: saving user mock error", err.Error()) s.Require().Equal("error updating user: error saving user: saving user mock error", err.Error())
} }
func TestUserTestSuite(t *testing.T) { func TestUserTestSuite(t *testing.T) {

View file

@ -17,10 +17,10 @@ package sql
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/pkg/errors"
"gorm.io/datatypes" "gorm.io/datatypes"
"gorm.io/gorm" "gorm.io/gorm"
@ -41,14 +41,14 @@ func (s *sqlDatabase) sqlToParamsInstance(instance Instance) (params.Instance, e
var labels []string var labels []string
if len(instance.AditionalLabels) > 0 { if len(instance.AditionalLabels) > 0 {
if err := json.Unmarshal(instance.AditionalLabels, &labels); err != nil { if err := json.Unmarshal(instance.AditionalLabels, &labels); err != nil {
return params.Instance{}, errors.Wrap(err, "unmarshalling labels") return params.Instance{}, fmt.Errorf("error unmarshalling labels: %w", err)
} }
} }
var jitConfig map[string]string var jitConfig map[string]string
if len(instance.JitConfiguration) > 0 { if len(instance.JitConfiguration) > 0 {
if err := s.unsealAndUnmarshal(instance.JitConfiguration, &jitConfig); err != nil { if err := s.unsealAndUnmarshal(instance.JitConfiguration, &jitConfig); err != nil {
return params.Instance{}, errors.Wrap(err, "unmarshalling jit configuration") return params.Instance{}, fmt.Errorf("error unmarshalling jit configuration: %w", err)
} }
} }
ret := params.Instance{ ret := params.Instance{
@ -95,7 +95,7 @@ func (s *sqlDatabase) sqlToParamsInstance(instance Instance) (params.Instance, e
if instance.Job != nil { if instance.Job != nil {
paramJob, err := sqlWorkflowJobToParamsJob(*instance.Job) paramJob, err := sqlWorkflowJobToParamsJob(*instance.Job)
if err != nil { if err != nil {
return params.Instance{}, errors.Wrap(err, "converting job") return params.Instance{}, fmt.Errorf("error converting job: %w", err)
} }
ret.Job = &paramJob ret.Job = &paramJob
} }
@ -132,12 +132,12 @@ func (s *sqlDatabase) sqlToCommonOrganization(org Organization, detailed bool) (
} }
secret, err := util.Unseal(org.WebhookSecret, []byte(s.cfg.Passphrase)) secret, err := util.Unseal(org.WebhookSecret, []byte(s.cfg.Passphrase))
if err != nil { if err != nil {
return params.Organization{}, errors.Wrap(err, "decrypting secret") return params.Organization{}, fmt.Errorf("error decrypting secret: %w", err)
} }
endpoint, err := s.sqlToCommonGithubEndpoint(org.Endpoint) endpoint, err := s.sqlToCommonGithubEndpoint(org.Endpoint)
if err != nil { if err != nil {
return params.Organization{}, errors.Wrap(err, "converting endpoint") return params.Organization{}, fmt.Errorf("error converting endpoint: %w", err)
} }
ret := params.Organization{ ret := params.Organization{
ID: org.ID.String(), ID: org.ID.String(),
@ -163,7 +163,7 @@ func (s *sqlDatabase) sqlToCommonOrganization(org Organization, detailed bool) (
} }
if err != nil { if err != nil {
return params.Organization{}, errors.Wrap(err, "converting credentials") return params.Organization{}, fmt.Errorf("error converting credentials: %w", err)
} }
if len(org.Events) > 0 { if len(org.Events) > 0 {
@ -191,7 +191,7 @@ func (s *sqlDatabase) sqlToCommonOrganization(org Organization, detailed bool) (
for idx, pool := range org.Pools { for idx, pool := range org.Pools {
ret.Pools[idx], err = s.sqlToCommonPool(pool) ret.Pools[idx], err = s.sqlToCommonPool(pool)
if err != nil { if err != nil {
return params.Organization{}, errors.Wrap(err, "converting pool") return params.Organization{}, fmt.Errorf("error converting pool: %w", err)
} }
} }
@ -204,12 +204,12 @@ func (s *sqlDatabase) sqlToCommonEnterprise(enterprise Enterprise, detailed bool
} }
secret, err := util.Unseal(enterprise.WebhookSecret, []byte(s.cfg.Passphrase)) secret, err := util.Unseal(enterprise.WebhookSecret, []byte(s.cfg.Passphrase))
if err != nil { if err != nil {
return params.Enterprise{}, errors.Wrap(err, "decrypting secret") return params.Enterprise{}, fmt.Errorf("error decrypting secret: %w", err)
} }
endpoint, err := s.sqlToCommonGithubEndpoint(enterprise.Endpoint) endpoint, err := s.sqlToCommonGithubEndpoint(enterprise.Endpoint)
if err != nil { if err != nil {
return params.Enterprise{}, errors.Wrap(err, "converting endpoint") return params.Enterprise{}, fmt.Errorf("error converting endpoint: %w", err)
} }
ret := params.Enterprise{ ret := params.Enterprise{
ID: enterprise.ID.String(), ID: enterprise.ID.String(),
@ -243,7 +243,7 @@ func (s *sqlDatabase) sqlToCommonEnterprise(enterprise Enterprise, detailed bool
if detailed { if detailed {
creds, err := s.sqlToCommonForgeCredentials(enterprise.Credentials) creds, err := s.sqlToCommonForgeCredentials(enterprise.Credentials)
if err != nil { if err != nil {
return params.Enterprise{}, errors.Wrap(err, "converting credentials") return params.Enterprise{}, fmt.Errorf("error converting credentials: %w", err)
} }
ret.Credentials = creds ret.Credentials = creds
} }
@ -255,7 +255,7 @@ func (s *sqlDatabase) sqlToCommonEnterprise(enterprise Enterprise, detailed bool
for idx, pool := range enterprise.Pools { for idx, pool := range enterprise.Pools {
ret.Pools[idx], err = s.sqlToCommonPool(pool) ret.Pools[idx], err = s.sqlToCommonPool(pool)
if err != nil { if err != nil {
return params.Enterprise{}, errors.Wrap(err, "converting pool") return params.Enterprise{}, fmt.Errorf("error converting pool: %w", err)
} }
} }
@ -309,7 +309,7 @@ func (s *sqlDatabase) sqlToCommonPool(pool Pool) (params.Pool, error) {
endpoint, err := s.sqlToCommonGithubEndpoint(ep) endpoint, err := s.sqlToCommonGithubEndpoint(ep)
if err != nil { if err != nil {
return params.Pool{}, errors.Wrap(err, "converting endpoint") return params.Pool{}, fmt.Errorf("error converting endpoint: %w", err)
} }
ret.Endpoint = endpoint ret.Endpoint = endpoint
@ -320,7 +320,7 @@ func (s *sqlDatabase) sqlToCommonPool(pool Pool) (params.Pool, error) {
for idx, inst := range pool.Instances { for idx, inst := range pool.Instances {
ret.Instances[idx], err = s.sqlToParamsInstance(inst) ret.Instances[idx], err = s.sqlToParamsInstance(inst)
if err != nil { if err != nil {
return params.Pool{}, errors.Wrap(err, "converting instance") return params.Pool{}, fmt.Errorf("error converting instance: %w", err)
} }
} }
@ -380,14 +380,14 @@ func (s *sqlDatabase) sqlToCommonScaleSet(scaleSet ScaleSet) (params.ScaleSet, e
endpoint, err := s.sqlToCommonGithubEndpoint(ep) endpoint, err := s.sqlToCommonGithubEndpoint(ep)
if err != nil { if err != nil {
return params.ScaleSet{}, errors.Wrap(err, "converting endpoint") return params.ScaleSet{}, fmt.Errorf("error converting endpoint: %w", err)
} }
ret.Endpoint = endpoint ret.Endpoint = endpoint
for idx, inst := range scaleSet.Instances { for idx, inst := range scaleSet.Instances {
ret.Instances[idx], err = s.sqlToParamsInstance(inst) ret.Instances[idx], err = s.sqlToParamsInstance(inst)
if err != nil { if err != nil {
return params.ScaleSet{}, errors.Wrap(err, "converting instance") return params.ScaleSet{}, fmt.Errorf("error converting instance: %w", err)
} }
} }
@ -407,11 +407,11 @@ func (s *sqlDatabase) sqlToCommonRepository(repo Repository, detailed bool) (par
} }
secret, err := util.Unseal(repo.WebhookSecret, []byte(s.cfg.Passphrase)) secret, err := util.Unseal(repo.WebhookSecret, []byte(s.cfg.Passphrase))
if err != nil { if err != nil {
return params.Repository{}, errors.Wrap(err, "decrypting secret") return params.Repository{}, fmt.Errorf("error decrypting secret: %w", err)
} }
endpoint, err := s.sqlToCommonGithubEndpoint(repo.Endpoint) endpoint, err := s.sqlToCommonGithubEndpoint(repo.Endpoint)
if err != nil { if err != nil {
return params.Repository{}, errors.Wrap(err, "converting endpoint") return params.Repository{}, fmt.Errorf("error converting endpoint: %w", err)
} }
ret := params.Repository{ ret := params.Repository{
ID: repo.ID.String(), ID: repo.ID.String(),
@ -442,7 +442,7 @@ func (s *sqlDatabase) sqlToCommonRepository(repo Repository, detailed bool) (par
} }
if err != nil { if err != nil {
return params.Repository{}, errors.Wrap(err, "converting credentials") return params.Repository{}, fmt.Errorf("error converting credentials: %w", err)
} }
if len(repo.Events) > 0 { if len(repo.Events) > 0 {
@ -470,7 +470,7 @@ func (s *sqlDatabase) sqlToCommonRepository(repo Repository, detailed bool) (par
for idx, pool := range repo.Pools { for idx, pool := range repo.Pools {
ret.Pools[idx], err = s.sqlToCommonPool(pool) ret.Pools[idx], err = s.sqlToCommonPool(pool)
if err != nil { if err != nil {
return params.Repository{}, errors.Wrap(err, "converting pool") return params.Repository{}, fmt.Errorf("error converting pool: %w", err)
} }
} }
@ -499,14 +499,14 @@ func (s *sqlDatabase) getOrCreateTag(tx *gorm.DB, tagName string) (Tag, error) {
return tag, nil return tag, nil
} }
if !errors.Is(q.Error, gorm.ErrRecordNotFound) { if !errors.Is(q.Error, gorm.ErrRecordNotFound) {
return Tag{}, errors.Wrap(q.Error, "fetching tag from database") return Tag{}, fmt.Errorf("error fetching tag from database: %w", q.Error)
} }
newTag := Tag{ newTag := Tag{
Name: tagName, Name: tagName,
} }
if err := tx.Create(&newTag).Error; err != nil { if err := tx.Create(&newTag).Error; err != nil {
return Tag{}, errors.Wrap(err, "creating tag") return Tag{}, fmt.Errorf("error creating tag: %w", err)
} }
return newTag, nil return newTag, nil
} }
@ -561,7 +561,7 @@ func (s *sqlDatabase) updatePool(tx *gorm.DB, pool Pool, param params.UpdatePool
} }
if q := tx.Save(&pool); q.Error != nil { if q := tx.Save(&pool); q.Error != nil {
return params.Pool{}, errors.Wrap(q.Error, "saving database entry") return params.Pool{}, fmt.Errorf("error saving database entry: %w", q.Error)
} }
tags := []Tag{} tags := []Tag{}
@ -569,13 +569,13 @@ func (s *sqlDatabase) updatePool(tx *gorm.DB, pool Pool, param params.UpdatePool
for _, val := range param.Tags { for _, val := range param.Tags {
t, err := s.getOrCreateTag(tx, val) t, err := s.getOrCreateTag(tx, val)
if err != nil { if err != nil {
return params.Pool{}, errors.Wrap(err, "fetching tag") return params.Pool{}, fmt.Errorf("error fetching tag: %w", err)
} }
tags = append(tags, t) tags = append(tags, t)
} }
if err := tx.Model(&pool).Association("Tags").Replace(&tags); err != nil { if err := tx.Model(&pool).Association("Tags").Replace(&tags); err != nil {
return params.Pool{}, errors.Wrap(err, "replacing tags") return params.Pool{}, fmt.Errorf("error replacing tags: %w", err)
} }
} }
@ -585,7 +585,7 @@ func (s *sqlDatabase) updatePool(tx *gorm.DB, pool Pool, param params.UpdatePool
func (s *sqlDatabase) getPoolByID(tx *gorm.DB, poolID string, preload ...string) (Pool, error) { func (s *sqlDatabase) getPoolByID(tx *gorm.DB, poolID string, preload ...string) (Pool, error) {
u, err := uuid.Parse(poolID) u, err := uuid.Parse(poolID)
if err != nil { if err != nil {
return Pool{}, errors.Wrap(runnerErrors.ErrBadRequest, "parsing id") return Pool{}, fmt.Errorf("error parsing id: %w", runnerErrors.ErrBadRequest)
} }
var pool Pool var pool Pool
q := tx.Model(&Pool{}) q := tx.Model(&Pool{})
@ -601,7 +601,7 @@ func (s *sqlDatabase) getPoolByID(tx *gorm.DB, poolID string, preload ...string)
if errors.Is(q.Error, gorm.ErrRecordNotFound) { if errors.Is(q.Error, gorm.ErrRecordNotFound) {
return Pool{}, runnerErrors.ErrNotFound return Pool{}, runnerErrors.ErrNotFound
} }
return Pool{}, errors.Wrap(q.Error, "fetching org from database") return Pool{}, fmt.Errorf("error fetching org from database: %w", q.Error)
} }
return pool, nil return pool, nil
} }
@ -621,7 +621,7 @@ func (s *sqlDatabase) getScaleSetByID(tx *gorm.DB, scaleSetID uint, preload ...s
if errors.Is(q.Error, gorm.ErrRecordNotFound) { if errors.Is(q.Error, gorm.ErrRecordNotFound) {
return ScaleSet{}, runnerErrors.ErrNotFound return ScaleSet{}, runnerErrors.ErrNotFound
} }
return ScaleSet{}, errors.Wrap(q.Error, "fetching scale set from database") return ScaleSet{}, fmt.Errorf("error fetching scale set from database: %w", q.Error)
} }
return scaleSet, nil return scaleSet, nil
} }
@ -629,7 +629,7 @@ func (s *sqlDatabase) getScaleSetByID(tx *gorm.DB, scaleSetID uint, preload ...s
func (s *sqlDatabase) hasGithubEntity(tx *gorm.DB, entityType params.ForgeEntityType, entityID string) error { func (s *sqlDatabase) hasGithubEntity(tx *gorm.DB, entityType params.ForgeEntityType, entityID string) error {
u, err := uuid.Parse(entityID) u, err := uuid.Parse(entityID)
if err != nil { if err != nil {
return errors.Wrap(runnerErrors.ErrBadRequest, "parsing id") return fmt.Errorf("error parsing id: %w", runnerErrors.ErrBadRequest)
} }
var q *gorm.DB var q *gorm.DB
switch entityType { switch entityType {
@ -640,15 +640,15 @@ func (s *sqlDatabase) hasGithubEntity(tx *gorm.DB, entityType params.ForgeEntity
case params.ForgeEntityTypeEnterprise: case params.ForgeEntityTypeEnterprise:
q = tx.Model(&Enterprise{}).Where("id = ?", u) q = tx.Model(&Enterprise{}).Where("id = ?", u)
default: default:
return errors.Wrap(runnerErrors.ErrBadRequest, "invalid entity type") return fmt.Errorf("error invalid entity type: %w", runnerErrors.ErrBadRequest)
} }
var entity interface{} var entity interface{}
if err := q.First(entity).Error; err != nil { if err := q.First(entity).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return errors.Wrap(runnerErrors.ErrNotFound, "entity not found") return fmt.Errorf("error entity not found: %w", runnerErrors.ErrNotFound)
} }
return errors.Wrap(err, "fetching entity from database") return fmt.Errorf("error fetching entity from database: %w", err)
} }
return nil return nil
} }
@ -656,7 +656,7 @@ func (s *sqlDatabase) hasGithubEntity(tx *gorm.DB, entityType params.ForgeEntity
func (s *sqlDatabase) marshalAndSeal(data interface{}) ([]byte, error) { func (s *sqlDatabase) marshalAndSeal(data interface{}) ([]byte, error) {
enc, err := json.Marshal(data) enc, err := json.Marshal(data)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "marshalling data") return nil, fmt.Errorf("error marshalling data: %w", err)
} }
return util.Seal(enc, []byte(s.cfg.Passphrase)) return util.Seal(enc, []byte(s.cfg.Passphrase))
} }
@ -664,10 +664,10 @@ func (s *sqlDatabase) marshalAndSeal(data interface{}) ([]byte, error) {
func (s *sqlDatabase) unsealAndUnmarshal(data []byte, target interface{}) error { func (s *sqlDatabase) unsealAndUnmarshal(data []byte, target interface{}) error {
decrypted, err := util.Unseal(data, []byte(s.cfg.Passphrase)) decrypted, err := util.Unseal(data, []byte(s.cfg.Passphrase))
if err != nil { if err != nil {
return errors.Wrap(err, "decrypting data") return fmt.Errorf("error decrypting data: %w", err)
} }
if err := json.Unmarshal(decrypted, target); err != nil { if err := json.Unmarshal(decrypted, target); err != nil {
return errors.Wrap(err, "unmarshalling data") return fmt.Errorf("error unmarshalling data: %w", err)
} }
return nil return nil
} }
@ -699,15 +699,15 @@ func (s *sqlDatabase) GetForgeEntity(_ context.Context, entityType params.ForgeE
case params.ForgeEntityTypeRepository: case params.ForgeEntityTypeRepository:
ghEntity, err = s.GetRepositoryByID(s.ctx, entityID) ghEntity, err = s.GetRepositoryByID(s.ctx, entityID)
default: default:
return params.ForgeEntity{}, errors.Wrap(runnerErrors.ErrBadRequest, "invalid entity type") return params.ForgeEntity{}, fmt.Errorf("error invalid entity type: %w", runnerErrors.ErrBadRequest)
} }
if err != nil { if err != nil {
return params.ForgeEntity{}, errors.Wrap(err, "failed to get ") return params.ForgeEntity{}, fmt.Errorf("error failed to get entity from db: %w", err)
} }
entity, err := ghEntity.GetEntity() entity, err := ghEntity.GetEntity()
if err != nil { if err != nil {
return params.ForgeEntity{}, errors.Wrap(err, "failed to get entity") return params.ForgeEntity{}, fmt.Errorf("error failed to get entity: %w", err)
} }
return entity, nil return entity, nil
} }
@ -715,7 +715,7 @@ func (s *sqlDatabase) GetForgeEntity(_ context.Context, entityType params.ForgeE
func (s *sqlDatabase) addRepositoryEvent(ctx context.Context, repoID string, event params.EventType, eventLevel params.EventLevel, statusMessage string, maxEvents int) error { func (s *sqlDatabase) addRepositoryEvent(ctx context.Context, repoID string, event params.EventType, eventLevel params.EventLevel, statusMessage string, maxEvents int) error {
repo, err := s.getRepoByID(ctx, s.conn, repoID) repo, err := s.getRepoByID(ctx, s.conn, repoID)
if err != nil { if err != nil {
return errors.Wrap(err, "updating instance") return fmt.Errorf("error updating instance: %w", err)
} }
msg := RepositoryEvent{ msg := RepositoryEvent{
@ -725,7 +725,7 @@ func (s *sqlDatabase) addRepositoryEvent(ctx context.Context, repoID string, eve
} }
if err := s.conn.Model(&repo).Association("Events").Append(&msg); err != nil { if err := s.conn.Model(&repo).Association("Events").Append(&msg); err != nil {
return errors.Wrap(err, "adding status message") return fmt.Errorf("error adding status message: %w", err)
} }
if maxEvents > 0 { if maxEvents > 0 {
@ -734,12 +734,12 @@ func (s *sqlDatabase) addRepositoryEvent(ctx context.Context, repoID string, eve
Limit(maxEvents).Order("id desc"). Limit(maxEvents).Order("id desc").
Where("repo_id = ?", repo.ID).Find(&latestEvents) Where("repo_id = ?", repo.ID).Find(&latestEvents)
if q.Error != nil { if q.Error != nil {
return errors.Wrap(q.Error, "fetching latest events") return fmt.Errorf("error fetching latest events: %w", q.Error)
} }
if len(latestEvents) == maxEvents { if len(latestEvents) == maxEvents {
lastInList := latestEvents[len(latestEvents)-1] lastInList := latestEvents[len(latestEvents)-1]
if err := s.conn.Where("repo_id = ? and id < ?", repo.ID, lastInList.ID).Unscoped().Delete(&RepositoryEvent{}).Error; err != nil { if err := s.conn.Where("repo_id = ? and id < ?", repo.ID, lastInList.ID).Unscoped().Delete(&RepositoryEvent{}).Error; err != nil {
return errors.Wrap(err, "deleting old events") return fmt.Errorf("error deleting old events: %w", err)
} }
} }
} }
@ -749,7 +749,7 @@ func (s *sqlDatabase) addRepositoryEvent(ctx context.Context, repoID string, eve
func (s *sqlDatabase) addOrgEvent(ctx context.Context, orgID string, event params.EventType, eventLevel params.EventLevel, statusMessage string, maxEvents int) error { func (s *sqlDatabase) addOrgEvent(ctx context.Context, orgID string, event params.EventType, eventLevel params.EventLevel, statusMessage string, maxEvents int) error {
org, err := s.getOrgByID(ctx, s.conn, orgID) org, err := s.getOrgByID(ctx, s.conn, orgID)
if err != nil { if err != nil {
return errors.Wrap(err, "updating instance") return fmt.Errorf("error updating instance: %w", err)
} }
msg := OrganizationEvent{ msg := OrganizationEvent{
@ -759,7 +759,7 @@ func (s *sqlDatabase) addOrgEvent(ctx context.Context, orgID string, event param
} }
if err := s.conn.Model(&org).Association("Events").Append(&msg); err != nil { if err := s.conn.Model(&org).Association("Events").Append(&msg); err != nil {
return errors.Wrap(err, "adding status message") return fmt.Errorf("error adding status message: %w", err)
} }
if maxEvents > 0 { if maxEvents > 0 {
@ -768,12 +768,12 @@ func (s *sqlDatabase) addOrgEvent(ctx context.Context, orgID string, event param
Limit(maxEvents).Order("id desc"). Limit(maxEvents).Order("id desc").
Where("org_id = ?", org.ID).Find(&latestEvents) Where("org_id = ?", org.ID).Find(&latestEvents)
if q.Error != nil { if q.Error != nil {
return errors.Wrap(q.Error, "fetching latest events") return fmt.Errorf("error fetching latest events: %w", q.Error)
} }
if len(latestEvents) == maxEvents { if len(latestEvents) == maxEvents {
lastInList := latestEvents[len(latestEvents)-1] lastInList := latestEvents[len(latestEvents)-1]
if err := s.conn.Where("org_id = ? and id < ?", org.ID, lastInList.ID).Unscoped().Delete(&OrganizationEvent{}).Error; err != nil { if err := s.conn.Where("org_id = ? and id < ?", org.ID, lastInList.ID).Unscoped().Delete(&OrganizationEvent{}).Error; err != nil {
return errors.Wrap(err, "deleting old events") return fmt.Errorf("error deleting old events: %w", err)
} }
} }
} }
@ -783,7 +783,7 @@ func (s *sqlDatabase) addOrgEvent(ctx context.Context, orgID string, event param
func (s *sqlDatabase) addEnterpriseEvent(ctx context.Context, entID string, event params.EventType, eventLevel params.EventLevel, statusMessage string, maxEvents int) error { func (s *sqlDatabase) addEnterpriseEvent(ctx context.Context, entID string, event params.EventType, eventLevel params.EventLevel, statusMessage string, maxEvents int) error {
ent, err := s.getEnterpriseByID(ctx, s.conn, entID) ent, err := s.getEnterpriseByID(ctx, s.conn, entID)
if err != nil { if err != nil {
return errors.Wrap(err, "updating instance") return fmt.Errorf("error updating instance: %w", err)
} }
msg := EnterpriseEvent{ msg := EnterpriseEvent{
@ -793,7 +793,7 @@ func (s *sqlDatabase) addEnterpriseEvent(ctx context.Context, entID string, even
} }
if err := s.conn.Model(&ent).Association("Events").Append(&msg); err != nil { if err := s.conn.Model(&ent).Association("Events").Append(&msg); err != nil {
return errors.Wrap(err, "adding status message") return fmt.Errorf("error adding status message: %w", err)
} }
if maxEvents > 0 { if maxEvents > 0 {
@ -802,12 +802,12 @@ func (s *sqlDatabase) addEnterpriseEvent(ctx context.Context, entID string, even
Limit(maxEvents).Order("id desc"). Limit(maxEvents).Order("id desc").
Where("enterprise_id = ?", ent.ID).Find(&latestEvents) Where("enterprise_id = ?", ent.ID).Find(&latestEvents)
if q.Error != nil { if q.Error != nil {
return errors.Wrap(q.Error, "fetching latest events") return fmt.Errorf("error fetching latest events: %w", q.Error)
} }
if len(latestEvents) == maxEvents { if len(latestEvents) == maxEvents {
lastInList := latestEvents[len(latestEvents)-1] lastInList := latestEvents[len(latestEvents)-1]
if err := s.conn.Where("enterprise_id = ? and id < ?", ent.ID, lastInList.ID).Unscoped().Delete(&EnterpriseEvent{}).Error; err != nil { if err := s.conn.Where("enterprise_id = ? and id < ?", ent.ID, lastInList.ID).Unscoped().Delete(&EnterpriseEvent{}).Error; err != nil {
return errors.Wrap(err, "deleting old events") return fmt.Errorf("error deleting old events: %w", err)
} }
} }
} }
@ -817,7 +817,7 @@ func (s *sqlDatabase) addEnterpriseEvent(ctx context.Context, entID string, even
func (s *sqlDatabase) AddEntityEvent(ctx context.Context, entity params.ForgeEntity, event params.EventType, eventLevel params.EventLevel, statusMessage string, maxEvents int) error { func (s *sqlDatabase) AddEntityEvent(ctx context.Context, entity params.ForgeEntity, event params.EventType, eventLevel params.EventLevel, statusMessage string, maxEvents int) error {
if maxEvents == 0 { if maxEvents == 0 {
return errors.Wrap(runnerErrors.ErrBadRequest, "max events cannot be 0") return fmt.Errorf("max events cannot be 0: %w", runnerErrors.ErrBadRequest)
} }
switch entity.EntityType { switch entity.EntityType {
@ -828,7 +828,7 @@ func (s *sqlDatabase) AddEntityEvent(ctx context.Context, entity params.ForgeEnt
case params.ForgeEntityTypeEnterprise: case params.ForgeEntityTypeEnterprise:
return s.addEnterpriseEvent(ctx, entity.ID, event, eventLevel, statusMessage, maxEvents) return s.addEnterpriseEvent(ctx, entity.ID, event, eventLevel, statusMessage, maxEvents)
default: default:
return errors.Wrap(runnerErrors.ErrBadRequest, "invalid entity type") return fmt.Errorf("invalid entity type: %w", runnerErrors.ErrBadRequest)
} }
} }
@ -838,12 +838,12 @@ func (s *sqlDatabase) sqlToCommonForgeCredentials(creds GithubCredentials) (para
} }
data, err := util.Unseal(creds.Payload, []byte(s.cfg.Passphrase)) data, err := util.Unseal(creds.Payload, []byte(s.cfg.Passphrase))
if err != nil { if err != nil {
return params.ForgeCredentials{}, errors.Wrap(err, "unsealing credentials") return params.ForgeCredentials{}, fmt.Errorf("error unsealing credentials: %w", err)
} }
ep, err := s.sqlToCommonGithubEndpoint(creds.Endpoint) ep, err := s.sqlToCommonGithubEndpoint(creds.Endpoint)
if err != nil { if err != nil {
return params.ForgeCredentials{}, errors.Wrap(err, "converting github endpoint") return params.ForgeCredentials{}, fmt.Errorf("error converting github endpoint: %w", err)
} }
commonCreds := params.ForgeCredentials{ commonCreds := params.ForgeCredentials{
@ -865,7 +865,7 @@ func (s *sqlDatabase) sqlToCommonForgeCredentials(creds GithubCredentials) (para
for _, repo := range creds.Repositories { for _, repo := range creds.Repositories {
commonRepo, err := s.sqlToCommonRepository(repo, false) commonRepo, err := s.sqlToCommonRepository(repo, false)
if err != nil { if err != nil {
return params.ForgeCredentials{}, errors.Wrap(err, "converting github repository") return params.ForgeCredentials{}, fmt.Errorf("error converting github repository: %w", err)
} }
commonCreds.Repositories = append(commonCreds.Repositories, commonRepo) commonCreds.Repositories = append(commonCreds.Repositories, commonRepo)
} }
@ -873,7 +873,7 @@ func (s *sqlDatabase) sqlToCommonForgeCredentials(creds GithubCredentials) (para
for _, org := range creds.Organizations { for _, org := range creds.Organizations {
commonOrg, err := s.sqlToCommonOrganization(org, false) commonOrg, err := s.sqlToCommonOrganization(org, false)
if err != nil { if err != nil {
return params.ForgeCredentials{}, errors.Wrap(err, "converting github organization") return params.ForgeCredentials{}, fmt.Errorf("error converting github organization: %w", err)
} }
commonCreds.Organizations = append(commonCreds.Organizations, commonOrg) commonCreds.Organizations = append(commonCreds.Organizations, commonOrg)
} }
@ -881,7 +881,7 @@ func (s *sqlDatabase) sqlToCommonForgeCredentials(creds GithubCredentials) (para
for _, ent := range creds.Enterprises { for _, ent := range creds.Enterprises {
commonEnt, err := s.sqlToCommonEnterprise(ent, false) commonEnt, err := s.sqlToCommonEnterprise(ent, false)
if err != nil { if err != nil {
return params.ForgeCredentials{}, errors.Wrapf(err, "converting github enterprise: %s", ent.Name) return params.ForgeCredentials{}, fmt.Errorf("error converting github enterprise %s: %w", ent.Name, err)
} }
commonCreds.Enterprises = append(commonCreds.Enterprises, commonEnt) commonCreds.Enterprises = append(commonCreds.Enterprises, commonEnt)
} }
@ -895,12 +895,12 @@ func (s *sqlDatabase) sqlGiteaToCommonForgeCredentials(creds GiteaCredentials) (
} }
data, err := util.Unseal(creds.Payload, []byte(s.cfg.Passphrase)) data, err := util.Unseal(creds.Payload, []byte(s.cfg.Passphrase))
if err != nil { if err != nil {
return params.ForgeCredentials{}, errors.Wrap(err, "unsealing credentials") return params.ForgeCredentials{}, fmt.Errorf("error unsealing credentials: %w", err)
} }
ep, err := s.sqlToCommonGithubEndpoint(creds.Endpoint) ep, err := s.sqlToCommonGithubEndpoint(creds.Endpoint)
if err != nil { if err != nil {
return params.ForgeCredentials{}, errors.Wrap(err, "converting github endpoint") return params.ForgeCredentials{}, fmt.Errorf("error converting github endpoint: %w", err)
} }
commonCreds := params.ForgeCredentials{ commonCreds := params.ForgeCredentials{
@ -921,7 +921,7 @@ func (s *sqlDatabase) sqlGiteaToCommonForgeCredentials(creds GiteaCredentials) (
for _, repo := range creds.Repositories { for _, repo := range creds.Repositories {
commonRepo, err := s.sqlToCommonRepository(repo, false) commonRepo, err := s.sqlToCommonRepository(repo, false)
if err != nil { if err != nil {
return params.ForgeCredentials{}, errors.Wrap(err, "converting github repository") return params.ForgeCredentials{}, fmt.Errorf("error converting github repository: %w", err)
} }
commonCreds.Repositories = append(commonCreds.Repositories, commonRepo) commonCreds.Repositories = append(commonCreds.Repositories, commonRepo)
} }
@ -929,7 +929,7 @@ func (s *sqlDatabase) sqlGiteaToCommonForgeCredentials(creds GiteaCredentials) (
for _, org := range creds.Organizations { for _, org := range creds.Organizations {
commonOrg, err := s.sqlToCommonOrganization(org, false) commonOrg, err := s.sqlToCommonOrganization(org, false)
if err != nil { if err != nil {
return params.ForgeCredentials{}, errors.Wrap(err, "converting github organization") return params.ForgeCredentials{}, fmt.Errorf("error converting github organization: %w", err)
} }
commonCreds.Organizations = append(commonCreds.Organizations, commonOrg) commonCreds.Organizations = append(commonCreds.Organizations, commonOrg)
} }
@ -954,12 +954,12 @@ func (s *sqlDatabase) sqlToCommonGithubEndpoint(ep GithubEndpoint) (params.Forge
func getUIDFromContext(ctx context.Context) (uuid.UUID, error) { func getUIDFromContext(ctx context.Context) (uuid.UUID, error) {
userID := auth.UserID(ctx) userID := auth.UserID(ctx)
if userID == "" { if userID == "" {
return uuid.Nil, errors.Wrap(runnerErrors.ErrUnauthorized, "getting UID from context") return uuid.Nil, fmt.Errorf("error getting UID from context: %w", runnerErrors.ErrUnauthorized)
} }
asUUID, err := uuid.Parse(userID) asUUID, err := uuid.Parse(userID)
if err != nil { if err != nil {
return uuid.Nil, errors.Wrap(runnerErrors.ErrUnauthorized, "parsing UID from context") return uuid.Nil, fmt.Errorf("error parsing UID from context: %w", runnerErrors.ErrUnauthorized)
} }
return asUUID, nil return asUUID, nil
} }

View file

@ -16,11 +16,10 @@ package watcher
import ( import (
"context" "context"
"fmt"
"log/slog" "log/slog"
"sync" "sync"
"github.com/pkg/errors"
"github.com/cloudbase/garm/database/common" "github.com/cloudbase/garm/database/common"
garmUtil "github.com/cloudbase/garm/util" garmUtil "github.com/cloudbase/garm/util"
) )
@ -83,7 +82,7 @@ func (w *watcher) RegisterProducer(ctx context.Context, id string) (common.Produ
defer w.mux.Unlock() defer w.mux.Unlock()
if _, ok := w.producers[id]; ok { if _, ok := w.producers[id]; ok {
return nil, errors.Wrapf(common.ErrProducerAlreadyRegistered, "producer_id: %s", id) return nil, fmt.Errorf("producer_id %s: %w", id, common.ErrProducerAlreadyRegistered)
} }
p := &producer{ p := &producer{
id: id, id: id,

View file

@ -17,11 +17,11 @@ package watcher_test
import ( import (
"context" "context"
"fmt"
"testing" "testing"
"time" "time"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/pkg/errors"
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
commonParams "github.com/cloudbase/garm-provider-common/params" commonParams "github.com/cloudbase/garm-provider-common/params"
@ -310,7 +310,7 @@ func maybeInitController(db common.Store) error {
} }
if _, err := db.InitController(); err != nil { if _, err := db.InitController(); err != nil {
return errors.Wrap(err, "initializing controller") return fmt.Errorf("error initializing controller: %w", err)
} }
return nil return nil

7
go.mod
View file

@ -20,11 +20,8 @@ require (
github.com/gorilla/mux v1.8.1 github.com/gorilla/mux v1.8.1
github.com/gorilla/websocket v1.5.4-0.20240702125206-a62d9d2a8413 github.com/gorilla/websocket v1.5.4-0.20240702125206-a62d9d2a8413
github.com/jedib0t/go-pretty/v6 v6.6.8 github.com/jedib0t/go-pretty/v6 v6.6.8
github.com/juju/clock v1.1.1
github.com/juju/retry v1.0.1
github.com/manifoldco/promptui v0.9.0 github.com/manifoldco/promptui v0.9.0
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.23.0 github.com/prometheus/client_golang v1.23.0
github.com/spf13/cobra v1.9.1 github.com/spf13/cobra v1.9.1
github.com/stretchr/testify v1.10.0 github.com/stretchr/testify v1.10.0
@ -62,9 +59,6 @@ require (
github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect github.com/jinzhu/now v1.1.5 // indirect
github.com/josharian/intern v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect
github.com/juju/errors v1.0.0 // indirect
github.com/juju/loggo v1.0.0 // indirect
github.com/juju/testing v1.0.2 // indirect
github.com/mailru/easyjson v0.9.0 // indirect github.com/mailru/easyjson v0.9.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect
@ -74,6 +68,7 @@ require (
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/oklog/ulid v1.3.1 // indirect github.com/oklog/ulid v1.3.1 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.65.0 // indirect github.com/prometheus/common v0.65.0 // indirect

19
go.sum
View file

@ -95,19 +95,6 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU=
github.com/juju/clock v1.1.1 h1:NvgHG9DQmOpBevgt6gzkyimdWBooLXDy1cQn89qJzBI=
github.com/juju/clock v1.1.1/go.mod h1:HIBvJ8kiV/n7UHwKuCkdYL4l/MDECztHR2sAvWDxxf0=
github.com/juju/errors v1.0.0 h1:yiq7kjCLll1BiaRuNY53MGI0+EQ3rF6GB+wvboZDefM=
github.com/juju/errors v1.0.0/go.mod h1:B5x9thDqx0wIMH3+aLIMP9HjItInYWObRovoCFM5Qe8=
github.com/juju/loggo v1.0.0 h1:Y6ZMQOGR9Aj3BGkiWx7HBbIx6zNwNkxhVNOHU2i1bl0=
github.com/juju/loggo v1.0.0/go.mod h1:NIXFioti1SmKAlKNuUwbMenNdef59IF52+ZzuOmHYkg=
github.com/juju/retry v1.0.1 h1:EVwOPq273wO1o0BCU7Ay7XE/bNb+bTNYsCK6y+BboAk=
github.com/juju/retry v1.0.1/go.mod h1:SssN1eYeK3A2qjnFGTiVMbdzGJ2BfluaJblJXvuvgqA=
github.com/juju/testing v1.0.2 h1:OR90RqCd9CJONxXamZAjLknpZdtqDyxqW8IwCbgw3i4=
github.com/juju/testing v1.0.2/go.mod h1:h3Vd2rzB57KrdsBEy6R7bmSKPzP76BnNavt7i8PerwQ=
github.com/juju/utils/v3 v3.0.0 h1:Gg3n63mGPbBuoXCo+EPJuMi44hGZfloI8nlCIebHu2Q=
github.com/juju/utils/v3 v3.0.0/go.mod h1:8csUcj1VRkfjNIRzBFWzLFCMLwLqsRWvkmhfVAUwbC4=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
@ -116,13 +103,10 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/lunixbochs/vtclean v0.0.0-20160125035106-4fbf7632a2c6/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA=
github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg=
github.com/mattn/go-colorable v0.0.6/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.0-20160806122752-66b8e73f3f5c/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
@ -213,13 +197,10 @@ google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/
gopkg.in/DATA-DOG/go-sqlmock.v1 v1.3.0 h1:FVCohIoYO7IJoDDVpV2pdq7SgrMH6wHnuTyrdrxJNoY= gopkg.in/DATA-DOG/go-sqlmock.v1 v1.3.0 h1:FVCohIoYO7IJoDDVpV2pdq7SgrMH6wHnuTyrdrxJNoY=
gopkg.in/DATA-DOG/go-sqlmock.v1 v1.3.0/go.mod h1:OdE7CF6DbADk7lN8LIKRzRJTTZXIjtWgA5THM5lhBAw= gopkg.in/DATA-DOG/go-sqlmock.v1 v1.3.0/go.mod h1:OdE7CF6DbADk7lN8LIKRzRJTTZXIjtWgA5THM5lhBAw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20160105164936-4f90aeace3a2/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/datatypes v1.2.6 h1:KafLdXvFUhzNeL2ncm03Gl3eTLONQfNKZ+wJ+9Y4Nck= gorm.io/datatypes v1.2.6 h1:KafLdXvFUhzNeL2ncm03Gl3eTLONQfNKZ+wJ+9Y4Nck=

View file

@ -19,13 +19,13 @@ package testing
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
"sort" "sort"
"testing" "testing"
"github.com/pkg/errors"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
runnerErrors "github.com/cloudbase/garm-provider-common/errors" runnerErrors "github.com/cloudbase/garm-provider-common/errors"

View file

@ -21,8 +21,6 @@ import (
"fmt" "fmt"
"net/url" "net/url"
"github.com/pkg/errors"
runnerErrors "github.com/cloudbase/garm-provider-common/errors" runnerErrors "github.com/cloudbase/garm-provider-common/errors"
commonParams "github.com/cloudbase/garm-provider-common/params" commonParams "github.com/cloudbase/garm-provider-common/params"
) )
@ -497,7 +495,7 @@ func (c CreateGithubCredentialsParams) Validate() error {
if c.AuthType == ForgeAuthTypeApp { if c.AuthType == ForgeAuthTypeApp {
if err := c.App.Validate(); err != nil { if err := c.App.Validate(); err != nil {
return errors.Wrap(err, "invalid app") return fmt.Errorf("invalid app: %w", err)
} }
} }
@ -525,7 +523,7 @@ func (u UpdateGithubCredentialsParams) Validate() error {
if u.App != nil { if u.App != nil {
if err := u.App.Validate(); err != nil { if err := u.App.Validate(); err != nil {
return errors.Wrap(err, "invalid app") return fmt.Errorf("invalid app: %w", err)
} }
} }

View file

@ -2,8 +2,8 @@ package runner
import ( import (
"context" "context"
"errors"
"github.com/pkg/errors" "fmt"
runnerErrors "github.com/cloudbase/garm-provider-common/errors" runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/params" "github.com/cloudbase/garm/params"
@ -12,11 +12,11 @@ import (
func (r *Runner) ResolveForgeCredentialByName(ctx context.Context, credentialsName string) (params.ForgeCredentials, error) { func (r *Runner) ResolveForgeCredentialByName(ctx context.Context, credentialsName string) (params.ForgeCredentials, error) {
githubCred, err := r.store.GetGithubCredentialsByName(ctx, credentialsName, false) githubCred, err := r.store.GetGithubCredentialsByName(ctx, credentialsName, false)
if err != nil && !errors.Is(err, runnerErrors.ErrNotFound) { if err != nil && !errors.Is(err, runnerErrors.ErrNotFound) {
return params.ForgeCredentials{}, errors.Wrap(err, "fetching github credentials") return params.ForgeCredentials{}, fmt.Errorf("error fetching github credentials: %w", err)
} }
giteaCred, err := r.store.GetGiteaCredentialsByName(ctx, credentialsName, false) giteaCred, err := r.store.GetGiteaCredentialsByName(ctx, credentialsName, false)
if err != nil && !errors.Is(err, runnerErrors.ErrNotFound) { if err != nil && !errors.Is(err, runnerErrors.ErrNotFound) {
return params.ForgeCredentials{}, errors.Wrap(err, "fetching gitea credentials") return params.ForgeCredentials{}, fmt.Errorf("error fetching gitea credentials: %w", err)
} }
if githubCred.ID != 0 && giteaCred.ID != 0 { if githubCred.ID != 0 && giteaCred.ID != 0 {
return params.ForgeCredentials{}, runnerErrors.NewBadRequestError("credentials %s are defined for both GitHub and Gitea, please specify the forge type", credentialsName) return params.ForgeCredentials{}, runnerErrors.NewBadRequestError("credentials %s are defined for both GitHub and Gitea, please specify the forge type", credentialsName)

View file

@ -16,12 +16,11 @@ package runner
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"log/slog" "log/slog"
"strings" "strings"
"github.com/pkg/errors"
runnerErrors "github.com/cloudbase/garm-provider-common/errors" runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/auth" "github.com/cloudbase/garm/auth"
"github.com/cloudbase/garm/params" "github.com/cloudbase/garm/params"
@ -36,7 +35,7 @@ func (r *Runner) CreateEnterprise(ctx context.Context, param params.CreateEnterp
err = param.Validate() err = param.Validate()
if err != nil { if err != nil {
return params.Enterprise{}, errors.Wrap(err, "validating params") return params.Enterprise{}, fmt.Errorf("error validating params: %w", err)
} }
creds, err := r.store.GetGithubCredentialsByName(ctx, param.CredentialsName, true) creds, err := r.store.GetGithubCredentialsByName(ctx, param.CredentialsName, true)
@ -47,7 +46,7 @@ func (r *Runner) CreateEnterprise(ctx context.Context, param params.CreateEnterp
_, err = r.store.GetEnterprise(ctx, param.Name, creds.Endpoint.Name) _, err = r.store.GetEnterprise(ctx, param.Name, creds.Endpoint.Name)
if err != nil { if err != nil {
if !errors.Is(err, runnerErrors.ErrNotFound) { if !errors.Is(err, runnerErrors.ErrNotFound) {
return params.Enterprise{}, errors.Wrap(err, "fetching enterprise") return params.Enterprise{}, fmt.Errorf("error fetching enterprise: %w", err)
} }
} else { } else {
return params.Enterprise{}, runnerErrors.NewConflictError("enterprise %s already exists", param.Name) return params.Enterprise{}, runnerErrors.NewConflictError("enterprise %s already exists", param.Name)
@ -55,7 +54,7 @@ func (r *Runner) CreateEnterprise(ctx context.Context, param params.CreateEnterp
enterprise, err = r.store.CreateEnterprise(ctx, param.Name, creds, param.WebhookSecret, param.PoolBalancerType) enterprise, err = r.store.CreateEnterprise(ctx, param.Name, creds, param.WebhookSecret, param.PoolBalancerType)
if err != nil { if err != nil {
return params.Enterprise{}, errors.Wrap(err, "creating enterprise") return params.Enterprise{}, fmt.Errorf("error creating enterprise: %w", err)
} }
defer func() { defer func() {
@ -73,7 +72,7 @@ func (r *Runner) CreateEnterprise(ctx context.Context, param params.CreateEnterp
var poolMgr common.PoolManager var poolMgr common.PoolManager
poolMgr, err = r.poolManagerCtrl.CreateEnterprisePoolManager(r.ctx, enterprise, r.providers, r.store) poolMgr, err = r.poolManagerCtrl.CreateEnterprisePoolManager(r.ctx, enterprise, r.providers, r.store)
if err != nil { if err != nil {
return params.Enterprise{}, errors.Wrap(err, "creating enterprise pool manager") return params.Enterprise{}, fmt.Errorf("error creating enterprise pool manager: %w", err)
} }
if err := poolMgr.Start(); err != nil { if err := poolMgr.Start(); err != nil {
if deleteErr := r.poolManagerCtrl.DeleteEnterprisePoolManager(enterprise); deleteErr != nil { if deleteErr := r.poolManagerCtrl.DeleteEnterprisePoolManager(enterprise); deleteErr != nil {
@ -81,7 +80,7 @@ func (r *Runner) CreateEnterprise(ctx context.Context, param params.CreateEnterp
ctx, "failed to cleanup pool manager for enterprise", ctx, "failed to cleanup pool manager for enterprise",
"enterprise_id", enterprise.ID) "enterprise_id", enterprise.ID)
} }
return params.Enterprise{}, errors.Wrap(err, "starting enterprise pool manager") return params.Enterprise{}, fmt.Errorf("error starting enterprise pool manager: %w", err)
} }
return enterprise, nil return enterprise, nil
} }
@ -93,7 +92,7 @@ func (r *Runner) ListEnterprises(ctx context.Context, filter params.EnterpriseFi
enterprises, err := r.store.ListEnterprises(ctx, filter) enterprises, err := r.store.ListEnterprises(ctx, filter)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "listing enterprises") return nil, fmt.Errorf("error listing enterprises: %w", err)
} }
var allEnterprises []params.Enterprise var allEnterprises []params.Enterprise
@ -119,7 +118,7 @@ func (r *Runner) GetEnterpriseByID(ctx context.Context, enterpriseID string) (pa
enterprise, err := r.store.GetEnterpriseByID(ctx, enterpriseID) enterprise, err := r.store.GetEnterpriseByID(ctx, enterpriseID)
if err != nil { if err != nil {
return params.Enterprise{}, errors.Wrap(err, "fetching enterprise") return params.Enterprise{}, fmt.Errorf("error fetching enterprise: %w", err)
} }
poolMgr, err := r.poolManagerCtrl.GetEnterprisePoolManager(enterprise) poolMgr, err := r.poolManagerCtrl.GetEnterprisePoolManager(enterprise)
if err != nil { if err != nil {
@ -137,17 +136,17 @@ func (r *Runner) DeleteEnterprise(ctx context.Context, enterpriseID string) erro
enterprise, err := r.store.GetEnterpriseByID(ctx, enterpriseID) enterprise, err := r.store.GetEnterpriseByID(ctx, enterpriseID)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching enterprise") return fmt.Errorf("error fetching enterprise: %w", err)
} }
entity, err := enterprise.GetEntity() entity, err := enterprise.GetEntity()
if err != nil { if err != nil {
return errors.Wrap(err, "getting entity") return fmt.Errorf("error getting entity: %w", err)
} }
pools, err := r.store.ListEntityPools(ctx, entity) pools, err := r.store.ListEntityPools(ctx, entity)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching enterprise pools") return fmt.Errorf("error fetching enterprise pools: %w", err)
} }
if len(pools) > 0 { if len(pools) > 0 {
@ -161,7 +160,7 @@ func (r *Runner) DeleteEnterprise(ctx context.Context, enterpriseID string) erro
scaleSets, err := r.store.ListEntityScaleSets(ctx, entity) scaleSets, err := r.store.ListEntityScaleSets(ctx, entity)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching enterprise scale sets") return fmt.Errorf("error fetching enterprise scale sets: %w", err)
} }
if len(scaleSets) > 0 { if len(scaleSets) > 0 {
@ -169,11 +168,11 @@ func (r *Runner) DeleteEnterprise(ctx context.Context, enterpriseID string) erro
} }
if err := r.poolManagerCtrl.DeleteEnterprisePoolManager(enterprise); err != nil { if err := r.poolManagerCtrl.DeleteEnterprisePoolManager(enterprise); err != nil {
return errors.Wrap(err, "deleting enterprise pool manager") return fmt.Errorf("error deleting enterprise pool manager: %w", err)
} }
if err := r.store.DeleteEnterprise(ctx, enterpriseID); err != nil { if err := r.store.DeleteEnterprise(ctx, enterpriseID); err != nil {
return errors.Wrapf(err, "removing enterprise %s", enterpriseID) return fmt.Errorf("error removing enterprise %s: %w", enterpriseID, err)
} }
return nil return nil
} }
@ -194,7 +193,7 @@ func (r *Runner) UpdateEnterprise(ctx context.Context, enterpriseID string, para
enterprise, err := r.store.UpdateEnterprise(ctx, enterpriseID, param) enterprise, err := r.store.UpdateEnterprise(ctx, enterpriseID, param)
if err != nil { if err != nil {
return params.Enterprise{}, errors.Wrap(err, "updating enterprise") return params.Enterprise{}, fmt.Errorf("error updating enterprise: %w", err)
} }
poolMgr, err := r.poolManagerCtrl.GetEnterprisePoolManager(enterprise) poolMgr, err := r.poolManagerCtrl.GetEnterprisePoolManager(enterprise)
@ -243,7 +242,7 @@ func (r *Runner) GetEnterprisePoolByID(ctx context.Context, enterpriseID, poolID
} }
pool, err := r.store.GetEntityPool(ctx, entity, poolID) pool, err := r.store.GetEntityPool(ctx, entity, poolID)
if err != nil { if err != nil {
return params.Pool{}, errors.Wrap(err, "fetching pool") return params.Pool{}, fmt.Errorf("error fetching pool: %w", err)
} }
return pool, nil return pool, nil
} }
@ -260,7 +259,7 @@ func (r *Runner) DeleteEnterprisePool(ctx context.Context, enterpriseID, poolID
pool, err := r.store.GetEntityPool(ctx, entity, poolID) pool, err := r.store.GetEntityPool(ctx, entity, poolID)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching pool") return fmt.Errorf("error fetching pool: %w", err)
} }
// nolint:golangci-lint,godox // nolint:golangci-lint,godox
@ -274,7 +273,7 @@ func (r *Runner) DeleteEnterprisePool(ctx context.Context, enterpriseID, poolID
} }
if err := r.store.DeleteEntityPool(ctx, entity, poolID); err != nil { if err := r.store.DeleteEntityPool(ctx, entity, poolID); err != nil {
return errors.Wrap(err, "deleting pool") return fmt.Errorf("error deleting pool: %w", err)
} }
return nil return nil
} }
@ -290,7 +289,7 @@ func (r *Runner) ListEnterprisePools(ctx context.Context, enterpriseID string) (
} }
pools, err := r.store.ListEntityPools(ctx, entity) pools, err := r.store.ListEntityPools(ctx, entity)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching pools") return nil, fmt.Errorf("error fetching pools: %w", err)
} }
return pools, nil return pools, nil
} }
@ -306,7 +305,7 @@ func (r *Runner) UpdateEnterprisePool(ctx context.Context, enterpriseID, poolID
} }
pool, err := r.store.GetEntityPool(ctx, entity, poolID) pool, err := r.store.GetEntityPool(ctx, entity, poolID)
if err != nil { if err != nil {
return params.Pool{}, errors.Wrap(err, "fetching pool") return params.Pool{}, fmt.Errorf("error fetching pool: %w", err)
} }
maxRunners := pool.MaxRunners maxRunners := pool.MaxRunners
@ -325,7 +324,7 @@ func (r *Runner) UpdateEnterprisePool(ctx context.Context, enterpriseID, poolID
newPool, err := r.store.UpdateEntityPool(ctx, entity, poolID, param) newPool, err := r.store.UpdateEntityPool(ctx, entity, poolID, param)
if err != nil { if err != nil {
return params.Pool{}, errors.Wrap(err, "updating pool") return params.Pool{}, fmt.Errorf("error updating pool: %w", err)
} }
return newPool, nil return newPool, nil
} }
@ -340,7 +339,7 @@ func (r *Runner) ListEnterpriseInstances(ctx context.Context, enterpriseID strin
} }
instances, err := r.store.ListEntityInstances(ctx, entity) instances, err := r.store.ListEntityInstances(ctx, entity)
if err != nil { if err != nil {
return []params.Instance{}, errors.Wrap(err, "fetching instances") return []params.Instance{}, fmt.Errorf("error fetching instances: %w", err)
} }
return instances, nil return instances, nil
} }
@ -351,12 +350,12 @@ func (r *Runner) findEnterprisePoolManager(name, endpointName string) (common.Po
enterprise, err := r.store.GetEnterprise(r.ctx, name, endpointName) enterprise, err := r.store.GetEnterprise(r.ctx, name, endpointName)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching enterprise") return nil, fmt.Errorf("error fetching enterprise: %w", err)
} }
poolManager, err := r.poolManagerCtrl.GetEnterprisePoolManager(enterprise) poolManager, err := r.poolManagerCtrl.GetEnterprisePoolManager(enterprise)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching pool manager for enterprise") return nil, fmt.Errorf("error fetching pool manager for enterprise: %w", err)
} }
return poolManager, nil return poolManager, nil
} }

View file

@ -16,10 +16,10 @@ package runner
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"testing" "testing"
"github.com/pkg/errors"
"github.com/stretchr/testify/mock" "github.com/stretchr/testify/mock"
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
@ -210,7 +210,7 @@ func (s *EnterpriseTestSuite) TestCreateEnterprisePoolMgrFailed() {
s.Fixtures.PoolMgrMock.AssertExpectations(s.T()) s.Fixtures.PoolMgrMock.AssertExpectations(s.T())
s.Fixtures.PoolMgrCtrlMock.AssertExpectations(s.T()) s.Fixtures.PoolMgrCtrlMock.AssertExpectations(s.T())
s.Require().Equal(fmt.Sprintf("creating enterprise pool manager: %s", s.Fixtures.ErrMock.Error()), err.Error()) s.Require().Equal(fmt.Sprintf("error creating enterprise pool manager: %s", s.Fixtures.ErrMock.Error()), err.Error())
} }
func (s *EnterpriseTestSuite) TestCreateEnterpriseStartPoolMgrFailed() { func (s *EnterpriseTestSuite) TestCreateEnterpriseStartPoolMgrFailed() {
@ -222,7 +222,7 @@ func (s *EnterpriseTestSuite) TestCreateEnterpriseStartPoolMgrFailed() {
s.Fixtures.PoolMgrMock.AssertExpectations(s.T()) s.Fixtures.PoolMgrMock.AssertExpectations(s.T())
s.Fixtures.PoolMgrCtrlMock.AssertExpectations(s.T()) s.Fixtures.PoolMgrCtrlMock.AssertExpectations(s.T())
s.Require().Equal(fmt.Sprintf("starting enterprise pool manager: %s", s.Fixtures.ErrMock.Error()), err.Error()) s.Require().Equal(fmt.Sprintf("error starting enterprise pool manager: %s", s.Fixtures.ErrMock.Error()), err.Error())
} }
func (s *EnterpriseTestSuite) TestListEnterprises() { func (s *EnterpriseTestSuite) TestListEnterprises() {
@ -324,7 +324,7 @@ func (s *EnterpriseTestSuite) TestDeleteEnterprise() {
s.Require().Nil(err) s.Require().Nil(err)
_, err = s.Fixtures.Store.GetEnterpriseByID(s.Fixtures.AdminContext, s.Fixtures.StoreEnterprises["test-enterprise-3"].ID) _, err = s.Fixtures.Store.GetEnterpriseByID(s.Fixtures.AdminContext, s.Fixtures.StoreEnterprises["test-enterprise-3"].ID)
s.Require().Equal("fetching enterprise: not found", err.Error()) s.Require().Equal("error fetching enterprise: not found", err.Error())
} }
func (s *EnterpriseTestSuite) TestDeleteEnterpriseErrUnauthorized() { func (s *EnterpriseTestSuite) TestDeleteEnterpriseErrUnauthorized() {
@ -354,7 +354,7 @@ func (s *EnterpriseTestSuite) TestDeleteEnterprisePoolMgrFailed() {
err := s.Runner.DeleteEnterprise(s.Fixtures.AdminContext, s.Fixtures.StoreEnterprises["test-enterprise-1"].ID) err := s.Runner.DeleteEnterprise(s.Fixtures.AdminContext, s.Fixtures.StoreEnterprises["test-enterprise-1"].ID)
s.Fixtures.PoolMgrCtrlMock.AssertExpectations(s.T()) s.Fixtures.PoolMgrCtrlMock.AssertExpectations(s.T())
s.Require().Equal(fmt.Sprintf("deleting enterprise pool manager: %s", s.Fixtures.ErrMock.Error()), err.Error()) s.Require().Equal(fmt.Sprintf("error deleting enterprise pool manager: %s", s.Fixtures.ErrMock.Error()), err.Error())
} }
func (s *EnterpriseTestSuite) TestUpdateEnterprise() { func (s *EnterpriseTestSuite) TestUpdateEnterprise() {
@ -477,7 +477,7 @@ func (s *EnterpriseTestSuite) TestDeleteEnterprisePool() {
s.Require().Nil(err) s.Require().Nil(err)
_, err = s.Fixtures.Store.GetEntityPool(s.Fixtures.AdminContext, entity, pool.ID) _, err = s.Fixtures.Store.GetEntityPool(s.Fixtures.AdminContext, entity, pool.ID)
s.Require().Equal("fetching pool: finding pool: not found", err.Error()) s.Require().Equal("fetching pool: error finding pool: not found", err.Error())
} }
func (s *EnterpriseTestSuite) TestDeleteEnterprisePoolErrUnauthorized() { func (s *EnterpriseTestSuite) TestDeleteEnterprisePoolErrUnauthorized() {

View file

@ -16,8 +16,7 @@ package runner
import ( import (
"context" "context"
"fmt"
"github.com/pkg/errors"
runnerErrors "github.com/cloudbase/garm-provider-common/errors" runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/auth" "github.com/cloudbase/garm/auth"
@ -35,7 +34,7 @@ func (r *Runner) ListGiteaCredentials(ctx context.Context) ([]params.ForgeCreden
// there is a posibillity that not all creds will be in the cache. // there is a posibillity that not all creds will be in the cache.
creds, err := r.store.ListGiteaCredentials(ctx) creds, err := r.store.ListGiteaCredentials(ctx)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching gitea credentials") return nil, fmt.Errorf("error fetching gitea credentials: %w", err)
} }
return creds, nil return creds, nil
} }
@ -46,12 +45,12 @@ func (r *Runner) CreateGiteaCredentials(ctx context.Context, param params.Create
} }
if err := param.Validate(); err != nil { if err := param.Validate(); err != nil {
return params.ForgeCredentials{}, errors.Wrap(err, "failed to validate gitea credentials params") return params.ForgeCredentials{}, fmt.Errorf("error failed to validate gitea credentials params: %w", err)
} }
creds, err := r.store.CreateGiteaCredentials(ctx, param) creds, err := r.store.CreateGiteaCredentials(ctx, param)
if err != nil { if err != nil {
return params.ForgeCredentials{}, errors.Wrap(err, "failed to create gitea credentials") return params.ForgeCredentials{}, fmt.Errorf("error failed to create gitea credentials: %w", err)
} }
return creds, nil return creds, nil
@ -64,7 +63,7 @@ func (r *Runner) GetGiteaCredentials(ctx context.Context, id uint) (params.Forge
creds, err := r.store.GetGiteaCredentials(ctx, id, true) creds, err := r.store.GetGiteaCredentials(ctx, id, true)
if err != nil { if err != nil {
return params.ForgeCredentials{}, errors.Wrap(err, "failed to get gitea credentials") return params.ForgeCredentials{}, fmt.Errorf("error failed to get gitea credentials: %w", err)
} }
return creds, nil return creds, nil
@ -76,7 +75,7 @@ func (r *Runner) DeleteGiteaCredentials(ctx context.Context, id uint) error {
} }
if err := r.store.DeleteGiteaCredentials(ctx, id); err != nil { if err := r.store.DeleteGiteaCredentials(ctx, id); err != nil {
return errors.Wrap(err, "failed to delete gitea credentials") return fmt.Errorf("error failed to delete gitea credentials: %w", err)
} }
return nil return nil
@ -88,12 +87,12 @@ func (r *Runner) UpdateGiteaCredentials(ctx context.Context, id uint, param para
} }
if err := param.Validate(); err != nil { if err := param.Validate(); err != nil {
return params.ForgeCredentials{}, errors.Wrap(err, "failed to validate gitea credentials params") return params.ForgeCredentials{}, fmt.Errorf("error failed to validate gitea credentials params: %w", err)
} }
newCreds, err := r.store.UpdateGiteaCredentials(ctx, id, param) newCreds, err := r.store.UpdateGiteaCredentials(ctx, id, param)
if err != nil { if err != nil {
return params.ForgeCredentials{}, errors.Wrap(err, "failed to update gitea credentials") return params.ForgeCredentials{}, fmt.Errorf("error failed to update gitea credentials: %w", err)
} }
return newCreds, nil return newCreds, nil

View file

@ -16,8 +16,7 @@ package runner
import ( import (
"context" "context"
"fmt"
"github.com/pkg/errors"
runnerErrors "github.com/cloudbase/garm-provider-common/errors" runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/auth" "github.com/cloudbase/garm/auth"
@ -30,12 +29,12 @@ func (r *Runner) CreateGiteaEndpoint(ctx context.Context, param params.CreateGit
} }
if err := param.Validate(); err != nil { if err := param.Validate(); err != nil {
return params.ForgeEndpoint{}, errors.Wrap(err, "failed to validate gitea endpoint params") return params.ForgeEndpoint{}, fmt.Errorf("failed to validate gitea endpoint params: %w", err)
} }
ep, err := r.store.CreateGiteaEndpoint(ctx, param) ep, err := r.store.CreateGiteaEndpoint(ctx, param)
if err != nil { if err != nil {
return params.ForgeEndpoint{}, errors.Wrap(err, "failed to create gitea endpoint") return params.ForgeEndpoint{}, fmt.Errorf("failed to create gitea endpoint: %w", err)
} }
return ep, nil return ep, nil
@ -47,7 +46,7 @@ func (r *Runner) GetGiteaEndpoint(ctx context.Context, name string) (params.Forg
} }
endpoint, err := r.store.GetGiteaEndpoint(ctx, name) endpoint, err := r.store.GetGiteaEndpoint(ctx, name)
if err != nil { if err != nil {
return params.ForgeEndpoint{}, errors.Wrap(err, "failed to get gitea endpoint") return params.ForgeEndpoint{}, fmt.Errorf("failed to get gitea endpoint: %w", err)
} }
return endpoint, nil return endpoint, nil
@ -60,7 +59,7 @@ func (r *Runner) DeleteGiteaEndpoint(ctx context.Context, name string) error {
err := r.store.DeleteGiteaEndpoint(ctx, name) err := r.store.DeleteGiteaEndpoint(ctx, name)
if err != nil { if err != nil {
return errors.Wrap(err, "failed to delete gitea endpoint") return fmt.Errorf("failed to delete gitea endpoint: %w", err)
} }
return nil return nil
@ -72,12 +71,12 @@ func (r *Runner) UpdateGiteaEndpoint(ctx context.Context, name string, param par
} }
if err := param.Validate(); err != nil { if err := param.Validate(); err != nil {
return params.ForgeEndpoint{}, errors.Wrap(err, "failed to validate gitea endpoint params") return params.ForgeEndpoint{}, fmt.Errorf("failed to validate gitea endpoint params: %w", err)
} }
newEp, err := r.store.UpdateGiteaEndpoint(ctx, name, param) newEp, err := r.store.UpdateGiteaEndpoint(ctx, name, param)
if err != nil { if err != nil {
return params.ForgeEndpoint{}, errors.Wrap(err, "failed to update gitea endpoint") return params.ForgeEndpoint{}, fmt.Errorf("failed to update gitea endpoint: %w", err)
} }
return newEp, nil return newEp, nil
} }
@ -89,7 +88,7 @@ func (r *Runner) ListGiteaEndpoints(ctx context.Context) ([]params.ForgeEndpoint
endpoints, err := r.store.ListGiteaEndpoints(ctx) endpoints, err := r.store.ListGiteaEndpoints(ctx)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to list gitea endpoints") return nil, fmt.Errorf("failed to list gitea endpoints: %w", err)
} }
return endpoints, nil return endpoints, nil

View file

@ -16,8 +16,7 @@ package runner
import ( import (
"context" "context"
"fmt"
"github.com/pkg/errors"
runnerErrors "github.com/cloudbase/garm-provider-common/errors" runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/auth" "github.com/cloudbase/garm/auth"
@ -36,7 +35,7 @@ func (r *Runner) ListCredentials(ctx context.Context) ([]params.ForgeCredentials
// there is a posibillity that not all creds will be in the cache. // there is a posibillity that not all creds will be in the cache.
creds, err := r.store.ListGithubCredentials(ctx) creds, err := r.store.ListGithubCredentials(ctx)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching github credentials") return nil, fmt.Errorf("error fetching github credentials: %w", err)
} }
// If we do have cache, update the rate limit for each credential. The rate limits are queried // If we do have cache, update the rate limit for each credential. The rate limits are queried
@ -57,12 +56,12 @@ func (r *Runner) CreateGithubCredentials(ctx context.Context, param params.Creat
} }
if err := param.Validate(); err != nil { if err := param.Validate(); err != nil {
return params.ForgeCredentials{}, errors.Wrap(err, "failed to validate github credentials params") return params.ForgeCredentials{}, fmt.Errorf("failed to validate github credentials params: %w", err)
} }
creds, err := r.store.CreateGithubCredentials(ctx, param) creds, err := r.store.CreateGithubCredentials(ctx, param)
if err != nil { if err != nil {
return params.ForgeCredentials{}, errors.Wrap(err, "failed to create github credentials") return params.ForgeCredentials{}, fmt.Errorf("failed to create github credentials: %w", err)
} }
return creds, nil return creds, nil
@ -75,7 +74,7 @@ func (r *Runner) GetGithubCredentials(ctx context.Context, id uint) (params.Forg
creds, err := r.store.GetGithubCredentials(ctx, id, true) creds, err := r.store.GetGithubCredentials(ctx, id, true)
if err != nil { if err != nil {
return params.ForgeCredentials{}, errors.Wrap(err, "failed to get github credentials") return params.ForgeCredentials{}, fmt.Errorf("failed to get github credentials: %w", err)
} }
cached, ok := cache.GetGithubCredentials((creds.ID)) cached, ok := cache.GetGithubCredentials((creds.ID))
@ -92,7 +91,7 @@ func (r *Runner) DeleteGithubCredentials(ctx context.Context, id uint) error {
} }
if err := r.store.DeleteGithubCredentials(ctx, id); err != nil { if err := r.store.DeleteGithubCredentials(ctx, id); err != nil {
return errors.Wrap(err, "failed to delete github credentials") return fmt.Errorf("failed to delete github credentials: %w", err)
} }
return nil return nil
@ -104,12 +103,12 @@ func (r *Runner) UpdateGithubCredentials(ctx context.Context, id uint, param par
} }
if err := param.Validate(); err != nil { if err := param.Validate(); err != nil {
return params.ForgeCredentials{}, errors.Wrap(err, "failed to validate github credentials params") return params.ForgeCredentials{}, fmt.Errorf("failed to validate github credentials params: %w", err)
} }
newCreds, err := r.store.UpdateGithubCredentials(ctx, id, param) newCreds, err := r.store.UpdateGithubCredentials(ctx, id, param)
if err != nil { if err != nil {
return params.ForgeCredentials{}, errors.Wrap(err, "failed to update github credentials") return params.ForgeCredentials{}, fmt.Errorf("failed to update github credentials: %w", err)
} }
return newCreds, nil return newCreds, nil

View file

@ -16,8 +16,7 @@ package runner
import ( import (
"context" "context"
"fmt"
"github.com/pkg/errors"
runnerErrors "github.com/cloudbase/garm-provider-common/errors" runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/auth" "github.com/cloudbase/garm/auth"
@ -30,12 +29,12 @@ func (r *Runner) CreateGithubEndpoint(ctx context.Context, param params.CreateGi
} }
if err := param.Validate(); err != nil { if err := param.Validate(); err != nil {
return params.ForgeEndpoint{}, errors.Wrap(err, "failed to validate github endpoint params") return params.ForgeEndpoint{}, fmt.Errorf("error failed to validate github endpoint params: %w", err)
} }
ep, err := r.store.CreateGithubEndpoint(ctx, param) ep, err := r.store.CreateGithubEndpoint(ctx, param)
if err != nil { if err != nil {
return params.ForgeEndpoint{}, errors.Wrap(err, "failed to create github endpoint") return params.ForgeEndpoint{}, fmt.Errorf("failed to create github endpoint: %w", err)
} }
return ep, nil return ep, nil
@ -47,7 +46,7 @@ func (r *Runner) GetGithubEndpoint(ctx context.Context, name string) (params.For
} }
endpoint, err := r.store.GetGithubEndpoint(ctx, name) endpoint, err := r.store.GetGithubEndpoint(ctx, name)
if err != nil { if err != nil {
return params.ForgeEndpoint{}, errors.Wrap(err, "failed to get github endpoint") return params.ForgeEndpoint{}, fmt.Errorf("failed to get github endpoint: %w", err)
} }
return endpoint, nil return endpoint, nil
@ -60,7 +59,7 @@ func (r *Runner) DeleteGithubEndpoint(ctx context.Context, name string) error {
err := r.store.DeleteGithubEndpoint(ctx, name) err := r.store.DeleteGithubEndpoint(ctx, name)
if err != nil { if err != nil {
return errors.Wrap(err, "failed to delete github endpoint") return fmt.Errorf("failed to delete github endpoint: %w", err)
} }
return nil return nil
@ -72,12 +71,12 @@ func (r *Runner) UpdateGithubEndpoint(ctx context.Context, name string, param pa
} }
if err := param.Validate(); err != nil { if err := param.Validate(); err != nil {
return params.ForgeEndpoint{}, errors.Wrap(err, "failed to validate github endpoint params") return params.ForgeEndpoint{}, fmt.Errorf("failed to validate github endpoint params: %w", err)
} }
newEp, err := r.store.UpdateGithubEndpoint(ctx, name, param) newEp, err := r.store.UpdateGithubEndpoint(ctx, name, param)
if err != nil { if err != nil {
return params.ForgeEndpoint{}, errors.Wrap(err, "failed to update github endpoint") return params.ForgeEndpoint{}, fmt.Errorf("failed to update github endpoint: %w", err)
} }
return newEp, nil return newEp, nil
} }
@ -89,7 +88,7 @@ func (r *Runner) ListGithubEndpoints(ctx context.Context) ([]params.ForgeEndpoin
endpoints, err := r.store.ListGithubEndpoints(ctx) endpoints, err := r.store.ListGithubEndpoints(ctx)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to list github endpoints") return nil, fmt.Errorf("failed to list github endpoints: %w", err)
} }
return endpoints, nil return endpoints, nil

View file

@ -18,12 +18,11 @@ import (
"bytes" "bytes"
"context" "context"
"encoding/base64" "encoding/base64"
"errors"
"fmt" "fmt"
"html/template" "html/template"
"log/slog" "log/slog"
"github.com/pkg/errors"
"github.com/cloudbase/garm-provider-common/defaults" "github.com/cloudbase/garm-provider-common/defaults"
runnerErrors "github.com/cloudbase/garm-provider-common/errors" runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/auth" "github.com/cloudbase/garm/auth"
@ -92,7 +91,7 @@ func (r *Runner) getForgeEntityFromInstance(ctx context.Context, instance params
slog.With(slog.Any("error", err)).ErrorContext( slog.With(slog.Any("error", err)).ErrorContext(
ctx, "failed to get entity getter", ctx, "failed to get entity getter",
"instance", instance.Name) "instance", instance.Name)
return params.ForgeEntity{}, errors.Wrap(err, "fetching entity getter") return params.ForgeEntity{}, fmt.Errorf("error fetching entity getter: %w", err)
} }
poolEntity, err := entityGetter.GetEntity() poolEntity, err := entityGetter.GetEntity()
@ -100,7 +99,7 @@ func (r *Runner) getForgeEntityFromInstance(ctx context.Context, instance params
slog.With(slog.Any("error", err)).ErrorContext( slog.With(slog.Any("error", err)).ErrorContext(
ctx, "failed to get entity", ctx, "failed to get entity",
"instance", instance.Name) "instance", instance.Name)
return params.ForgeEntity{}, errors.Wrap(err, "fetching entity") return params.ForgeEntity{}, fmt.Errorf("error fetching entity: %w", err)
} }
entity, err := r.store.GetForgeEntity(r.ctx, poolEntity.EntityType, poolEntity.ID) entity, err := r.store.GetForgeEntity(r.ctx, poolEntity.EntityType, poolEntity.ID)
@ -108,7 +107,7 @@ func (r *Runner) getForgeEntityFromInstance(ctx context.Context, instance params
slog.With(slog.Any("error", err)).ErrorContext( slog.With(slog.Any("error", err)).ErrorContext(
ctx, "failed to get entity", ctx, "failed to get entity",
"instance", instance.Name) "instance", instance.Name)
return params.ForgeEntity{}, errors.Wrap(err, "fetching entity") return params.ForgeEntity{}, fmt.Errorf("error fetching entity: %w", err)
} }
return entity, nil return entity, nil
} }
@ -136,13 +135,13 @@ func (r *Runner) GetRunnerServiceName(ctx context.Context) (string, error) {
entity, err := r.getForgeEntityFromInstance(ctx, instance) entity, err := r.getForgeEntityFromInstance(ctx, instance)
if err != nil { if err != nil {
slog.ErrorContext(r.ctx, "failed to get entity", "error", err) slog.ErrorContext(r.ctx, "failed to get entity", "error", err)
return "", errors.Wrap(err, "fetching entity") return "", fmt.Errorf("error fetching entity: %w", err)
} }
serviceName, err := r.getServiceNameForEntity(entity) serviceName, err := r.getServiceNameForEntity(entity)
if err != nil { if err != nil {
slog.ErrorContext(r.ctx, "failed to get service name", "error", err) slog.ErrorContext(r.ctx, "failed to get service name", "error", err)
return "", errors.Wrap(err, "fetching service name") return "", fmt.Errorf("error fetching service name: %w", err)
} }
return serviceName, nil return serviceName, nil
} }
@ -157,13 +156,13 @@ func (r *Runner) GenerateSystemdUnitFile(ctx context.Context, runAsUser string)
entity, err := r.getForgeEntityFromInstance(ctx, instance) entity, err := r.getForgeEntityFromInstance(ctx, instance)
if err != nil { if err != nil {
slog.ErrorContext(r.ctx, "failed to get entity", "error", err) slog.ErrorContext(r.ctx, "failed to get entity", "error", err)
return nil, errors.Wrap(err, "fetching entity") return nil, fmt.Errorf("error fetching entity: %w", err)
} }
serviceName, err := r.getServiceNameForEntity(entity) serviceName, err := r.getServiceNameForEntity(entity)
if err != nil { if err != nil {
slog.ErrorContext(r.ctx, "failed to get service name", "error", err) slog.ErrorContext(r.ctx, "failed to get service name", "error", err)
return nil, errors.Wrap(err, "fetching service name") return nil, fmt.Errorf("error fetching service name: %w", err)
} }
var unitTemplate *template.Template var unitTemplate *template.Template
@ -178,7 +177,7 @@ func (r *Runner) GenerateSystemdUnitFile(ctx context.Context, runAsUser string)
} }
if err != nil { if err != nil {
slog.ErrorContext(r.ctx, "failed to parse template", "error", err) slog.ErrorContext(r.ctx, "failed to parse template", "error", err)
return nil, errors.Wrap(err, "parsing template") return nil, fmt.Errorf("error parsing template: %w", err)
} }
if runAsUser == "" { if runAsUser == "" {
@ -196,14 +195,14 @@ func (r *Runner) GenerateSystemdUnitFile(ctx context.Context, runAsUser string)
var unitFile bytes.Buffer var unitFile bytes.Buffer
if err := unitTemplate.Execute(&unitFile, data); err != nil { if err := unitTemplate.Execute(&unitFile, data); err != nil {
slog.ErrorContext(r.ctx, "failed to execute template", "error", err) slog.ErrorContext(r.ctx, "failed to execute template", "error", err)
return nil, errors.Wrap(err, "executing template") return nil, fmt.Errorf("error executing template: %w", err)
} }
return unitFile.Bytes(), nil return unitFile.Bytes(), nil
} }
func (r *Runner) GetJITConfigFile(ctx context.Context, file string) ([]byte, error) { func (r *Runner) GetJITConfigFile(ctx context.Context, file string) ([]byte, error) {
if !auth.InstanceHasJITConfig(ctx) { if !auth.InstanceHasJITConfig(ctx) {
return nil, fmt.Errorf("instance not configured for JIT: %w", runnerErrors.ErrNotFound) return nil, runnerErrors.NewNotFoundError("instance not configured for JIT")
} }
instance, err := validateInstanceState(ctx) instance, err := validateInstanceState(ctx)
@ -215,12 +214,12 @@ func (r *Runner) GetJITConfigFile(ctx context.Context, file string) ([]byte, err
jitConfig := instance.JitConfiguration jitConfig := instance.JitConfiguration
contents, ok := jitConfig[file] contents, ok := jitConfig[file]
if !ok { if !ok {
return nil, errors.Wrap(runnerErrors.ErrNotFound, "retrieving file") return nil, runnerErrors.NewNotFoundError("could not find file %q", file)
} }
decoded, err := base64.StdEncoding.DecodeString(contents) decoded, err := base64.StdEncoding.DecodeString(contents)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "decoding file contents") return nil, fmt.Errorf("error decoding file contents: %w", err)
} }
return decoded, nil return decoded, nil
@ -249,12 +248,12 @@ func (r *Runner) GetInstanceGithubRegistrationToken(ctx context.Context) (string
poolMgr, err := r.getPoolManagerFromInstance(ctx, instance) poolMgr, err := r.getPoolManagerFromInstance(ctx, instance)
if err != nil { if err != nil {
return "", errors.Wrap(err, "fetching pool manager for instance") return "", fmt.Errorf("error fetching pool manager for instance: %w", err)
} }
token, err := poolMgr.GithubRunnerRegistrationToken() token, err := poolMgr.GithubRunnerRegistrationToken()
if err != nil { if err != nil {
return "", errors.Wrap(err, "fetching runner token") return "", fmt.Errorf("error fetching runner token: %w", err)
} }
tokenFetched := true tokenFetched := true
@ -263,11 +262,11 @@ func (r *Runner) GetInstanceGithubRegistrationToken(ctx context.Context) (string
} }
if _, err := r.store.UpdateInstance(r.ctx, instance.Name, updateParams); err != nil { if _, err := r.store.UpdateInstance(r.ctx, instance.Name, updateParams); err != nil {
return "", errors.Wrap(err, "setting token_fetched for instance") return "", fmt.Errorf("error setting token_fetched for instance: %w", err)
} }
if err := r.store.AddInstanceEvent(ctx, instance.Name, params.FetchTokenEvent, params.EventInfo, "runner registration token was retrieved"); err != nil { if err := r.store.AddInstanceEvent(ctx, instance.Name, params.FetchTokenEvent, params.EventInfo, "runner registration token was retrieved"); err != nil {
return "", errors.Wrap(err, "recording event") return "", fmt.Errorf("error recording event: %w", err)
} }
return token, nil return token, nil
@ -283,7 +282,7 @@ func (r *Runner) GetRootCertificateBundle(ctx context.Context) (params.Certifica
poolMgr, err := r.getPoolManagerFromInstance(ctx, instance) poolMgr, err := r.getPoolManagerFromInstance(ctx, instance)
if err != nil { if err != nil {
return params.CertificateBundle{}, errors.Wrap(err, "fetching pool manager for instance") return params.CertificateBundle{}, fmt.Errorf("error fetching pool manager for instance: %w", err)
} }
bundle, err := poolMgr.RootCABundle() bundle, err := poolMgr.RootCABundle()

View file

@ -16,12 +16,11 @@ package runner
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"log/slog" "log/slog"
"strings" "strings"
"github.com/pkg/errors"
runnerErrors "github.com/cloudbase/garm-provider-common/errors" runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/auth" "github.com/cloudbase/garm/auth"
"github.com/cloudbase/garm/params" "github.com/cloudbase/garm/params"
@ -35,7 +34,7 @@ func (r *Runner) CreateOrganization(ctx context.Context, param params.CreateOrgP
} }
if err := param.Validate(); err != nil { if err := param.Validate(); err != nil {
return params.Organization{}, errors.Wrap(err, "validating params") return params.Organization{}, fmt.Errorf("error validating params: %w", err)
} }
var creds params.ForgeCredentials var creds params.ForgeCredentials
@ -57,7 +56,7 @@ func (r *Runner) CreateOrganization(ctx context.Context, param params.CreateOrgP
_, err = r.store.GetOrganization(ctx, param.Name, creds.Endpoint.Name) _, err = r.store.GetOrganization(ctx, param.Name, creds.Endpoint.Name)
if err != nil { if err != nil {
if !errors.Is(err, runnerErrors.ErrNotFound) { if !errors.Is(err, runnerErrors.ErrNotFound) {
return params.Organization{}, errors.Wrap(err, "fetching org") return params.Organization{}, fmt.Errorf("error fetching org: %w", err)
} }
} else { } else {
return params.Organization{}, runnerErrors.NewConflictError("organization %s already exists", param.Name) return params.Organization{}, runnerErrors.NewConflictError("organization %s already exists", param.Name)
@ -65,7 +64,7 @@ func (r *Runner) CreateOrganization(ctx context.Context, param params.CreateOrgP
org, err = r.store.CreateOrganization(ctx, param.Name, creds, param.WebhookSecret, param.PoolBalancerType) org, err = r.store.CreateOrganization(ctx, param.Name, creds, param.WebhookSecret, param.PoolBalancerType)
if err != nil { if err != nil {
return params.Organization{}, errors.Wrap(err, "creating organization") return params.Organization{}, fmt.Errorf("error creating organization: %w", err)
} }
defer func() { defer func() {
@ -82,7 +81,7 @@ func (r *Runner) CreateOrganization(ctx context.Context, param params.CreateOrgP
// updating the store. // updating the store.
poolMgr, err := r.poolManagerCtrl.CreateOrgPoolManager(r.ctx, org, r.providers, r.store) poolMgr, err := r.poolManagerCtrl.CreateOrgPoolManager(r.ctx, org, r.providers, r.store)
if err != nil { if err != nil {
return params.Organization{}, errors.Wrap(err, "creating org pool manager") return params.Organization{}, fmt.Errorf("error creating org pool manager: %w", err)
} }
if err := poolMgr.Start(); err != nil { if err := poolMgr.Start(); err != nil {
if deleteErr := r.poolManagerCtrl.DeleteOrgPoolManager(org); deleteErr != nil { if deleteErr := r.poolManagerCtrl.DeleteOrgPoolManager(org); deleteErr != nil {
@ -90,7 +89,7 @@ func (r *Runner) CreateOrganization(ctx context.Context, param params.CreateOrgP
ctx, "failed to cleanup pool manager for org", ctx, "failed to cleanup pool manager for org",
"org_id", org.ID) "org_id", org.ID)
} }
return params.Organization{}, errors.Wrap(err, "starting org pool manager") return params.Organization{}, fmt.Errorf("error starting org pool manager: %w", err)
} }
return org, nil return org, nil
} }
@ -102,7 +101,7 @@ func (r *Runner) ListOrganizations(ctx context.Context, filter params.Organizati
orgs, err := r.store.ListOrganizations(ctx, filter) orgs, err := r.store.ListOrganizations(ctx, filter)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "listing organizations") return nil, fmt.Errorf("error listing organizations: %w", err)
} }
var allOrgs []params.Organization var allOrgs []params.Organization
@ -129,7 +128,7 @@ func (r *Runner) GetOrganizationByID(ctx context.Context, orgID string) (params.
org, err := r.store.GetOrganizationByID(ctx, orgID) org, err := r.store.GetOrganizationByID(ctx, orgID)
if err != nil { if err != nil {
return params.Organization{}, errors.Wrap(err, "fetching organization") return params.Organization{}, fmt.Errorf("error fetching organization: %w", err)
} }
poolMgr, err := r.poolManagerCtrl.GetOrgPoolManager(org) poolMgr, err := r.poolManagerCtrl.GetOrgPoolManager(org)
@ -148,17 +147,17 @@ func (r *Runner) DeleteOrganization(ctx context.Context, orgID string, keepWebho
org, err := r.store.GetOrganizationByID(ctx, orgID) org, err := r.store.GetOrganizationByID(ctx, orgID)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching org") return fmt.Errorf("error fetching org: %w", err)
} }
entity, err := org.GetEntity() entity, err := org.GetEntity()
if err != nil { if err != nil {
return errors.Wrap(err, "getting entity") return fmt.Errorf("error getting entity: %w", err)
} }
pools, err := r.store.ListEntityPools(ctx, entity) pools, err := r.store.ListEntityPools(ctx, entity)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching org pools") return fmt.Errorf("error fetching org pools: %w", err)
} }
if len(pools) > 0 { if len(pools) > 0 {
@ -172,7 +171,7 @@ func (r *Runner) DeleteOrganization(ctx context.Context, orgID string, keepWebho
scaleSets, err := r.store.ListEntityScaleSets(ctx, entity) scaleSets, err := r.store.ListEntityScaleSets(ctx, entity)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching organization scale sets") return fmt.Errorf("error fetching organization scale sets: %w", err)
} }
if len(scaleSets) > 0 { if len(scaleSets) > 0 {
@ -182,7 +181,7 @@ func (r *Runner) DeleteOrganization(ctx context.Context, orgID string, keepWebho
if !keepWebhook && r.config.Default.EnableWebhookManagement { if !keepWebhook && r.config.Default.EnableWebhookManagement {
poolMgr, err := r.poolManagerCtrl.GetOrgPoolManager(org) poolMgr, err := r.poolManagerCtrl.GetOrgPoolManager(org)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching pool manager") return fmt.Errorf("error fetching pool manager: %w", err)
} }
if err := poolMgr.UninstallWebhook(ctx); err != nil { if err := poolMgr.UninstallWebhook(ctx); err != nil {
@ -195,11 +194,11 @@ func (r *Runner) DeleteOrganization(ctx context.Context, orgID string, keepWebho
} }
if err := r.poolManagerCtrl.DeleteOrgPoolManager(org); err != nil { if err := r.poolManagerCtrl.DeleteOrgPoolManager(org); err != nil {
return errors.Wrap(err, "deleting org pool manager") return fmt.Errorf("error deleting org pool manager: %w", err)
} }
if err := r.store.DeleteOrganization(ctx, orgID); err != nil { if err := r.store.DeleteOrganization(ctx, orgID); err != nil {
return errors.Wrapf(err, "removing organization %s", orgID) return fmt.Errorf("error removing organization %s: %w", orgID, err)
} }
return nil return nil
} }
@ -220,7 +219,7 @@ func (r *Runner) UpdateOrganization(ctx context.Context, orgID string, param par
org, err := r.store.UpdateOrganization(ctx, orgID, param) org, err := r.store.UpdateOrganization(ctx, orgID, param)
if err != nil { if err != nil {
return params.Organization{}, errors.Wrap(err, "updating org") return params.Organization{}, fmt.Errorf("error updating org: %w", err)
} }
poolMgr, err := r.poolManagerCtrl.GetOrgPoolManager(org) poolMgr, err := r.poolManagerCtrl.GetOrgPoolManager(org)
@ -239,7 +238,7 @@ func (r *Runner) CreateOrgPool(ctx context.Context, orgID string, param params.C
createPoolParams, err := r.appendTagsToCreatePoolParams(param) createPoolParams, err := r.appendTagsToCreatePoolParams(param)
if err != nil { if err != nil {
return params.Pool{}, errors.Wrap(err, "fetching pool params") return params.Pool{}, fmt.Errorf("error fetching pool params: %w", err)
} }
if param.RunnerBootstrapTimeout == 0 { if param.RunnerBootstrapTimeout == 0 {
@ -253,7 +252,7 @@ func (r *Runner) CreateOrgPool(ctx context.Context, orgID string, param params.C
pool, err := r.store.CreateEntityPool(ctx, entity, createPoolParams) pool, err := r.store.CreateEntityPool(ctx, entity, createPoolParams)
if err != nil { if err != nil {
return params.Pool{}, errors.Wrap(err, "creating pool") return params.Pool{}, fmt.Errorf("error creating pool: %w", err)
} }
return pool, nil return pool, nil
@ -271,7 +270,7 @@ func (r *Runner) GetOrgPoolByID(ctx context.Context, orgID, poolID string) (para
pool, err := r.store.GetEntityPool(ctx, entity, poolID) pool, err := r.store.GetEntityPool(ctx, entity, poolID)
if err != nil { if err != nil {
return params.Pool{}, errors.Wrap(err, "fetching pool") return params.Pool{}, fmt.Errorf("error fetching pool: %w", err)
} }
return pool, nil return pool, nil
@ -290,7 +289,7 @@ func (r *Runner) DeleteOrgPool(ctx context.Context, orgID, poolID string) error
pool, err := r.store.GetEntityPool(ctx, entity, poolID) pool, err := r.store.GetEntityPool(ctx, entity, poolID)
if err != nil { if err != nil {
if !errors.Is(err, runnerErrors.ErrNotFound) { if !errors.Is(err, runnerErrors.ErrNotFound) {
return errors.Wrap(err, "fetching pool") return fmt.Errorf("error fetching pool: %w", err)
} }
return nil return nil
} }
@ -306,7 +305,7 @@ func (r *Runner) DeleteOrgPool(ctx context.Context, orgID, poolID string) error
} }
if err := r.store.DeleteEntityPool(ctx, entity, poolID); err != nil { if err := r.store.DeleteEntityPool(ctx, entity, poolID); err != nil {
return errors.Wrap(err, "deleting pool") return fmt.Errorf("error deleting pool: %w", err)
} }
return nil return nil
} }
@ -321,7 +320,7 @@ func (r *Runner) ListOrgPools(ctx context.Context, orgID string) ([]params.Pool,
} }
pools, err := r.store.ListEntityPools(ctx, entity) pools, err := r.store.ListEntityPools(ctx, entity)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching pools") return nil, fmt.Errorf("error fetching pools: %w", err)
} }
return pools, nil return pools, nil
} }
@ -338,7 +337,7 @@ func (r *Runner) UpdateOrgPool(ctx context.Context, orgID, poolID string, param
pool, err := r.store.GetEntityPool(ctx, entity, poolID) pool, err := r.store.GetEntityPool(ctx, entity, poolID)
if err != nil { if err != nil {
return params.Pool{}, errors.Wrap(err, "fetching pool") return params.Pool{}, fmt.Errorf("error fetching pool: %w", err)
} }
maxRunners := pool.MaxRunners maxRunners := pool.MaxRunners
@ -357,7 +356,7 @@ func (r *Runner) UpdateOrgPool(ctx context.Context, orgID, poolID string, param
newPool, err := r.store.UpdateEntityPool(ctx, entity, poolID, param) newPool, err := r.store.UpdateEntityPool(ctx, entity, poolID, param)
if err != nil { if err != nil {
return params.Pool{}, errors.Wrap(err, "updating pool") return params.Pool{}, fmt.Errorf("error updating pool: %w", err)
} }
return newPool, nil return newPool, nil
} }
@ -374,7 +373,7 @@ func (r *Runner) ListOrgInstances(ctx context.Context, orgID string) ([]params.I
instances, err := r.store.ListEntityInstances(ctx, entity) instances, err := r.store.ListEntityInstances(ctx, entity)
if err != nil { if err != nil {
return []params.Instance{}, errors.Wrap(err, "fetching instances") return []params.Instance{}, fmt.Errorf("error fetching instances: %w", err)
} }
return instances, nil return instances, nil
} }
@ -385,12 +384,12 @@ func (r *Runner) findOrgPoolManager(name, endpointName string) (common.PoolManag
org, err := r.store.GetOrganization(r.ctx, name, endpointName) org, err := r.store.GetOrganization(r.ctx, name, endpointName)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching org") return nil, fmt.Errorf("error fetching org: %w", err)
} }
poolManager, err := r.poolManagerCtrl.GetOrgPoolManager(org) poolManager, err := r.poolManagerCtrl.GetOrgPoolManager(org)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching pool manager for org") return nil, fmt.Errorf("error fetching pool manager for org: %w", err)
} }
return poolManager, nil return poolManager, nil
} }
@ -402,17 +401,17 @@ func (r *Runner) InstallOrgWebhook(ctx context.Context, orgID string, param para
org, err := r.store.GetOrganizationByID(ctx, orgID) org, err := r.store.GetOrganizationByID(ctx, orgID)
if err != nil { if err != nil {
return params.HookInfo{}, errors.Wrap(err, "fetching org") return params.HookInfo{}, fmt.Errorf("error fetching org: %w", err)
} }
poolMgr, err := r.poolManagerCtrl.GetOrgPoolManager(org) poolMgr, err := r.poolManagerCtrl.GetOrgPoolManager(org)
if err != nil { if err != nil {
return params.HookInfo{}, errors.Wrap(err, "fetching pool manager for org") return params.HookInfo{}, fmt.Errorf("error fetching pool manager for org: %w", err)
} }
info, err := poolMgr.InstallWebhook(ctx, param) info, err := poolMgr.InstallWebhook(ctx, param)
if err != nil { if err != nil {
return params.HookInfo{}, errors.Wrap(err, "installing webhook") return params.HookInfo{}, fmt.Errorf("error installing webhook: %w", err)
} }
return info, nil return info, nil
} }
@ -424,16 +423,16 @@ func (r *Runner) UninstallOrgWebhook(ctx context.Context, orgID string) error {
org, err := r.store.GetOrganizationByID(ctx, orgID) org, err := r.store.GetOrganizationByID(ctx, orgID)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching org") return fmt.Errorf("error fetching org: %w", err)
} }
poolMgr, err := r.poolManagerCtrl.GetOrgPoolManager(org) poolMgr, err := r.poolManagerCtrl.GetOrgPoolManager(org)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching pool manager for org") return fmt.Errorf("error fetching pool manager for org: %w", err)
} }
if err := poolMgr.UninstallWebhook(ctx); err != nil { if err := poolMgr.UninstallWebhook(ctx); err != nil {
return errors.Wrap(err, "uninstalling webhook") return fmt.Errorf("error uninstalling webhook: %w", err)
} }
return nil return nil
} }
@ -445,17 +444,17 @@ func (r *Runner) GetOrgWebhookInfo(ctx context.Context, orgID string) (params.Ho
org, err := r.store.GetOrganizationByID(ctx, orgID) org, err := r.store.GetOrganizationByID(ctx, orgID)
if err != nil { if err != nil {
return params.HookInfo{}, errors.Wrap(err, "fetching org") return params.HookInfo{}, fmt.Errorf("error fetching org: %w", err)
} }
poolMgr, err := r.poolManagerCtrl.GetOrgPoolManager(org) poolMgr, err := r.poolManagerCtrl.GetOrgPoolManager(org)
if err != nil { if err != nil {
return params.HookInfo{}, errors.Wrap(err, "fetching pool manager for org") return params.HookInfo{}, fmt.Errorf("error fetching pool manager for org: %w", err)
} }
info, err := poolMgr.GetWebhookInfo(ctx) info, err := poolMgr.GetWebhookInfo(ctx)
if err != nil { if err != nil {
return params.HookInfo{}, errors.Wrap(err, "fetching webhook info") return params.HookInfo{}, fmt.Errorf("error fetching webhook info: %w", err)
} }
return info, nil return info, nil
} }

View file

@ -16,10 +16,10 @@ package runner
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"testing" "testing"
"github.com/pkg/errors"
"github.com/stretchr/testify/mock" "github.com/stretchr/testify/mock"
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
@ -224,7 +224,7 @@ func (s *OrgTestSuite) TestCreateOrganizationPoolMgrFailed() {
s.Fixtures.PoolMgrMock.AssertExpectations(s.T()) s.Fixtures.PoolMgrMock.AssertExpectations(s.T())
s.Fixtures.PoolMgrCtrlMock.AssertExpectations(s.T()) s.Fixtures.PoolMgrCtrlMock.AssertExpectations(s.T())
s.Require().Equal(fmt.Sprintf("creating org pool manager: %s", s.Fixtures.ErrMock.Error()), err.Error()) s.Require().Equal(fmt.Sprintf("error creating org pool manager: %s", s.Fixtures.ErrMock.Error()), err.Error())
} }
func (s *OrgTestSuite) TestCreateOrganizationStartPoolMgrFailed() { func (s *OrgTestSuite) TestCreateOrganizationStartPoolMgrFailed() {
@ -236,7 +236,7 @@ func (s *OrgTestSuite) TestCreateOrganizationStartPoolMgrFailed() {
s.Fixtures.PoolMgrMock.AssertExpectations(s.T()) s.Fixtures.PoolMgrMock.AssertExpectations(s.T())
s.Fixtures.PoolMgrCtrlMock.AssertExpectations(s.T()) s.Fixtures.PoolMgrCtrlMock.AssertExpectations(s.T())
s.Require().Equal(fmt.Sprintf("starting org pool manager: %s", s.Fixtures.ErrMock.Error()), err.Error()) s.Require().Equal(fmt.Sprintf("error starting org pool manager: %s", s.Fixtures.ErrMock.Error()), err.Error())
} }
func (s *OrgTestSuite) TestListOrganizations() { func (s *OrgTestSuite) TestListOrganizations() {
@ -338,7 +338,7 @@ func (s *OrgTestSuite) TestDeleteOrganization() {
s.Require().Nil(err) s.Require().Nil(err)
_, err = s.Fixtures.Store.GetOrganizationByID(s.Fixtures.AdminContext, s.Fixtures.StoreOrgs["test-org-3"].ID) _, err = s.Fixtures.Store.GetOrganizationByID(s.Fixtures.AdminContext, s.Fixtures.StoreOrgs["test-org-3"].ID)
s.Require().Equal("fetching org: not found", err.Error()) s.Require().Equal("error fetching org: not found", err.Error())
} }
func (s *OrgTestSuite) TestDeleteOrganizationErrUnauthorized() { func (s *OrgTestSuite) TestDeleteOrganizationErrUnauthorized() {
@ -368,7 +368,7 @@ func (s *OrgTestSuite) TestDeleteOrganizationPoolMgrFailed() {
err := s.Runner.DeleteOrganization(s.Fixtures.AdminContext, s.Fixtures.StoreOrgs["test-org-1"].ID, true) err := s.Runner.DeleteOrganization(s.Fixtures.AdminContext, s.Fixtures.StoreOrgs["test-org-1"].ID, true)
s.Fixtures.PoolMgrCtrlMock.AssertExpectations(s.T()) s.Fixtures.PoolMgrCtrlMock.AssertExpectations(s.T())
s.Require().Equal(fmt.Sprintf("deleting org pool manager: %s", s.Fixtures.ErrMock.Error()), err.Error()) s.Require().Equal(fmt.Sprintf("error deleting org pool manager: %s", s.Fixtures.ErrMock.Error()), err.Error())
} }
func (s *OrgTestSuite) TestUpdateOrganization() { func (s *OrgTestSuite) TestUpdateOrganization() {
@ -502,7 +502,7 @@ func (s *OrgTestSuite) TestDeleteOrgPool() {
s.Require().Nil(err) s.Require().Nil(err)
_, err = s.Fixtures.Store.GetEntityPool(s.Fixtures.AdminContext, entity, pool.ID) _, err = s.Fixtures.Store.GetEntityPool(s.Fixtures.AdminContext, entity, pool.ID)
s.Require().Equal("fetching pool: finding pool: not found", err.Error()) s.Require().Equal("fetching pool: error finding pool: not found", err.Error())
} }
func (s *OrgTestSuite) TestDeleteOrgPoolErrUnauthorized() { func (s *OrgTestSuite) TestDeleteOrgPoolErrUnauthorized() {

View file

@ -16,12 +16,12 @@ package pool
import ( import (
"context" "context"
"fmt"
"net/http" "net/http"
"net/url" "net/url"
"strings" "strings"
"github.com/google/go-github/v72/github" "github.com/google/go-github/v72/github"
"github.com/pkg/errors"
runnerErrors "github.com/cloudbase/garm-provider-common/errors" runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/params" "github.com/cloudbase/garm/params"
@ -30,7 +30,7 @@ import (
func validateHookRequest(controllerID, baseURL string, allHooks []*github.Hook, req *github.Hook) error { func validateHookRequest(controllerID, baseURL string, allHooks []*github.Hook, req *github.Hook) error {
parsed, err := url.Parse(baseURL) parsed, err := url.Parse(baseURL)
if err != nil { if err != nil {
return errors.Wrap(err, "parsing webhook url") return fmt.Errorf("error parsing webhook url: %w", err)
} }
partialMatches := []string{} partialMatches := []string{}
@ -80,7 +80,7 @@ func (r *basePoolManager) listHooks(ctx context.Context) ([]*github.Hook, error)
if ghResp != nil && ghResp.StatusCode == http.StatusNotFound { if ghResp != nil && ghResp.StatusCode == http.StatusNotFound {
return nil, runnerErrors.NewBadRequestError("repository not found or your PAT does not have access to manage webhooks") return nil, runnerErrors.NewBadRequestError("repository not found or your PAT does not have access to manage webhooks")
} }
return nil, errors.Wrap(err, "fetching hooks") return nil, fmt.Errorf("error fetching hooks: %w", err)
} }
allHooks = append(allHooks, hooks...) allHooks = append(allHooks, hooks...)
if ghResp.NextPage == 0 { if ghResp.NextPage == 0 {

View file

@ -17,6 +17,7 @@ package pool
import ( import (
"context" "context"
"crypto/rand" "crypto/rand"
"errors"
"fmt" "fmt"
"log/slog" "log/slog"
"math" "math"
@ -29,7 +30,6 @@ import (
"github.com/google/go-github/v72/github" "github.com/google/go-github/v72/github"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/pkg/errors"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
runnerErrors "github.com/cloudbase/garm-provider-common/errors" runnerErrors "github.com/cloudbase/garm-provider-common/errors"
@ -76,16 +76,16 @@ func NewEntityPoolManager(ctx context.Context, entity params.ForgeEntity, instan
) )
ghc, err := ghClient.Client(ctx, entity) ghc, err := ghClient.Client(ctx, entity)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "getting github client") return nil, fmt.Errorf("error getting github client: %w", err)
} }
if entity.WebhookSecret == "" { if entity.WebhookSecret == "" {
return nil, errors.New("webhook secret is empty") return nil, fmt.Errorf("webhook secret is empty")
} }
controllerInfo, err := store.ControllerInfo() controllerInfo, err := store.ControllerInfo()
if err != nil { if err != nil {
return nil, errors.Wrap(err, "getting controller info") return nil, fmt.Errorf("error getting controller info: %w", err)
} }
consumerID := fmt.Sprintf("pool-manager-%s-%s", entity.String(), entity.Credentials.Endpoint.Name) consumerID := fmt.Sprintf("pool-manager-%s-%s", entity.String(), entity.Credentials.Endpoint.Name)
@ -95,13 +95,13 @@ func NewEntityPoolManager(ctx context.Context, entity params.ForgeEntity, instan
composeWatcherFilters(entity), composeWatcherFilters(entity),
) )
if err != nil { if err != nil {
return nil, errors.Wrap(err, "registering consumer") return nil, fmt.Errorf("error registering consumer: %w", err)
} }
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
backoff, err := locking.NewInstanceDeleteBackoff(ctx) backoff, err := locking.NewInstanceDeleteBackoff(ctx)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "creating backoff") return nil, fmt.Errorf("error creating backoff: %w", err)
} }
repo := &basePoolManager{ repo := &basePoolManager{
@ -158,7 +158,7 @@ func (r *basePoolManager) getProviderBaseParams(pool params.Pool) common.Provide
func (r *basePoolManager) HandleWorkflowJob(job params.WorkflowJob) error { func (r *basePoolManager) HandleWorkflowJob(job params.WorkflowJob) error {
if err := r.ValidateOwner(job); err != nil { if err := r.ValidateOwner(job); err != nil {
slog.ErrorContext(r.ctx, "failed to validate owner", "error", err) slog.ErrorContext(r.ctx, "failed to validate owner", "error", err)
return errors.Wrap(err, "validating owner") return fmt.Errorf("error validating owner: %w", err)
} }
// we see events where the lables seem to be missing. We should ignore these // we see events where the lables seem to be missing. We should ignore these
@ -171,7 +171,7 @@ func (r *basePoolManager) HandleWorkflowJob(job params.WorkflowJob) error {
jobParams, err := r.paramsWorkflowJobToParamsJob(job) jobParams, err := r.paramsWorkflowJobToParamsJob(job)
if err != nil { if err != nil {
slog.ErrorContext(r.ctx, "failed to convert job to params", "error", err) slog.ErrorContext(r.ctx, "failed to convert job to params", "error", err)
return errors.Wrap(err, "converting job to params") return fmt.Errorf("error converting job to params: %w", err)
} }
var triggeredBy int64 var triggeredBy int64
@ -249,7 +249,7 @@ func (r *basePoolManager) HandleWorkflowJob(job params.WorkflowJob) error {
slog.With(slog.Any("error", err)).ErrorContext( slog.With(slog.Any("error", err)).ErrorContext(
r.ctx, "failed to update runner status", r.ctx, "failed to update runner status",
"runner_name", util.SanitizeLogEntry(jobParams.RunnerName)) "runner_name", util.SanitizeLogEntry(jobParams.RunnerName))
return errors.Wrap(err, "updating runner") return fmt.Errorf("error updating runner: %w", err)
} }
slog.DebugContext( slog.DebugContext(
r.ctx, "marking instance as pending_delete", r.ctx, "marking instance as pending_delete",
@ -261,7 +261,7 @@ func (r *basePoolManager) HandleWorkflowJob(job params.WorkflowJob) error {
slog.With(slog.Any("error", err)).ErrorContext( slog.With(slog.Any("error", err)).ErrorContext(
r.ctx, "failed to update runner status", r.ctx, "failed to update runner status",
"runner_name", util.SanitizeLogEntry(jobParams.RunnerName)) "runner_name", util.SanitizeLogEntry(jobParams.RunnerName))
return errors.Wrap(err, "updating runner") return fmt.Errorf("error updating runner: %w", err)
} }
case "in_progress": case "in_progress":
fromCache, ok := cache.GetInstanceCache(jobParams.RunnerName) fromCache, ok := cache.GetInstanceCache(jobParams.RunnerName)
@ -284,7 +284,7 @@ func (r *basePoolManager) HandleWorkflowJob(job params.WorkflowJob) error {
slog.With(slog.Any("error", err)).ErrorContext( slog.With(slog.Any("error", err)).ErrorContext(
r.ctx, "failed to update runner status", r.ctx, "failed to update runner status",
"runner_name", util.SanitizeLogEntry(jobParams.RunnerName)) "runner_name", util.SanitizeLogEntry(jobParams.RunnerName))
return errors.Wrap(err, "updating runner") return fmt.Errorf("error updating runner: %w", err)
} }
// Set triggeredBy here so we break the lock on any potential queued job. // Set triggeredBy here so we break the lock on any potential queued job.
triggeredBy = jobIDFromLabels(instance.AditionalLabels) triggeredBy = jobIDFromLabels(instance.AditionalLabels)
@ -396,7 +396,7 @@ func (r *basePoolManager) updateTools() error {
func (r *basePoolManager) cleanupOrphanedProviderRunners(runners []*github.Runner) error { func (r *basePoolManager) cleanupOrphanedProviderRunners(runners []*github.Runner) error {
dbInstances, err := r.store.ListEntityInstances(r.ctx, r.entity) dbInstances, err := r.store.ListEntityInstances(r.ctx, r.entity)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching instances from db") return fmt.Errorf("error fetching instances from db: %w", err)
} }
runnerNames := map[string]bool{} runnerNames := map[string]bool{}
@ -435,7 +435,7 @@ func (r *basePoolManager) cleanupOrphanedProviderRunners(runners []*github.Runne
} }
pool, err := r.store.GetEntityPool(r.ctx, r.entity, instance.PoolID) pool, err := r.store.GetEntityPool(r.ctx, r.entity, instance.PoolID)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching instance pool info") return fmt.Errorf("error fetching instance pool info: %w", err)
} }
switch instance.RunnerStatus { switch instance.RunnerStatus {
@ -463,7 +463,7 @@ func (r *basePoolManager) cleanupOrphanedProviderRunners(runners []*github.Runne
slog.With(slog.Any("error", err)).ErrorContext( slog.With(slog.Any("error", err)).ErrorContext(
r.ctx, "failed to update runner", r.ctx, "failed to update runner",
"runner_name", instance.Name) "runner_name", instance.Name)
return errors.Wrap(err, "updating runner") return fmt.Errorf("error updating runner: %w", err)
} }
} }
} }
@ -476,7 +476,7 @@ func (r *basePoolManager) cleanupOrphanedProviderRunners(runners []*github.Runne
func (r *basePoolManager) reapTimedOutRunners(runners []*github.Runner) error { func (r *basePoolManager) reapTimedOutRunners(runners []*github.Runner) error {
dbInstances, err := r.store.ListEntityInstances(r.ctx, r.entity) dbInstances, err := r.store.ListEntityInstances(r.ctx, r.entity)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching instances from db") return fmt.Errorf("error fetching instances from db: %w", err)
} }
runnersByName := map[string]*github.Runner{} runnersByName := map[string]*github.Runner{}
@ -510,7 +510,7 @@ func (r *basePoolManager) reapTimedOutRunners(runners []*github.Runner) error {
pool, err := r.store.GetEntityPool(r.ctx, r.entity, instance.PoolID) pool, err := r.store.GetEntityPool(r.ctx, r.entity, instance.PoolID)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching instance pool info") return fmt.Errorf("error fetching instance pool info: %w", err)
} }
if time.Since(instance.UpdatedAt).Minutes() < float64(pool.RunnerTimeout()) { if time.Since(instance.UpdatedAt).Minutes() < float64(pool.RunnerTimeout()) {
continue continue
@ -529,7 +529,7 @@ func (r *basePoolManager) reapTimedOutRunners(runners []*github.Runner) error {
slog.With(slog.Any("error", err)).ErrorContext( slog.With(slog.Any("error", err)).ErrorContext(
r.ctx, "failed to update runner status", r.ctx, "failed to update runner status",
"runner_name", instance.Name) "runner_name", instance.Name)
return errors.Wrap(err, "updating runner") return fmt.Errorf("error updating runner: %w", err)
} }
} }
} }
@ -560,7 +560,7 @@ func (r *basePoolManager) cleanupOrphanedGithubRunners(runners []*github.Runner)
dbInstance, err := r.store.GetInstanceByName(r.ctx, *runner.Name) dbInstance, err := r.store.GetInstanceByName(r.ctx, *runner.Name)
if err != nil { if err != nil {
if !errors.Is(err, runnerErrors.ErrNotFound) { if !errors.Is(err, runnerErrors.ErrNotFound) {
return errors.Wrap(err, "fetching instance from DB") return fmt.Errorf("error fetching instance from DB: %w", err)
} }
// We no longer have a DB entry for this instance, and the runner appears offline in github. // We no longer have a DB entry for this instance, and the runner appears offline in github.
// Previous forceful removal may have failed? // Previous forceful removal may have failed?
@ -572,7 +572,7 @@ func (r *basePoolManager) cleanupOrphanedGithubRunners(runners []*github.Runner)
if errors.Is(err, runnerErrors.ErrNotFound) { if errors.Is(err, runnerErrors.ErrNotFound) {
continue continue
} }
return errors.Wrap(err, "removing runner") return fmt.Errorf("error removing runner: %w", err)
} }
continue continue
} }
@ -606,7 +606,7 @@ func (r *basePoolManager) cleanupOrphanedGithubRunners(runners []*github.Runner)
pool, err := r.store.GetEntityPool(r.ctx, r.entity, dbInstance.PoolID) pool, err := r.store.GetEntityPool(r.ctx, r.entity, dbInstance.PoolID)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching pool") return fmt.Errorf("error fetching pool: %w", err)
} }
// check if the provider still has the instance. // check if the provider still has the instance.
@ -628,7 +628,7 @@ func (r *basePoolManager) cleanupOrphanedGithubRunners(runners []*github.Runner)
} }
poolInstances, err = provider.ListInstances(r.ctx, pool.ID, listInstancesParams) poolInstances, err = provider.ListInstances(r.ctx, pool.ID, listInstancesParams)
if err != nil { if err != nil {
return errors.Wrapf(err, "fetching instances for pool %s", dbInstance.PoolID) return fmt.Errorf("error fetching instances for pool %s: %w", dbInstance.PoolID, err)
} }
poolInstanceCache[dbInstance.PoolID] = poolInstances poolInstanceCache[dbInstance.PoolID] = poolInstances
} }
@ -662,7 +662,7 @@ func (r *basePoolManager) cleanupOrphanedGithubRunners(runners []*github.Runner)
r.ctx, "runner disappeared from github", r.ctx, "runner disappeared from github",
"runner_name", dbInstance.Name) "runner_name", dbInstance.Name)
} else { } else {
return errors.Wrap(err, "removing runner from github") return fmt.Errorf("error removing runner from github: %w", err)
} }
} }
// Remove the database entry for the runner. // Remove the database entry for the runner.
@ -670,7 +670,7 @@ func (r *basePoolManager) cleanupOrphanedGithubRunners(runners []*github.Runner)
r.ctx, "Removing from database", r.ctx, "Removing from database",
"runner_name", dbInstance.Name) "runner_name", dbInstance.Name)
if err := r.store.DeleteInstance(ctx, dbInstance.PoolID, dbInstance.Name); err != nil { if err := r.store.DeleteInstance(ctx, dbInstance.PoolID, dbInstance.Name); err != nil {
return errors.Wrap(err, "removing runner from database") return fmt.Errorf("error removing runner from database: %w", err)
} }
deleteMux = true deleteMux = true
return nil return nil
@ -696,13 +696,13 @@ func (r *basePoolManager) cleanupOrphanedGithubRunners(runners []*github.Runner)
}, },
} }
if err := provider.Start(r.ctx, dbInstance.ProviderID, startParams); err != nil { if err := provider.Start(r.ctx, dbInstance.ProviderID, startParams); err != nil {
return errors.Wrapf(err, "starting instance %s", dbInstance.ProviderID) return fmt.Errorf("error starting instance %s: %w", dbInstance.ProviderID, err)
} }
return nil return nil
}) })
} }
if err := r.waitForErrorGroupOrContextCancelled(g); err != nil { if err := r.waitForErrorGroupOrContextCancelled(g); err != nil {
return errors.Wrap(err, "removing orphaned github runners") return fmt.Errorf("error removing orphaned github runners: %w", err)
} }
return nil return nil
} }
@ -732,7 +732,7 @@ func (r *basePoolManager) setInstanceRunnerStatus(runnerName string, status para
} }
instance, err := r.store.UpdateInstance(r.ctx, runnerName, updateParams) instance, err := r.store.UpdateInstance(r.ctx, runnerName, updateParams)
if err != nil { if err != nil {
return params.Instance{}, errors.Wrap(err, "updating runner state") return params.Instance{}, fmt.Errorf("error updating runner state: %w", err)
} }
return instance, nil return instance, nil
} }
@ -745,7 +745,7 @@ func (r *basePoolManager) setInstanceStatus(runnerName string, status commonPara
instance, err := r.store.UpdateInstance(r.ctx, runnerName, updateParams) instance, err := r.store.UpdateInstance(r.ctx, runnerName, updateParams)
if err != nil { if err != nil {
return params.Instance{}, errors.Wrap(err, "updating runner state") return params.Instance{}, fmt.Errorf("error updating runner state: %w", err)
} }
return instance, nil return instance, nil
} }
@ -753,7 +753,7 @@ func (r *basePoolManager) setInstanceStatus(runnerName string, status commonPara
func (r *basePoolManager) AddRunner(ctx context.Context, poolID string, aditionalLabels []string) (err error) { func (r *basePoolManager) AddRunner(ctx context.Context, poolID string, aditionalLabels []string) (err error) {
pool, err := r.store.GetEntityPool(r.ctx, r.entity, poolID) pool, err := r.store.GetEntityPool(r.ctx, r.entity, poolID)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching pool") return fmt.Errorf("error fetching pool: %w", err)
} }
provider, ok := r.providers[pool.ProviderName] provider, ok := r.providers[pool.ProviderName]
@ -796,7 +796,7 @@ func (r *basePoolManager) AddRunner(ctx context.Context, poolID string, aditiona
instance, err := r.store.CreateInstance(r.ctx, poolID, createParams) instance, err := r.store.CreateInstance(r.ctx, poolID, createParams)
if err != nil { if err != nil {
return errors.Wrap(err, "creating instance") return fmt.Errorf("error creating instance: %w", err)
} }
defer func() { defer func() {
@ -864,7 +864,7 @@ func (r *basePoolManager) getLabelsForInstance(pool params.Pool) []string {
func (r *basePoolManager) addInstanceToProvider(instance params.Instance) error { func (r *basePoolManager) addInstanceToProvider(instance params.Instance) error {
pool, err := r.store.GetEntityPool(r.ctx, r.entity, instance.PoolID) pool, err := r.store.GetEntityPool(r.ctx, r.entity, instance.PoolID)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching pool") return fmt.Errorf("error fetching pool: %w", err)
} }
provider, ok := r.providers[pool.ProviderName] provider, ok := r.providers[pool.ProviderName]
@ -876,7 +876,7 @@ func (r *basePoolManager) addInstanceToProvider(instance params.Instance) error
jwtToken, err := r.instanceTokenGetter.NewInstanceJWTToken(instance, r.entity, pool.PoolType(), jwtValidity) jwtToken, err := r.instanceTokenGetter.NewInstanceJWTToken(instance, r.entity, pool.PoolType(), jwtValidity)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching instance jwt token") return fmt.Errorf("error fetching instance jwt token: %w", err)
} }
hasJITConfig := len(instance.JitConfiguration) > 0 hasJITConfig := len(instance.JitConfiguration) > 0
@ -933,7 +933,7 @@ func (r *basePoolManager) addInstanceToProvider(instance params.Instance) error
providerInstance, err := provider.CreateInstance(r.ctx, bootstrapArgs, createInstanceParams) providerInstance, err := provider.CreateInstance(r.ctx, bootstrapArgs, createInstanceParams)
if err != nil { if err != nil {
instanceIDToDelete = instance.Name instanceIDToDelete = instance.Name
return errors.Wrap(err, "creating instance") return fmt.Errorf("error creating instance: %w", err)
} }
if providerInstance.Status == commonParams.InstanceError { if providerInstance.Status == commonParams.InstanceError {
@ -945,7 +945,7 @@ func (r *basePoolManager) addInstanceToProvider(instance params.Instance) error
updateInstanceArgs := r.updateArgsFromProviderInstance(providerInstance) updateInstanceArgs := r.updateArgsFromProviderInstance(providerInstance)
if _, err := r.store.UpdateInstance(r.ctx, instance.Name, updateInstanceArgs); err != nil { if _, err := r.store.UpdateInstance(r.ctx, instance.Name, updateInstanceArgs); err != nil {
return errors.Wrap(err, "updating instance") return fmt.Errorf("error updating instance: %w", err)
} }
return nil return nil
} }
@ -966,7 +966,7 @@ func (r *basePoolManager) addInstanceToProvider(instance params.Instance) error
func (r *basePoolManager) paramsWorkflowJobToParamsJob(job params.WorkflowJob) (params.Job, error) { func (r *basePoolManager) paramsWorkflowJobToParamsJob(job params.WorkflowJob) (params.Job, error) {
asUUID, err := uuid.Parse(r.ID()) asUUID, err := uuid.Parse(r.ID())
if err != nil { if err != nil {
return params.Job{}, errors.Wrap(err, "parsing pool ID as UUID") return params.Job{}, fmt.Errorf("error parsing pool ID as UUID: %w", err)
} }
jobParams := params.Job{ jobParams := params.Job{
@ -995,7 +995,7 @@ func (r *basePoolManager) paramsWorkflowJobToParamsJob(job params.WorkflowJob) (
case params.ForgeEntityTypeOrganization: case params.ForgeEntityTypeOrganization:
jobParams.OrgID = &asUUID jobParams.OrgID = &asUUID
default: default:
return jobParams, errors.Errorf("unknown pool type: %s", r.entity.EntityType) return jobParams, fmt.Errorf("unknown pool type: %s", r.entity.EntityType)
} }
return jobParams, nil return jobParams, nil
@ -1101,7 +1101,7 @@ func (r *basePoolManager) scaleDownOnePool(ctx context.Context, pool params.Pool
// instead of returning a bunch of results and filtering manually. // instead of returning a bunch of results and filtering manually.
queued, err := r.store.ListEntityJobsByStatus(r.ctx, r.entity.EntityType, r.entity.ID, params.JobStatusQueued) queued, err := r.store.ListEntityJobsByStatus(r.ctx, r.entity.EntityType, r.entity.ID, params.JobStatusQueued)
if err != nil && !errors.Is(err, runnerErrors.ErrNotFound) { if err != nil && !errors.Is(err, runnerErrors.ErrNotFound) {
return errors.Wrap(err, "listing queued jobs") return fmt.Errorf("error listing queued jobs: %w", err)
} }
for _, job := range queued { for _, job := range queued {
@ -1341,7 +1341,7 @@ func (r *basePoolManager) ensureMinIdleRunners() error {
func (r *basePoolManager) deleteInstanceFromProvider(ctx context.Context, instance params.Instance) error { func (r *basePoolManager) deleteInstanceFromProvider(ctx context.Context, instance params.Instance) error {
pool, err := r.store.GetEntityPool(r.ctx, r.entity, instance.PoolID) pool, err := r.store.GetEntityPool(r.ctx, r.entity, instance.PoolID)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching pool") return fmt.Errorf("error fetching pool: %w", err)
} }
provider, ok := r.providers[instance.ProviderName] provider, ok := r.providers[instance.ProviderName]
@ -1367,7 +1367,7 @@ func (r *basePoolManager) deleteInstanceFromProvider(ctx context.Context, instan
}, },
} }
if err := provider.DeleteInstance(ctx, identifier, deleteInstanceParams); err != nil { if err := provider.DeleteInstance(ctx, identifier, deleteInstanceParams); err != nil {
return errors.Wrap(err, "removing instance") return fmt.Errorf("error removing instance: %w", err)
} }
return nil return nil
@ -1583,7 +1583,7 @@ func (r *basePoolManager) Wait() error {
select { select {
case <-done: case <-done:
case <-timer.C: case <-timer.C:
return errors.Wrap(runnerErrors.ErrTimeout, "waiting for pool to stop") return runnerErrors.NewTimeoutError("waiting for pool to stop")
} }
return nil return nil
} }
@ -1609,11 +1609,11 @@ func (r *basePoolManager) runnerCleanup() (err error) {
func (r *basePoolManager) cleanupOrphanedRunners(runners []*github.Runner) error { func (r *basePoolManager) cleanupOrphanedRunners(runners []*github.Runner) error {
if err := r.cleanupOrphanedProviderRunners(runners); err != nil { if err := r.cleanupOrphanedProviderRunners(runners); err != nil {
return errors.Wrap(err, "cleaning orphaned instances") return fmt.Errorf("error cleaning orphaned instances: %w", err)
} }
if err := r.cleanupOrphanedGithubRunners(runners); err != nil { if err := r.cleanupOrphanedGithubRunners(runners); err != nil {
return errors.Wrap(err, "cleaning orphaned github runners") return fmt.Errorf("error cleaning orphaned github runners: %w", err)
} }
return nil return nil
@ -1693,10 +1693,10 @@ func (r *basePoolManager) DeleteRunner(runner params.Instance, forceRemove, bypa
if bypassGHUnauthorizedError { if bypassGHUnauthorizedError {
slog.Info("bypass github unauthorized error is set, marking runner for deletion") slog.Info("bypass github unauthorized error is set, marking runner for deletion")
} else { } else {
return errors.Wrap(err, "removing runner") return fmt.Errorf("error removing runner: %w", err)
} }
} else { } else {
return errors.Wrap(err, "removing runner") return fmt.Errorf("error removing runner: %w", err)
} }
} }
} }
@ -1714,7 +1714,7 @@ func (r *basePoolManager) DeleteRunner(runner params.Instance, forceRemove, bypa
slog.With(slog.Any("error", err)).ErrorContext( slog.With(slog.Any("error", err)).ErrorContext(
r.ctx, "failed to update runner", r.ctx, "failed to update runner",
"runner_name", runner.Name) "runner_name", runner.Name)
return errors.Wrap(err, "updating runner") return fmt.Errorf("error updating runner: %w", err)
} }
return nil return nil
} }
@ -1745,7 +1745,7 @@ func (r *basePoolManager) DeleteRunner(runner params.Instance, forceRemove, bypa
func (r *basePoolManager) consumeQueuedJobs() error { func (r *basePoolManager) consumeQueuedJobs() error {
queued, err := r.store.ListEntityJobsByStatus(r.ctx, r.entity.EntityType, r.entity.ID, params.JobStatusQueued) queued, err := r.store.ListEntityJobsByStatus(r.ctx, r.entity.EntityType, r.entity.ID, params.JobStatusQueued)
if err != nil { if err != nil {
return errors.Wrap(err, "listing queued jobs") return fmt.Errorf("error listing queued jobs: %w", err)
} }
poolsCache := poolsForTags{ poolsCache := poolsForTags{
@ -1860,7 +1860,7 @@ func (r *basePoolManager) consumeQueuedJobs() error {
slog.With(slog.Any("error", err)).ErrorContext( slog.With(slog.Any("error", err)).ErrorContext(
r.ctx, "failed to unlock job", r.ctx, "failed to unlock job",
"job_id", job.WorkflowJobID) "job_id", job.WorkflowJobID)
return errors.Wrap(err, "unlocking job") return fmt.Errorf("error unlocking job: %w", err)
} }
} }
} }
@ -1874,12 +1874,12 @@ func (r *basePoolManager) consumeQueuedJobs() error {
func (r *basePoolManager) UninstallWebhook(ctx context.Context) error { func (r *basePoolManager) UninstallWebhook(ctx context.Context) error {
if r.controllerInfo.ControllerWebhookURL == "" { if r.controllerInfo.ControllerWebhookURL == "" {
return errors.Wrap(runnerErrors.ErrBadRequest, "controller webhook url is empty") return runnerErrors.NewBadRequestError("controller webhook url is empty")
} }
allHooks, err := r.listHooks(ctx) allHooks, err := r.listHooks(ctx)
if err != nil { if err != nil {
return errors.Wrap(err, "listing hooks") return fmt.Errorf("error listing hooks: %w", err)
} }
var controllerHookID int64 var controllerHookID int64
@ -1917,16 +1917,16 @@ func (r *basePoolManager) UninstallWebhook(ctx context.Context) error {
func (r *basePoolManager) InstallHook(ctx context.Context, req *github.Hook) (params.HookInfo, error) { func (r *basePoolManager) InstallHook(ctx context.Context, req *github.Hook) (params.HookInfo, error) {
allHooks, err := r.listHooks(ctx) allHooks, err := r.listHooks(ctx)
if err != nil { if err != nil {
return params.HookInfo{}, errors.Wrap(err, "listing hooks") return params.HookInfo{}, fmt.Errorf("error listing hooks: %w", err)
} }
if err := validateHookRequest(r.controllerInfo.ControllerID.String(), r.controllerInfo.WebhookURL, allHooks, req); err != nil { if err := validateHookRequest(r.controllerInfo.ControllerID.String(), r.controllerInfo.WebhookURL, allHooks, req); err != nil {
return params.HookInfo{}, errors.Wrap(err, "validating hook request") return params.HookInfo{}, fmt.Errorf("error validating hook request: %w", err)
} }
hook, err := r.ghcli.CreateEntityHook(ctx, req) hook, err := r.ghcli.CreateEntityHook(ctx, req)
if err != nil { if err != nil {
return params.HookInfo{}, errors.Wrap(err, "creating entity hook") return params.HookInfo{}, fmt.Errorf("error creating entity hook: %w", err)
} }
if _, err := r.ghcli.PingEntityHook(ctx, hook.GetID()); err != nil { if _, err := r.ghcli.PingEntityHook(ctx, hook.GetID()); err != nil {
@ -1941,7 +1941,7 @@ func (r *basePoolManager) InstallHook(ctx context.Context, req *github.Hook) (pa
func (r *basePoolManager) InstallWebhook(ctx context.Context, param params.InstallWebhookParams) (params.HookInfo, error) { func (r *basePoolManager) InstallWebhook(ctx context.Context, param params.InstallWebhookParams) (params.HookInfo, error) {
if r.controllerInfo.ControllerWebhookURL == "" { if r.controllerInfo.ControllerWebhookURL == "" {
return params.HookInfo{}, errors.Wrap(runnerErrors.ErrBadRequest, "controller webhook url is empty") return params.HookInfo{}, runnerErrors.NewBadRequestError("controller webhook url is empty")
} }
insecureSSL := "0" insecureSSL := "0"
@ -1989,9 +1989,9 @@ func (r *basePoolManager) GithubRunnerRegistrationToken() (string, error) {
tk, ghResp, err := r.ghcli.CreateEntityRegistrationToken(r.ctx) tk, ghResp, err := r.ghcli.CreateEntityRegistrationToken(r.ctx)
if err != nil { if err != nil {
if ghResp != nil && ghResp.StatusCode == http.StatusUnauthorized { if ghResp != nil && ghResp.StatusCode == http.StatusUnauthorized {
return "", errors.Wrap(runnerErrors.ErrUnauthorized, "fetching token") return "", runnerErrors.NewUnauthorizedError("error fetching token")
} }
return "", errors.Wrap(err, "creating runner token") return "", fmt.Errorf("error creating runner token: %w", err)
} }
return *tk.Token, nil return *tk.Token, nil
} }
@ -2000,9 +2000,9 @@ func (r *basePoolManager) FetchTools() ([]commonParams.RunnerApplicationDownload
tools, ghResp, err := r.ghcli.ListEntityRunnerApplicationDownloads(r.ctx) tools, ghResp, err := r.ghcli.ListEntityRunnerApplicationDownloads(r.ctx)
if err != nil { if err != nil {
if ghResp != nil && ghResp.StatusCode == http.StatusUnauthorized { if ghResp != nil && ghResp.StatusCode == http.StatusUnauthorized {
return nil, errors.Wrap(runnerErrors.ErrUnauthorized, "fetching tools") return nil, runnerErrors.NewUnauthorizedError("error fetching tools")
} }
return nil, errors.Wrap(err, "fetching runner tools") return nil, fmt.Errorf("error fetching runner tools: %w", err)
} }
ret := []commonParams.RunnerApplicationDownload{} ret := []commonParams.RunnerApplicationDownload{}
@ -2027,9 +2027,9 @@ func (r *basePoolManager) GetGithubRunners() ([]*github.Runner, error) {
runners, ghResp, err := r.ghcli.ListEntityRunners(r.ctx, &opts) runners, ghResp, err := r.ghcli.ListEntityRunners(r.ctx, &opts)
if err != nil { if err != nil {
if ghResp != nil && ghResp.StatusCode == http.StatusUnauthorized { if ghResp != nil && ghResp.StatusCode == http.StatusUnauthorized {
return nil, errors.Wrap(runnerErrors.ErrUnauthorized, "fetching runners") return nil, runnerErrors.NewUnauthorizedError("error fetching runners")
} }
return nil, errors.Wrap(err, "fetching runners") return nil, fmt.Errorf("error fetching runners: %w", err)
} }
allRunners = append(allRunners, runners.Runners...) allRunners = append(allRunners, runners.Runners...)
if ghResp.NextPage == 0 { if ghResp.NextPage == 0 {
@ -2044,7 +2044,7 @@ func (r *basePoolManager) GetGithubRunners() ([]*github.Runner, error) {
func (r *basePoolManager) GetWebhookInfo(ctx context.Context) (params.HookInfo, error) { func (r *basePoolManager) GetWebhookInfo(ctx context.Context) (params.HookInfo, error) {
allHooks, err := r.listHooks(ctx) allHooks, err := r.listHooks(ctx)
if err != nil { if err != nil {
return params.HookInfo{}, errors.Wrap(err, "listing hooks") return params.HookInfo{}, fmt.Errorf("error listing hooks: %w", err)
} }
trimmedBase := strings.TrimRight(r.controllerInfo.WebhookURL, "/") trimmedBase := strings.TrimRight(r.controllerInfo.WebhookURL, "/")
trimmedController := strings.TrimRight(r.controllerInfo.ControllerWebhookURL, "/") trimmedController := strings.TrimRight(r.controllerInfo.ControllerWebhookURL, "/")

View file

@ -17,8 +17,6 @@ package pool
import ( import (
"log/slog" "log/slog"
"github.com/pkg/errors"
runnerErrors "github.com/cloudbase/garm-provider-common/errors" runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/database/common" "github.com/cloudbase/garm/database/common"
"github.com/cloudbase/garm/params" "github.com/cloudbase/garm/params"
@ -46,7 +44,7 @@ func (r *basePoolManager) getClientOrStub() runnerCommon.GithubClient {
if err != nil { if err != nil {
slog.WarnContext(r.ctx, "failed to create github client", "error", err) slog.WarnContext(r.ctx, "failed to create github client", "error", err)
ghc = &stubGithubClient{ ghc = &stubGithubClient{
err: errors.Wrapf(runnerErrors.ErrUnauthorized, "failed to create github client; please update credentials: %v", err), err: runnerErrors.NewUnauthorizedError("failed to create github client; please update credentials"),
} }
} }
return ghc return ghc

View file

@ -16,8 +16,8 @@ package runner
import ( import (
"context" "context"
"errors"
"github.com/pkg/errors" "fmt"
runnerErrors "github.com/cloudbase/garm-provider-common/errors" runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/auth" "github.com/cloudbase/garm/auth"
@ -31,7 +31,7 @@ func (r *Runner) ListAllPools(ctx context.Context) ([]params.Pool, error) {
pools, err := r.store.ListAllPools(ctx) pools, err := r.store.ListAllPools(ctx)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching pools") return nil, fmt.Errorf("error fetching pools: %w", err)
} }
return pools, nil return pools, nil
} }
@ -43,7 +43,7 @@ func (r *Runner) GetPoolByID(ctx context.Context, poolID string) (params.Pool, e
pool, err := r.store.GetPoolByID(ctx, poolID) pool, err := r.store.GetPoolByID(ctx, poolID)
if err != nil { if err != nil {
return params.Pool{}, errors.Wrap(err, "fetching pool") return params.Pool{}, fmt.Errorf("error fetching pool: %w", err)
} }
return pool, nil return pool, nil
} }
@ -56,7 +56,7 @@ func (r *Runner) DeletePoolByID(ctx context.Context, poolID string) error {
pool, err := r.store.GetPoolByID(ctx, poolID) pool, err := r.store.GetPoolByID(ctx, poolID)
if err != nil { if err != nil {
if !errors.Is(err, runnerErrors.ErrNotFound) { if !errors.Is(err, runnerErrors.ErrNotFound) {
return errors.Wrap(err, "fetching pool") return fmt.Errorf("error fetching pool: %w", err)
} }
return nil return nil
} }
@ -66,7 +66,7 @@ func (r *Runner) DeletePoolByID(ctx context.Context, poolID string) error {
} }
if err := r.store.DeletePoolByID(ctx, poolID); err != nil { if err := r.store.DeletePoolByID(ctx, poolID); err != nil {
return errors.Wrap(err, "deleting pool") return fmt.Errorf("error deleting pool: %w", err)
} }
return nil return nil
} }
@ -78,7 +78,7 @@ func (r *Runner) UpdatePoolByID(ctx context.Context, poolID string, param params
pool, err := r.store.GetPoolByID(ctx, poolID) pool, err := r.store.GetPoolByID(ctx, poolID)
if err != nil { if err != nil {
return params.Pool{}, errors.Wrap(err, "fetching pool") return params.Pool{}, fmt.Errorf("error fetching pool: %w", err)
} }
maxRunners := pool.MaxRunners maxRunners := pool.MaxRunners
@ -101,12 +101,12 @@ func (r *Runner) UpdatePoolByID(ctx context.Context, poolID string, param params
entity, err := pool.GetEntity() entity, err := pool.GetEntity()
if err != nil { if err != nil {
return params.Pool{}, errors.Wrap(err, "getting entity") return params.Pool{}, fmt.Errorf("error getting entity: %w", err)
} }
newPool, err := r.store.UpdateEntityPool(ctx, entity, poolID, param) newPool, err := r.store.UpdateEntityPool(ctx, entity, poolID, param)
if err != nil { if err != nil {
return params.Pool{}, errors.Wrap(err, "updating pool") return params.Pool{}, fmt.Errorf("error updating pool: %w", err)
} }
return newPool, nil return newPool, nil
} }
@ -118,7 +118,7 @@ func (r *Runner) ListAllJobs(ctx context.Context) ([]params.Job, error) {
jobs, err := r.store.ListAllJobs(ctx) jobs, err := r.store.ListAllJobs(ctx)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching jobs") return nil, fmt.Errorf("error fetching jobs: %w", err)
} }
return jobs, nil return jobs, nil
} }

View file

@ -169,7 +169,7 @@ func (s *PoolTestSuite) TestGetPoolByIDNotFound() {
s.Require().Nil(err) s.Require().Nil(err)
_, err = s.Runner.GetPoolByID(s.Fixtures.AdminContext, s.Fixtures.Pools[0].ID) _, err = s.Runner.GetPoolByID(s.Fixtures.AdminContext, s.Fixtures.Pools[0].ID)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching pool: fetching pool by ID: not found", err.Error()) s.Require().Equal("error fetching pool: error fetching pool by ID: not found", err.Error())
} }
func (s *PoolTestSuite) TestDeletePoolByID() { func (s *PoolTestSuite) TestDeletePoolByID() {
@ -178,7 +178,7 @@ func (s *PoolTestSuite) TestDeletePoolByID() {
s.Require().Nil(err) s.Require().Nil(err)
_, err = s.Fixtures.Store.GetPoolByID(s.Fixtures.AdminContext, s.Fixtures.Pools[0].ID) _, err = s.Fixtures.Store.GetPoolByID(s.Fixtures.AdminContext, s.Fixtures.Pools[0].ID)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching pool by ID: not found", err.Error()) s.Require().Equal("error fetching pool by ID: not found", err.Error())
} }
func (s *PoolTestSuite) TestDeletePoolByIDErrUnauthorized() { func (s *PoolTestSuite) TestDeletePoolByIDErrUnauthorized() {
@ -220,7 +220,7 @@ func (s *PoolTestSuite) TestTestUpdatePoolByIDInvalidPoolID() {
_, err := s.Runner.UpdatePoolByID(s.Fixtures.AdminContext, "dummy-pool-id", s.Fixtures.UpdatePoolParams) _, err := s.Runner.UpdatePoolByID(s.Fixtures.AdminContext, "dummy-pool-id", s.Fixtures.UpdatePoolParams)
s.Require().NotNil(err) s.Require().NotNil(err)
s.Require().Equal("fetching pool: fetching pool by ID: parsing id: invalid request", err.Error()) s.Require().Equal("error fetching pool: error fetching pool by ID: error parsing id: invalid request", err.Error())
} }
func (s *PoolTestSuite) TestTestUpdatePoolByIDRunnerBootstrapTimeoutFailed() { func (s *PoolTestSuite) TestTestUpdatePoolByIDRunnerBootstrapTimeoutFailed() {

View file

@ -16,10 +16,9 @@ package providers
import ( import (
"context" "context"
"fmt"
"log/slog" "log/slog"
"github.com/pkg/errors"
"github.com/cloudbase/garm/config" "github.com/cloudbase/garm/config"
"github.com/cloudbase/garm/params" "github.com/cloudbase/garm/params"
"github.com/cloudbase/garm/runner/common" "github.com/cloudbase/garm/runner/common"
@ -39,11 +38,11 @@ func LoadProvidersFromConfig(ctx context.Context, cfg config.Config, controllerI
conf := providerCfg conf := providerCfg
provider, err := external.NewProvider(ctx, &conf, controllerID) provider, err := external.NewProvider(ctx, &conf, controllerID)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "creating provider") return nil, fmt.Errorf("error creating provider: %w", err)
} }
providers[providerCfg.Name] = provider providers[providerCfg.Name] = provider
default: default:
return nil, errors.Errorf("unknown provider type %s", providerCfg.ProviderType) return nil, fmt.Errorf("unknown provider type %s", providerCfg.ProviderType)
} }
} }
return providers, nil return providers, nil

View file

@ -17,12 +17,11 @@ package v010
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"log/slog" "log/slog"
"os/exec" "os/exec"
"github.com/pkg/errors"
garmErrors "github.com/cloudbase/garm-provider-common/errors" garmErrors "github.com/cloudbase/garm-provider-common/errors"
commonExecution "github.com/cloudbase/garm-provider-common/execution/common" commonExecution "github.com/cloudbase/garm-provider-common/execution/common"
commonParams "github.com/cloudbase/garm-provider-common/params" commonParams "github.com/cloudbase/garm-provider-common/params"
@ -44,7 +43,7 @@ func NewProvider(ctx context.Context, cfg *config.Provider, controllerID string)
execPath, err := cfg.External.ExecutablePath() execPath, err := cfg.External.ExecutablePath()
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching executable path") return nil, fmt.Errorf("error fetching executable path: %w", err)
} }
// Set GARM_INTERFACE_VERSION to the version of the interface that the external // Set GARM_INTERFACE_VERSION to the version of the interface that the external
@ -83,7 +82,7 @@ func (e *external) CreateInstance(ctx context.Context, bootstrapParams commonPar
asJs, err := json.Marshal(bootstrapParams) asJs, err := json.Marshal(bootstrapParams)
if err != nil { if err != nil {
return commonParams.ProviderInstance{}, errors.Wrap(err, "serializing bootstrap params") return commonParams.ProviderInstance{}, fmt.Errorf("error serializing bootstrap params: %w", err)
} }
metrics.InstanceOperationCount.WithLabelValues( metrics.InstanceOperationCount.WithLabelValues(

View file

@ -18,12 +18,11 @@ import (
"context" "context"
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"log/slog" "log/slog"
"os/exec" "os/exec"
"github.com/pkg/errors"
garmErrors "github.com/cloudbase/garm-provider-common/errors" garmErrors "github.com/cloudbase/garm-provider-common/errors"
commonExecution "github.com/cloudbase/garm-provider-common/execution/common" commonExecution "github.com/cloudbase/garm-provider-common/execution/common"
commonParams "github.com/cloudbase/garm-provider-common/params" commonParams "github.com/cloudbase/garm-provider-common/params"
@ -44,7 +43,7 @@ func NewProvider(ctx context.Context, cfg *config.Provider, controllerID string)
execPath, err := cfg.External.ExecutablePath() execPath, err := cfg.External.ExecutablePath()
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching executable path") return nil, fmt.Errorf("error fetching executable path: %w", err)
} }
// Set GARM_INTERFACE_VERSION to the version of the interface that the external // Set GARM_INTERFACE_VERSION to the version of the interface that the external
@ -75,7 +74,7 @@ func (e *external) CreateInstance(ctx context.Context, bootstrapParams commonPar
extraspecs := bootstrapParams.ExtraSpecs extraspecs := bootstrapParams.ExtraSpecs
extraspecsValue, err := json.Marshal(extraspecs) extraspecsValue, err := json.Marshal(extraspecs)
if err != nil { if err != nil {
return commonParams.ProviderInstance{}, errors.Wrap(err, "serializing extraspecs") return commonParams.ProviderInstance{}, fmt.Errorf("error serializing extraspecs: %w", err)
} }
// Encode the extraspecs as base64 to avoid issues with special characters. // Encode the extraspecs as base64 to avoid issues with special characters.
base64EncodedExtraSpecs := base64.StdEncoding.EncodeToString(extraspecsValue) base64EncodedExtraSpecs := base64.StdEncoding.EncodeToString(extraspecsValue)
@ -90,7 +89,7 @@ func (e *external) CreateInstance(ctx context.Context, bootstrapParams commonPar
asJs, err := json.Marshal(bootstrapParams) asJs, err := json.Marshal(bootstrapParams)
if err != nil { if err != nil {
return commonParams.ProviderInstance{}, errors.Wrap(err, "serializing bootstrap params") return commonParams.ProviderInstance{}, fmt.Errorf("error serializing bootstrap params: %w", err)
} }
metrics.InstanceOperationCount.WithLabelValues( metrics.InstanceOperationCount.WithLabelValues(
@ -136,7 +135,7 @@ func (e *external) DeleteInstance(ctx context.Context, instance string, deleteIn
extraspecs := deleteInstanceParams.DeleteInstanceV011.PoolInfo.ExtraSpecs extraspecs := deleteInstanceParams.DeleteInstanceV011.PoolInfo.ExtraSpecs
extraspecsValue, err := json.Marshal(extraspecs) extraspecsValue, err := json.Marshal(extraspecs)
if err != nil { if err != nil {
return errors.Wrap(err, "serializing extraspecs") return fmt.Errorf("error serializing extraspecs: %w", err)
} }
// Encode the extraspecs as base64 to avoid issues with special characters. // Encode the extraspecs as base64 to avoid issues with special characters.
base64EncodedExtraSpecs := base64.StdEncoding.EncodeToString(extraspecsValue) base64EncodedExtraSpecs := base64.StdEncoding.EncodeToString(extraspecsValue)
@ -173,7 +172,7 @@ func (e *external) GetInstance(ctx context.Context, instance string, getInstance
extraspecs := getInstanceParams.GetInstanceV011.PoolInfo.ExtraSpecs extraspecs := getInstanceParams.GetInstanceV011.PoolInfo.ExtraSpecs
extraspecsValue, err := json.Marshal(extraspecs) extraspecsValue, err := json.Marshal(extraspecs)
if err != nil { if err != nil {
return commonParams.ProviderInstance{}, errors.Wrap(err, "serializing extraspecs") return commonParams.ProviderInstance{}, fmt.Errorf("error serializing extraspecs: %w", err)
} }
// Encode the extraspecs as base64 to avoid issues with special characters. // Encode the extraspecs as base64 to avoid issues with special characters.
base64EncodedExtraSpecs := base64.StdEncoding.EncodeToString(extraspecsValue) base64EncodedExtraSpecs := base64.StdEncoding.EncodeToString(extraspecsValue)
@ -228,7 +227,7 @@ func (e *external) ListInstances(ctx context.Context, poolID string, listInstanc
extraspecs := listInstancesParams.ListInstancesV011.PoolInfo.ExtraSpecs extraspecs := listInstancesParams.ListInstancesV011.PoolInfo.ExtraSpecs
extraspecsValue, err := json.Marshal(extraspecs) extraspecsValue, err := json.Marshal(extraspecs)
if err != nil { if err != nil {
return []commonParams.ProviderInstance{}, errors.Wrap(err, "serializing extraspecs") return []commonParams.ProviderInstance{}, fmt.Errorf("error serializing extraspecs: %w", err)
} }
// Encode the extraspecs as base64 to avoid issues with special characters. // Encode the extraspecs as base64 to avoid issues with special characters.
base64EncodedExtraSpecs := base64.StdEncoding.EncodeToString(extraspecsValue) base64EncodedExtraSpecs := base64.StdEncoding.EncodeToString(extraspecsValue)
@ -283,7 +282,7 @@ func (e *external) RemoveAllInstances(ctx context.Context, removeAllInstances co
extraspecs := removeAllInstances.RemoveAllInstancesV011.PoolInfo.ExtraSpecs extraspecs := removeAllInstances.RemoveAllInstancesV011.PoolInfo.ExtraSpecs
extraspecsValue, err := json.Marshal(extraspecs) extraspecsValue, err := json.Marshal(extraspecs)
if err != nil { if err != nil {
return errors.Wrap(err, "serializing extraspecs") return fmt.Errorf("error serializing extraspecs: %w", err)
} }
// Encode the extraspecs as base64 to avoid issues with special characters. // Encode the extraspecs as base64 to avoid issues with special characters.
base64EncodedExtraSpecs := base64.StdEncoding.EncodeToString(extraspecsValue) base64EncodedExtraSpecs := base64.StdEncoding.EncodeToString(extraspecsValue)
@ -317,7 +316,7 @@ func (e *external) Stop(ctx context.Context, instance string, stopParams common.
extraspecs := stopParams.StopV011.PoolInfo.ExtraSpecs extraspecs := stopParams.StopV011.PoolInfo.ExtraSpecs
extraspecsValue, err := json.Marshal(extraspecs) extraspecsValue, err := json.Marshal(extraspecs)
if err != nil { if err != nil {
return errors.Wrap(err, "serializing extraspecs") return fmt.Errorf("error serializing extraspecs: %w", err)
} }
// Encode the extraspecs as base64 to avoid issues with special characters. // Encode the extraspecs as base64 to avoid issues with special characters.
base64EncodedExtraSpecs := base64.StdEncoding.EncodeToString(extraspecsValue) base64EncodedExtraSpecs := base64.StdEncoding.EncodeToString(extraspecsValue)
@ -351,7 +350,7 @@ func (e *external) Start(ctx context.Context, instance string, startParams commo
extraspecs := startParams.StartV011.PoolInfo.ExtraSpecs extraspecs := startParams.StartV011.PoolInfo.ExtraSpecs
extraspecsValue, err := json.Marshal(extraspecs) extraspecsValue, err := json.Marshal(extraspecs)
if err != nil { if err != nil {
return errors.Wrap(err, "serializing extraspecs") return fmt.Errorf("error serializing extraspecs: %w", err)
} }
// Encode the extraspecs as base64 to avoid issues with special characters. // Encode the extraspecs as base64 to avoid issues with special characters.
base64EncodedExtraSpecs := base64.StdEncoding.EncodeToString(extraspecsValue) base64EncodedExtraSpecs := base64.StdEncoding.EncodeToString(extraspecsValue)

View file

@ -16,12 +16,11 @@ package runner
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"log/slog" "log/slog"
"strings" "strings"
"github.com/pkg/errors"
runnerErrors "github.com/cloudbase/garm-provider-common/errors" runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/auth" "github.com/cloudbase/garm/auth"
"github.com/cloudbase/garm/params" "github.com/cloudbase/garm/params"
@ -35,7 +34,7 @@ func (r *Runner) CreateRepository(ctx context.Context, param params.CreateRepoPa
} }
if err := param.Validate(); err != nil { if err := param.Validate(); err != nil {
return params.Repository{}, errors.Wrap(err, "validating params") return params.Repository{}, fmt.Errorf("error validating params: %w", err)
} }
var creds params.ForgeCredentials var creds params.ForgeCredentials
@ -55,7 +54,7 @@ func (r *Runner) CreateRepository(ctx context.Context, param params.CreateRepoPa
_, err = r.store.GetRepository(ctx, param.Owner, param.Name, creds.Endpoint.Name) _, err = r.store.GetRepository(ctx, param.Owner, param.Name, creds.Endpoint.Name)
if err != nil { if err != nil {
if !errors.Is(err, runnerErrors.ErrNotFound) { if !errors.Is(err, runnerErrors.ErrNotFound) {
return params.Repository{}, errors.Wrap(err, "fetching repo") return params.Repository{}, fmt.Errorf("error fetching repo: %w", err)
} }
} else { } else {
return params.Repository{}, runnerErrors.NewConflictError("repository %s/%s already exists", param.Owner, param.Name) return params.Repository{}, runnerErrors.NewConflictError("repository %s/%s already exists", param.Owner, param.Name)
@ -63,7 +62,7 @@ func (r *Runner) CreateRepository(ctx context.Context, param params.CreateRepoPa
repo, err = r.store.CreateRepository(ctx, param.Owner, param.Name, creds, param.WebhookSecret, param.PoolBalancerType) repo, err = r.store.CreateRepository(ctx, param.Owner, param.Name, creds, param.WebhookSecret, param.PoolBalancerType)
if err != nil { if err != nil {
return params.Repository{}, errors.Wrap(err, "creating repository") return params.Repository{}, fmt.Errorf("error creating repository: %w", err)
} }
defer func() { defer func() {
@ -80,7 +79,7 @@ func (r *Runner) CreateRepository(ctx context.Context, param params.CreateRepoPa
// updating the store. // updating the store.
poolMgr, err := r.poolManagerCtrl.CreateRepoPoolManager(r.ctx, repo, r.providers, r.store) poolMgr, err := r.poolManagerCtrl.CreateRepoPoolManager(r.ctx, repo, r.providers, r.store)
if err != nil { if err != nil {
return params.Repository{}, errors.Wrap(err, "creating repo pool manager") return params.Repository{}, fmt.Errorf("error creating repo pool manager: %w", err)
} }
if err := poolMgr.Start(); err != nil { if err := poolMgr.Start(); err != nil {
if deleteErr := r.poolManagerCtrl.DeleteRepoPoolManager(repo); deleteErr != nil { if deleteErr := r.poolManagerCtrl.DeleteRepoPoolManager(repo); deleteErr != nil {
@ -88,7 +87,7 @@ func (r *Runner) CreateRepository(ctx context.Context, param params.CreateRepoPa
ctx, "failed to cleanup pool manager for repo", ctx, "failed to cleanup pool manager for repo",
"repository_id", repo.ID) "repository_id", repo.ID)
} }
return params.Repository{}, errors.Wrap(err, "starting repo pool manager") return params.Repository{}, fmt.Errorf("error starting repo pool manager: %w", err)
} }
return repo, nil return repo, nil
} }
@ -100,7 +99,7 @@ func (r *Runner) ListRepositories(ctx context.Context, filter params.RepositoryF
repos, err := r.store.ListRepositories(ctx, filter) repos, err := r.store.ListRepositories(ctx, filter)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "listing repositories") return nil, fmt.Errorf("error listing repositories: %w", err)
} }
var allRepos []params.Repository var allRepos []params.Repository
@ -126,7 +125,7 @@ func (r *Runner) GetRepositoryByID(ctx context.Context, repoID string) (params.R
repo, err := r.store.GetRepositoryByID(ctx, repoID) repo, err := r.store.GetRepositoryByID(ctx, repoID)
if err != nil { if err != nil {
return params.Repository{}, errors.Wrap(err, "fetching repository") return params.Repository{}, fmt.Errorf("error fetching repository: %w", err)
} }
poolMgr, err := r.poolManagerCtrl.GetRepoPoolManager(repo) poolMgr, err := r.poolManagerCtrl.GetRepoPoolManager(repo)
@ -145,17 +144,17 @@ func (r *Runner) DeleteRepository(ctx context.Context, repoID string, keepWebhoo
repo, err := r.store.GetRepositoryByID(ctx, repoID) repo, err := r.store.GetRepositoryByID(ctx, repoID)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching repo") return fmt.Errorf("error fetching repo: %w", err)
} }
entity, err := repo.GetEntity() entity, err := repo.GetEntity()
if err != nil { if err != nil {
return errors.Wrap(err, "getting entity") return fmt.Errorf("error getting entity: %w", err)
} }
pools, err := r.store.ListEntityPools(ctx, entity) pools, err := r.store.ListEntityPools(ctx, entity)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching repo pools") return fmt.Errorf("error fetching repo pools: %w", err)
} }
if len(pools) > 0 { if len(pools) > 0 {
@ -169,7 +168,7 @@ func (r *Runner) DeleteRepository(ctx context.Context, repoID string, keepWebhoo
scaleSets, err := r.store.ListEntityScaleSets(ctx, entity) scaleSets, err := r.store.ListEntityScaleSets(ctx, entity)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching repo scale sets") return fmt.Errorf("error fetching repo scale sets: %w", err)
} }
if len(scaleSets) > 0 { if len(scaleSets) > 0 {
@ -179,7 +178,7 @@ func (r *Runner) DeleteRepository(ctx context.Context, repoID string, keepWebhoo
if !keepWebhook && r.config.Default.EnableWebhookManagement { if !keepWebhook && r.config.Default.EnableWebhookManagement {
poolMgr, err := r.poolManagerCtrl.GetRepoPoolManager(repo) poolMgr, err := r.poolManagerCtrl.GetRepoPoolManager(repo)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching pool manager") return fmt.Errorf("error fetching pool manager: %w", err)
} }
if err := poolMgr.UninstallWebhook(ctx); err != nil { if err := poolMgr.UninstallWebhook(ctx); err != nil {
@ -192,11 +191,11 @@ func (r *Runner) DeleteRepository(ctx context.Context, repoID string, keepWebhoo
} }
if err := r.poolManagerCtrl.DeleteRepoPoolManager(repo); err != nil { if err := r.poolManagerCtrl.DeleteRepoPoolManager(repo); err != nil {
return errors.Wrap(err, "deleting repo pool manager") return fmt.Errorf("error deleting repo pool manager: %w", err)
} }
if err := r.store.DeleteRepository(ctx, repoID); err != nil { if err := r.store.DeleteRepository(ctx, repoID); err != nil {
return errors.Wrap(err, "removing repository") return fmt.Errorf("error removing repository: %w", err)
} }
return nil return nil
} }
@ -218,12 +217,12 @@ func (r *Runner) UpdateRepository(ctx context.Context, repoID string, param para
slog.InfoContext(ctx, "updating repository", "repo_id", repoID, "param", param) slog.InfoContext(ctx, "updating repository", "repo_id", repoID, "param", param)
repo, err := r.store.UpdateRepository(ctx, repoID, param) repo, err := r.store.UpdateRepository(ctx, repoID, param)
if err != nil { if err != nil {
return params.Repository{}, errors.Wrap(err, "updating repo") return params.Repository{}, fmt.Errorf("error updating repo: %w", err)
} }
poolMgr, err := r.poolManagerCtrl.GetRepoPoolManager(repo) poolMgr, err := r.poolManagerCtrl.GetRepoPoolManager(repo)
if err != nil { if err != nil {
return params.Repository{}, errors.Wrap(err, "getting pool manager") return params.Repository{}, fmt.Errorf("error getting pool manager: %w", err)
} }
repo.PoolManagerStatus = poolMgr.Status() repo.PoolManagerStatus = poolMgr.Status()
@ -237,7 +236,7 @@ func (r *Runner) CreateRepoPool(ctx context.Context, repoID string, param params
createPoolParams, err := r.appendTagsToCreatePoolParams(param) createPoolParams, err := r.appendTagsToCreatePoolParams(param)
if err != nil { if err != nil {
return params.Pool{}, errors.Wrap(err, "appending tags to create pool params") return params.Pool{}, fmt.Errorf("error appending tags to create pool params: %w", err)
} }
if createPoolParams.RunnerBootstrapTimeout == 0 { if createPoolParams.RunnerBootstrapTimeout == 0 {
@ -251,7 +250,7 @@ func (r *Runner) CreateRepoPool(ctx context.Context, repoID string, param params
pool, err := r.store.CreateEntityPool(ctx, entity, createPoolParams) pool, err := r.store.CreateEntityPool(ctx, entity, createPoolParams)
if err != nil { if err != nil {
return params.Pool{}, errors.Wrap(err, "creating pool") return params.Pool{}, fmt.Errorf("error creating pool: %w", err)
} }
return pool, nil return pool, nil
@ -269,7 +268,7 @@ func (r *Runner) GetRepoPoolByID(ctx context.Context, repoID, poolID string) (pa
pool, err := r.store.GetEntityPool(ctx, entity, poolID) pool, err := r.store.GetEntityPool(ctx, entity, poolID)
if err != nil { if err != nil {
return params.Pool{}, errors.Wrap(err, "fetching pool") return params.Pool{}, fmt.Errorf("error fetching pool: %w", err)
} }
return pool, nil return pool, nil
@ -286,7 +285,7 @@ func (r *Runner) DeleteRepoPool(ctx context.Context, repoID, poolID string) erro
} }
pool, err := r.store.GetEntityPool(ctx, entity, poolID) pool, err := r.store.GetEntityPool(ctx, entity, poolID)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching pool") return fmt.Errorf("error fetching pool: %w", err)
} }
// nolint:golangci-lint,godox // nolint:golangci-lint,godox
@ -300,7 +299,7 @@ func (r *Runner) DeleteRepoPool(ctx context.Context, repoID, poolID string) erro
} }
if err := r.store.DeleteEntityPool(ctx, entity, poolID); err != nil { if err := r.store.DeleteEntityPool(ctx, entity, poolID); err != nil {
return errors.Wrap(err, "deleting pool") return fmt.Errorf("error deleting pool: %w", err)
} }
return nil return nil
} }
@ -315,7 +314,7 @@ func (r *Runner) ListRepoPools(ctx context.Context, repoID string) ([]params.Poo
} }
pools, err := r.store.ListEntityPools(ctx, entity) pools, err := r.store.ListEntityPools(ctx, entity)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching pools") return nil, fmt.Errorf("error fetching pools: %w", err)
} }
return pools, nil return pools, nil
} }
@ -327,7 +326,7 @@ func (r *Runner) ListPoolInstances(ctx context.Context, poolID string) ([]params
instances, err := r.store.ListPoolInstances(ctx, poolID) instances, err := r.store.ListPoolInstances(ctx, poolID)
if err != nil { if err != nil {
return []params.Instance{}, errors.Wrap(err, "fetching instances") return []params.Instance{}, fmt.Errorf("error fetching instances: %w", err)
} }
return instances, nil return instances, nil
} }
@ -343,7 +342,7 @@ func (r *Runner) UpdateRepoPool(ctx context.Context, repoID, poolID string, para
} }
pool, err := r.store.GetEntityPool(ctx, entity, poolID) pool, err := r.store.GetEntityPool(ctx, entity, poolID)
if err != nil { if err != nil {
return params.Pool{}, errors.Wrap(err, "fetching pool") return params.Pool{}, fmt.Errorf("error fetching pool: %w", err)
} }
maxRunners := pool.MaxRunners maxRunners := pool.MaxRunners
@ -362,7 +361,7 @@ func (r *Runner) UpdateRepoPool(ctx context.Context, repoID, poolID string, para
newPool, err := r.store.UpdateEntityPool(ctx, entity, poolID, param) newPool, err := r.store.UpdateEntityPool(ctx, entity, poolID, param)
if err != nil { if err != nil {
return params.Pool{}, errors.Wrap(err, "updating pool") return params.Pool{}, fmt.Errorf("error updating pool: %w", err)
} }
return newPool, nil return newPool, nil
} }
@ -377,7 +376,7 @@ func (r *Runner) ListRepoInstances(ctx context.Context, repoID string) ([]params
} }
instances, err := r.store.ListEntityInstances(ctx, entity) instances, err := r.store.ListEntityInstances(ctx, entity)
if err != nil { if err != nil {
return []params.Instance{}, errors.Wrap(err, "fetching instances") return []params.Instance{}, fmt.Errorf("error , errfetching instances: %w", err)
} }
return instances, nil return instances, nil
} }
@ -388,12 +387,12 @@ func (r *Runner) findRepoPoolManager(owner, name, endpointName string) (common.P
repo, err := r.store.GetRepository(r.ctx, owner, name, endpointName) repo, err := r.store.GetRepository(r.ctx, owner, name, endpointName)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching repo") return nil, fmt.Errorf("error fetching repo: %w", err)
} }
poolManager, err := r.poolManagerCtrl.GetRepoPoolManager(repo) poolManager, err := r.poolManagerCtrl.GetRepoPoolManager(repo)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching pool manager for repo") return nil, fmt.Errorf("error fetching pool manager for repo: %w", err)
} }
return poolManager, nil return poolManager, nil
} }
@ -405,17 +404,17 @@ func (r *Runner) InstallRepoWebhook(ctx context.Context, repoID string, param pa
repo, err := r.store.GetRepositoryByID(ctx, repoID) repo, err := r.store.GetRepositoryByID(ctx, repoID)
if err != nil { if err != nil {
return params.HookInfo{}, errors.Wrap(err, "fetching repo") return params.HookInfo{}, fmt.Errorf("error fetching repo: %w", err)
} }
poolManager, err := r.poolManagerCtrl.GetRepoPoolManager(repo) poolManager, err := r.poolManagerCtrl.GetRepoPoolManager(repo)
if err != nil { if err != nil {
return params.HookInfo{}, errors.Wrap(err, "fetching pool manager for repo") return params.HookInfo{}, fmt.Errorf("error fetching pool manager for repo: %w", err)
} }
info, err := poolManager.InstallWebhook(ctx, param) info, err := poolManager.InstallWebhook(ctx, param)
if err != nil { if err != nil {
return params.HookInfo{}, errors.Wrap(err, "installing webhook") return params.HookInfo{}, fmt.Errorf("error installing webhook: %w", err)
} }
return info, nil return info, nil
} }
@ -427,16 +426,16 @@ func (r *Runner) UninstallRepoWebhook(ctx context.Context, repoID string) error
repo, err := r.store.GetRepositoryByID(ctx, repoID) repo, err := r.store.GetRepositoryByID(ctx, repoID)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching repo") return fmt.Errorf("error fetching repo: %w", err)
} }
poolManager, err := r.poolManagerCtrl.GetRepoPoolManager(repo) poolManager, err := r.poolManagerCtrl.GetRepoPoolManager(repo)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching pool manager for repo") return fmt.Errorf("error fetching pool manager for repo: %w", err)
} }
if err := poolManager.UninstallWebhook(ctx); err != nil { if err := poolManager.UninstallWebhook(ctx); err != nil {
return errors.Wrap(err, "uninstalling webhook") return fmt.Errorf("error uninstalling webhook: %w", err)
} }
return nil return nil
} }
@ -448,17 +447,17 @@ func (r *Runner) GetRepoWebhookInfo(ctx context.Context, repoID string) (params.
repo, err := r.store.GetRepositoryByID(ctx, repoID) repo, err := r.store.GetRepositoryByID(ctx, repoID)
if err != nil { if err != nil {
return params.HookInfo{}, errors.Wrap(err, "fetching repo") return params.HookInfo{}, fmt.Errorf("error fetching repo: %w", err)
} }
poolManager, err := r.poolManagerCtrl.GetRepoPoolManager(repo) poolManager, err := r.poolManagerCtrl.GetRepoPoolManager(repo)
if err != nil { if err != nil {
return params.HookInfo{}, errors.Wrap(err, "fetching pool manager for repo") return params.HookInfo{}, fmt.Errorf("error fetching pool manager for repo: %w", err)
} }
info, err := poolManager.GetWebhookInfo(ctx) info, err := poolManager.GetWebhookInfo(ctx)
if err != nil { if err != nil {
return params.HookInfo{}, errors.Wrap(err, "getting webhook info") return params.HookInfo{}, fmt.Errorf("error getting webhook info: %w", err)
} }
return info, nil return info, nil
} }

View file

@ -16,10 +16,10 @@ package runner
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"testing" "testing"
"github.com/pkg/errors"
"github.com/stretchr/testify/mock" "github.com/stretchr/testify/mock"
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
@ -240,7 +240,7 @@ func (s *RepoTestSuite) TestCreateRepositoryPoolMgrFailed() {
s.Fixtures.PoolMgrMock.AssertExpectations(s.T()) s.Fixtures.PoolMgrMock.AssertExpectations(s.T())
s.Fixtures.PoolMgrCtrlMock.AssertExpectations(s.T()) s.Fixtures.PoolMgrCtrlMock.AssertExpectations(s.T())
s.Require().Equal(fmt.Sprintf("creating repo pool manager: %s", s.Fixtures.ErrMock.Error()), err.Error()) s.Require().Equal(fmt.Sprintf("error creating repo pool manager: %s", s.Fixtures.ErrMock.Error()), err.Error())
} }
func (s *RepoTestSuite) TestCreateRepositoryStartPoolMgrFailed() { func (s *RepoTestSuite) TestCreateRepositoryStartPoolMgrFailed() {
@ -252,7 +252,7 @@ func (s *RepoTestSuite) TestCreateRepositoryStartPoolMgrFailed() {
s.Fixtures.PoolMgrMock.AssertExpectations(s.T()) s.Fixtures.PoolMgrMock.AssertExpectations(s.T())
s.Fixtures.PoolMgrCtrlMock.AssertExpectations(s.T()) s.Fixtures.PoolMgrCtrlMock.AssertExpectations(s.T())
s.Require().Equal(fmt.Sprintf("starting repo pool manager: %s", s.Fixtures.ErrMock.Error()), err.Error()) s.Require().Equal(fmt.Sprintf("error starting repo pool manager: %s", s.Fixtures.ErrMock.Error()), err.Error())
} }
func (s *RepoTestSuite) TestListRepositories() { func (s *RepoTestSuite) TestListRepositories() {
@ -361,7 +361,7 @@ func (s *RepoTestSuite) TestDeleteRepository() {
s.Require().Nil(err) s.Require().Nil(err)
_, err = s.Fixtures.Store.GetRepositoryByID(s.Fixtures.AdminContext, s.Fixtures.StoreRepos["test-repo-1"].ID) _, err = s.Fixtures.Store.GetRepositoryByID(s.Fixtures.AdminContext, s.Fixtures.StoreRepos["test-repo-1"].ID)
s.Require().Equal("fetching repo: not found", err.Error()) s.Require().Equal("error fetching repo: not found", err.Error())
} }
func (s *RepoTestSuite) TestDeleteRepositoryErrUnauthorized() { func (s *RepoTestSuite) TestDeleteRepositoryErrUnauthorized() {
@ -391,7 +391,7 @@ func (s *RepoTestSuite) TestDeleteRepositoryPoolMgrFailed() {
err := s.Runner.DeleteRepository(s.Fixtures.AdminContext, s.Fixtures.StoreRepos["test-repo-1"].ID, true) err := s.Runner.DeleteRepository(s.Fixtures.AdminContext, s.Fixtures.StoreRepos["test-repo-1"].ID, true)
s.Fixtures.PoolMgrCtrlMock.AssertExpectations(s.T()) s.Fixtures.PoolMgrCtrlMock.AssertExpectations(s.T())
s.Require().Equal(fmt.Sprintf("deleting repo pool manager: %s", s.Fixtures.ErrMock.Error()), err.Error()) s.Require().Equal(fmt.Sprintf("error deleting repo pool manager: %s", s.Fixtures.ErrMock.Error()), err.Error())
} }
func (s *RepoTestSuite) TestUpdateRepository() { func (s *RepoTestSuite) TestUpdateRepository() {
@ -445,7 +445,7 @@ func (s *RepoTestSuite) TestUpdateRepositoryPoolMgrFailed() {
_, err := s.Runner.UpdateRepository(s.Fixtures.AdminContext, s.Fixtures.StoreRepos["test-repo-1"].ID, s.Fixtures.UpdateRepoParams) _, err := s.Runner.UpdateRepository(s.Fixtures.AdminContext, s.Fixtures.StoreRepos["test-repo-1"].ID, s.Fixtures.UpdateRepoParams)
s.Fixtures.PoolMgrCtrlMock.AssertExpectations(s.T()) s.Fixtures.PoolMgrCtrlMock.AssertExpectations(s.T())
s.Require().Equal(fmt.Sprintf("getting pool manager: %s", s.Fixtures.ErrMock.Error()), err.Error()) s.Require().Equal(fmt.Sprintf("error getting pool manager: %s", s.Fixtures.ErrMock.Error()), err.Error())
} }
func (s *RepoTestSuite) TestUpdateRepositoryCreateRepoPoolMgrFailed() { func (s *RepoTestSuite) TestUpdateRepositoryCreateRepoPoolMgrFailed() {
@ -454,7 +454,7 @@ func (s *RepoTestSuite) TestUpdateRepositoryCreateRepoPoolMgrFailed() {
_, err := s.Runner.UpdateRepository(s.Fixtures.AdminContext, s.Fixtures.StoreRepos["test-repo-1"].ID, s.Fixtures.UpdateRepoParams) _, err := s.Runner.UpdateRepository(s.Fixtures.AdminContext, s.Fixtures.StoreRepos["test-repo-1"].ID, s.Fixtures.UpdateRepoParams)
s.Fixtures.PoolMgrCtrlMock.AssertExpectations(s.T()) s.Fixtures.PoolMgrCtrlMock.AssertExpectations(s.T())
s.Require().Equal(fmt.Sprintf("getting pool manager: %s", s.Fixtures.ErrMock.Error()), err.Error()) s.Require().Equal(fmt.Sprintf("error getting pool manager: %s", s.Fixtures.ErrMock.Error()), err.Error())
} }
func (s *RepoTestSuite) TestCreateRepoPool() { func (s *RepoTestSuite) TestCreateRepoPool() {
@ -527,7 +527,7 @@ func (s *RepoTestSuite) TestDeleteRepoPool() {
s.Require().Nil(err) s.Require().Nil(err)
_, err = s.Fixtures.Store.GetEntityPool(s.Fixtures.AdminContext, entity, pool.ID) _, err = s.Fixtures.Store.GetEntityPool(s.Fixtures.AdminContext, entity, pool.ID)
s.Require().Equal("fetching pool: finding pool: not found", err.Error()) s.Require().Equal("fetching pool: error finding pool: not found", err.Error())
} }
func (s *RepoTestSuite) TestDeleteRepoPoolErrUnauthorized() { func (s *RepoTestSuite) TestDeleteRepoPoolErrUnauthorized() {

View file

@ -21,6 +21,7 @@ import (
"crypto/sha256" "crypto/sha256"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"hash" "hash"
"log/slog" "log/slog"
@ -30,9 +31,6 @@ import (
"sync" "sync"
"time" "time"
"github.com/juju/clock"
"github.com/juju/retry"
"github.com/pkg/errors"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
runnerErrors "github.com/cloudbase/garm-provider-common/errors" runnerErrors "github.com/cloudbase/garm-provider-common/errors"
@ -52,12 +50,12 @@ import (
func NewRunner(ctx context.Context, cfg config.Config, db dbCommon.Store) (*Runner, error) { func NewRunner(ctx context.Context, cfg config.Config, db dbCommon.Store) (*Runner, error) {
ctrlID, err := db.ControllerInfo() ctrlID, err := db.ControllerInfo()
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching controller info") return nil, fmt.Errorf("error fetching controller info: %w", err)
} }
providers, err := providers.LoadProvidersFromConfig(ctx, cfg, ctrlID.ControllerID.String()) providers, err := providers.LoadProvidersFromConfig(ctx, cfg, ctrlID.ControllerID.String())
if err != nil { if err != nil {
return nil, errors.Wrap(err, "loading providers") return nil, fmt.Errorf("error loading providers: %w", err)
} }
creds := map[string]config.Github{} creds := map[string]config.Github{}
@ -82,7 +80,7 @@ func NewRunner(ctx context.Context, cfg config.Config, db dbCommon.Store) (*Runn
} }
if err := runner.loadReposOrgsAndEnterprises(); err != nil { if err := runner.loadReposOrgsAndEnterprises(); err != nil {
return nil, errors.Wrap(err, "loading pool managers") return nil, fmt.Errorf("error loading pool managers: %w", err)
} }
return runner, nil return runner, nil
@ -105,16 +103,16 @@ func (p *poolManagerCtrl) CreateRepoPoolManager(ctx context.Context, repo params
entity, err := repo.GetEntity() entity, err := repo.GetEntity()
if err != nil { if err != nil {
return nil, errors.Wrap(err, "getting entity") return nil, fmt.Errorf("error getting entity: %w", err)
} }
instanceTokenGetter, err := auth.NewInstanceTokenGetter(p.config.JWTAuth.Secret) instanceTokenGetter, err := auth.NewInstanceTokenGetter(p.config.JWTAuth.Secret)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "creating instance token getter") return nil, fmt.Errorf("error creating instance token getter: %w", err)
} }
poolManager, err := pool.NewEntityPoolManager(ctx, entity, instanceTokenGetter, providers, store) poolManager, err := pool.NewEntityPoolManager(ctx, entity, instanceTokenGetter, providers, store)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "creating repo pool manager") return nil, fmt.Errorf("error creating repo pool manager: %w", err)
} }
p.repositories[repo.ID] = poolManager p.repositories[repo.ID] = poolManager
return poolManager, nil return poolManager, nil
@ -124,7 +122,7 @@ func (p *poolManagerCtrl) GetRepoPoolManager(repo params.Repository) (common.Poo
if repoPoolMgr, ok := p.repositories[repo.ID]; ok { if repoPoolMgr, ok := p.repositories[repo.ID]; ok {
return repoPoolMgr, nil return repoPoolMgr, nil
} }
return nil, errors.Wrapf(runnerErrors.ErrNotFound, "repository %s/%s pool manager not loaded", repo.Owner, repo.Name) return nil, fmt.Errorf("repository %s/%s pool manager not loaded: %w", repo.Owner, repo.Name, runnerErrors.ErrNotFound)
} }
func (p *poolManagerCtrl) DeleteRepoPoolManager(repo params.Repository) error { func (p *poolManagerCtrl) DeleteRepoPoolManager(repo params.Repository) error {
@ -134,7 +132,7 @@ func (p *poolManagerCtrl) DeleteRepoPoolManager(repo params.Repository) error {
poolMgr, ok := p.repositories[repo.ID] poolMgr, ok := p.repositories[repo.ID]
if ok { if ok {
if err := poolMgr.Stop(); err != nil { if err := poolMgr.Stop(); err != nil {
return errors.Wrap(err, "stopping repo pool manager") return fmt.Errorf("error stopping repo pool manager: %w", err)
} }
delete(p.repositories, repo.ID) delete(p.repositories, repo.ID)
} }
@ -151,16 +149,16 @@ func (p *poolManagerCtrl) CreateOrgPoolManager(ctx context.Context, org params.O
entity, err := org.GetEntity() entity, err := org.GetEntity()
if err != nil { if err != nil {
return nil, errors.Wrap(err, "getting entity") return nil, fmt.Errorf("error getting entity: %w", err)
} }
instanceTokenGetter, err := auth.NewInstanceTokenGetter(p.config.JWTAuth.Secret) instanceTokenGetter, err := auth.NewInstanceTokenGetter(p.config.JWTAuth.Secret)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "creating instance token getter") return nil, fmt.Errorf("error creating instance token getter: %w", err)
} }
poolManager, err := pool.NewEntityPoolManager(ctx, entity, instanceTokenGetter, providers, store) poolManager, err := pool.NewEntityPoolManager(ctx, entity, instanceTokenGetter, providers, store)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "creating org pool manager") return nil, fmt.Errorf("error creating org pool manager: %w", err)
} }
p.organizations[org.ID] = poolManager p.organizations[org.ID] = poolManager
return poolManager, nil return poolManager, nil
@ -170,7 +168,7 @@ func (p *poolManagerCtrl) GetOrgPoolManager(org params.Organization) (common.Poo
if orgPoolMgr, ok := p.organizations[org.ID]; ok { if orgPoolMgr, ok := p.organizations[org.ID]; ok {
return orgPoolMgr, nil return orgPoolMgr, nil
} }
return nil, errors.Wrapf(runnerErrors.ErrNotFound, "organization %s pool manager not loaded", org.Name) return nil, fmt.Errorf("organization %s pool manager not loaded: %w", org.Name, runnerErrors.ErrNotFound)
} }
func (p *poolManagerCtrl) DeleteOrgPoolManager(org params.Organization) error { func (p *poolManagerCtrl) DeleteOrgPoolManager(org params.Organization) error {
@ -180,7 +178,7 @@ func (p *poolManagerCtrl) DeleteOrgPoolManager(org params.Organization) error {
poolMgr, ok := p.organizations[org.ID] poolMgr, ok := p.organizations[org.ID]
if ok { if ok {
if err := poolMgr.Stop(); err != nil { if err := poolMgr.Stop(); err != nil {
return errors.Wrap(err, "stopping org pool manager") return fmt.Errorf("error stopping org pool manager: %w", err)
} }
delete(p.organizations, org.ID) delete(p.organizations, org.ID)
} }
@ -197,16 +195,16 @@ func (p *poolManagerCtrl) CreateEnterprisePoolManager(ctx context.Context, enter
entity, err := enterprise.GetEntity() entity, err := enterprise.GetEntity()
if err != nil { if err != nil {
return nil, errors.Wrap(err, "getting entity") return nil, fmt.Errorf("error getting entity: %w", err)
} }
instanceTokenGetter, err := auth.NewInstanceTokenGetter(p.config.JWTAuth.Secret) instanceTokenGetter, err := auth.NewInstanceTokenGetter(p.config.JWTAuth.Secret)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "creating instance token getter") return nil, fmt.Errorf("error creating instance token getter: %w", err)
} }
poolManager, err := pool.NewEntityPoolManager(ctx, entity, instanceTokenGetter, providers, store) poolManager, err := pool.NewEntityPoolManager(ctx, entity, instanceTokenGetter, providers, store)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "creating enterprise pool manager") return nil, fmt.Errorf("error creating enterprise pool manager: %w", err)
} }
p.enterprises[enterprise.ID] = poolManager p.enterprises[enterprise.ID] = poolManager
return poolManager, nil return poolManager, nil
@ -216,7 +214,7 @@ func (p *poolManagerCtrl) GetEnterprisePoolManager(enterprise params.Enterprise)
if enterprisePoolMgr, ok := p.enterprises[enterprise.ID]; ok { if enterprisePoolMgr, ok := p.enterprises[enterprise.ID]; ok {
return enterprisePoolMgr, nil return enterprisePoolMgr, nil
} }
return nil, errors.Wrapf(runnerErrors.ErrNotFound, "enterprise %s pool manager not loaded", enterprise.Name) return nil, fmt.Errorf("enterprise %s pool manager not loaded: %w", enterprise.Name, runnerErrors.ErrNotFound)
} }
func (p *poolManagerCtrl) DeleteEnterprisePoolManager(enterprise params.Enterprise) error { func (p *poolManagerCtrl) DeleteEnterprisePoolManager(enterprise params.Enterprise) error {
@ -226,7 +224,7 @@ func (p *poolManagerCtrl) DeleteEnterprisePoolManager(enterprise params.Enterpri
poolMgr, ok := p.enterprises[enterprise.ID] poolMgr, ok := p.enterprises[enterprise.ID]
if ok { if ok {
if err := poolMgr.Stop(); err != nil { if err := poolMgr.Stop(); err != nil {
return errors.Wrap(err, "stopping enterprise pool manager") return fmt.Errorf("error stopping enterprise pool manager: %w", err)
} }
delete(p.enterprises, enterprise.ID) delete(p.enterprises, enterprise.ID)
} }
@ -256,12 +254,12 @@ func (r *Runner) UpdateController(ctx context.Context, param params.UpdateContro
} }
if err := param.Validate(); err != nil { if err := param.Validate(); err != nil {
return params.ControllerInfo{}, errors.Wrap(err, "validating controller update params") return params.ControllerInfo{}, fmt.Errorf("error validating controller update params: %w", err)
} }
info, err := r.store.UpdateController(param) info, err := r.store.UpdateController(param)
if err != nil { if err != nil {
return params.ControllerInfo{}, errors.Wrap(err, "updating controller info") return params.ControllerInfo{}, fmt.Errorf("error updating controller info: %w", err)
} }
return info, nil return info, nil
} }
@ -281,26 +279,26 @@ func (r *Runner) GetControllerInfo(ctx context.Context) (params.ControllerInfo,
// As a side note, Windows requires a reboot for the hostname change to take effect, // As a side note, Windows requires a reboot for the hostname change to take effect,
// so if we'll ever support Windows as a target system, the hostname can be cached. // so if we'll ever support Windows as a target system, the hostname can be cached.
var hostname string var hostname string
err := retry.Call(retry.CallArgs{ var err error
Func: func() error { for range 10 {
var err error hostname, err = os.Hostname()
hostname, err = os.Hostname() if err != nil {
if err != nil { select {
return errors.Wrap(err, "fetching hostname") case <-time.After(10 * time.Millisecond):
continue
case <-ctx.Done():
} }
return nil return params.ControllerInfo{}, fmt.Errorf("error fetching hostname: %w", err)
}, }
Attempts: 10, break
Delay: 100 * time.Millisecond, }
Clock: clock.WallClock,
})
if err != nil { if err != nil {
return params.ControllerInfo{}, errors.Wrap(err, "fetching hostname") return params.ControllerInfo{}, fmt.Errorf("error fetching hostname: %w", err)
} }
info, err := r.store.ControllerInfo() info, err := r.store.ControllerInfo()
if err != nil { if err != nil {
return params.ControllerInfo{}, errors.Wrap(err, "fetching controller info") return params.ControllerInfo{}, fmt.Errorf("error fetching controller info: %w", err)
} }
// This is temporary. Right now, GARM is a single-instance deployment. When we add the // This is temporary. Right now, GARM is a single-instance deployment. When we add the
@ -329,17 +327,17 @@ func (r *Runner) loadReposOrgsAndEnterprises() error {
repos, err := r.store.ListRepositories(r.ctx, params.RepositoryFilter{}) repos, err := r.store.ListRepositories(r.ctx, params.RepositoryFilter{})
if err != nil { if err != nil {
return errors.Wrap(err, "fetching repositories") return fmt.Errorf("error fetching repositories: %w", err)
} }
orgs, err := r.store.ListOrganizations(r.ctx, params.OrganizationFilter{}) orgs, err := r.store.ListOrganizations(r.ctx, params.OrganizationFilter{})
if err != nil { if err != nil {
return errors.Wrap(err, "fetching organizations") return fmt.Errorf("error fetching organizations: %w", err)
} }
enterprises, err := r.store.ListEnterprises(r.ctx, params.EnterpriseFilter{}) enterprises, err := r.store.ListEnterprises(r.ctx, params.EnterpriseFilter{})
if err != nil { if err != nil {
return errors.Wrap(err, "fetching enterprises") return fmt.Errorf("error fetching enterprises: %w", err)
} }
g, _ := errgroup.WithContext(r.ctx) g, _ := errgroup.WithContext(r.ctx)
@ -384,17 +382,17 @@ func (r *Runner) Start() error {
repositories, err := r.poolManagerCtrl.GetRepoPoolManagers() repositories, err := r.poolManagerCtrl.GetRepoPoolManagers()
if err != nil { if err != nil {
return errors.Wrap(err, "fetch repo pool managers") return fmt.Errorf("error fetch repo pool managers: %w", err)
} }
organizations, err := r.poolManagerCtrl.GetOrgPoolManagers() organizations, err := r.poolManagerCtrl.GetOrgPoolManagers()
if err != nil { if err != nil {
return errors.Wrap(err, "fetch org pool managers") return fmt.Errorf("error fetch org pool managers: %w", err)
} }
enterprises, err := r.poolManagerCtrl.GetEnterprisePoolManagers() enterprises, err := r.poolManagerCtrl.GetEnterprisePoolManagers()
if err != nil { if err != nil {
return errors.Wrap(err, "fetch enterprise pool managers") return fmt.Errorf("error fetch enterprise pool managers: %w", err)
} }
g, _ := errgroup.WithContext(r.ctx) g, _ := errgroup.WithContext(r.ctx)
@ -450,17 +448,17 @@ func (r *Runner) Stop() error {
repos, err := r.poolManagerCtrl.GetRepoPoolManagers() repos, err := r.poolManagerCtrl.GetRepoPoolManagers()
if err != nil { if err != nil {
return errors.Wrap(err, "fetch repo pool managers") return fmt.Errorf("error fetching repo pool managers: %w", err)
} }
orgs, err := r.poolManagerCtrl.GetOrgPoolManagers() orgs, err := r.poolManagerCtrl.GetOrgPoolManagers()
if err != nil { if err != nil {
return errors.Wrap(err, "fetch org pool managers") return fmt.Errorf("error fetching org pool managers: %w", err)
} }
enterprises, err := r.poolManagerCtrl.GetEnterprisePoolManagers() enterprises, err := r.poolManagerCtrl.GetEnterprisePoolManagers()
if err != nil { if err != nil {
return errors.Wrap(err, "fetch enterprise pool managers") return fmt.Errorf("error fetching enterprise pool managers: %w", err)
} }
g, _ := errgroup.WithContext(r.ctx) g, _ := errgroup.WithContext(r.ctx)
@ -512,17 +510,17 @@ func (r *Runner) Wait() error {
repos, err := r.poolManagerCtrl.GetRepoPoolManagers() repos, err := r.poolManagerCtrl.GetRepoPoolManagers()
if err != nil { if err != nil {
return errors.Wrap(err, "fetch repo pool managers") return fmt.Errorf("error fetching repo pool managers: %w", err)
} }
orgs, err := r.poolManagerCtrl.GetOrgPoolManagers() orgs, err := r.poolManagerCtrl.GetOrgPoolManagers()
if err != nil { if err != nil {
return errors.Wrap(err, "fetch org pool managers") return fmt.Errorf("error fetching org pool managers: %w", err)
} }
enterprises, err := r.poolManagerCtrl.GetEnterprisePoolManagers() enterprises, err := r.poolManagerCtrl.GetEnterprisePoolManagers()
if err != nil { if err != nil {
return errors.Wrap(err, "fetch enterprise pool managers") return fmt.Errorf("error fetching enterprise pool managers: %w", err)
} }
for poolID, repo := range repos { for poolID, repo := range repos {
@ -591,7 +589,7 @@ func (r *Runner) validateHookBody(signature, secret string, body []byte) error {
mac := hmac.New(hashFunc, []byte(secret)) mac := hmac.New(hashFunc, []byte(secret))
_, err := mac.Write(body) _, err := mac.Write(body)
if err != nil { if err != nil {
return errors.Wrap(err, "failed to compute sha256") return fmt.Errorf("failed to compute sha256: %w", err)
} }
expectedMAC := hex.EncodeToString(mac.Sum(nil)) expectedMAC := hex.EncodeToString(mac.Sum(nil))
@ -605,7 +603,7 @@ func (r *Runner) validateHookBody(signature, secret string, body []byte) error {
func (r *Runner) findEndpointForJob(job params.WorkflowJob, forgeType params.EndpointType) (params.ForgeEndpoint, error) { func (r *Runner) findEndpointForJob(job params.WorkflowJob, forgeType params.EndpointType) (params.ForgeEndpoint, error) {
uri, err := url.ParseRequestURI(job.WorkflowJob.HTMLURL) uri, err := url.ParseRequestURI(job.WorkflowJob.HTMLURL)
if err != nil { if err != nil {
return params.ForgeEndpoint{}, errors.Wrap(err, "parsing job URL") return params.ForgeEndpoint{}, fmt.Errorf("error parsing job URL: %w", err)
} }
baseURI := fmt.Sprintf("%s://%s", uri.Scheme, uri.Host) baseURI := fmt.Sprintf("%s://%s", uri.Scheme, uri.Host)
@ -625,7 +623,7 @@ func (r *Runner) findEndpointForJob(job params.WorkflowJob, forgeType params.End
} }
if err != nil { if err != nil {
return params.ForgeEndpoint{}, errors.Wrap(err, "fetching github endpoints") return params.ForgeEndpoint{}, fmt.Errorf("error fetching github endpoints: %w", err)
} }
for _, ep := range endpoints { for _, ep := range endpoints {
slog.DebugContext(r.ctx, "checking endpoint", "base_uri", baseURI, "endpoint", ep.BaseURL) slog.DebugContext(r.ctx, "checking endpoint", "base_uri", baseURI, "endpoint", ep.BaseURL)
@ -647,13 +645,13 @@ func (r *Runner) DispatchWorkflowJob(hookTargetType, signature string, forgeType
var job params.WorkflowJob var job params.WorkflowJob
if err := json.Unmarshal(jobData, &job); err != nil { if err := json.Unmarshal(jobData, &job); err != nil {
slog.ErrorContext(r.ctx, "failed to unmarshal job data", "error", err) slog.ErrorContext(r.ctx, "failed to unmarshal job data", "error", err)
return errors.Wrapf(runnerErrors.ErrBadRequest, "invalid job data: %s", err) return fmt.Errorf("invalid job data %s: %w", err, runnerErrors.ErrBadRequest)
} }
endpoint, err := r.findEndpointForJob(job, forgeType) endpoint, err := r.findEndpointForJob(job, forgeType)
if err != nil { if err != nil {
slog.ErrorContext(r.ctx, "failed to find endpoint for job", "error", err) slog.ErrorContext(r.ctx, "failed to find endpoint for job", "error", err)
return errors.Wrap(err, "finding endpoint for job") return fmt.Errorf("error finding endpoint for job: %w", err)
} }
var poolManager common.PoolManager var poolManager common.PoolManager
@ -687,7 +685,7 @@ func (r *Runner) DispatchWorkflowJob(hookTargetType, signature string, forgeType
slog.ErrorContext(r.ctx, "failed to find pool manager", "error", err, "hook_target_type", hookTargetType) slog.ErrorContext(r.ctx, "failed to find pool manager", "error", err, "hook_target_type", hookTargetType)
// We don't have a repository or organization configured that // We don't have a repository or organization configured that
// can handle this workflow job. // can handle this workflow job.
return errors.Wrap(err, "fetching poolManager") return fmt.Errorf("error fetching poolManager: %w", err)
} }
// We found a pool. Validate the webhook job. If a secret is configured, // We found a pool. Validate the webhook job. If a secret is configured,
@ -695,12 +693,12 @@ func (r *Runner) DispatchWorkflowJob(hookTargetType, signature string, forgeType
secret := poolManager.WebhookSecret() secret := poolManager.WebhookSecret()
if err := r.validateHookBody(signature, secret, jobData); err != nil { if err := r.validateHookBody(signature, secret, jobData); err != nil {
slog.ErrorContext(r.ctx, "failed to validate webhook data", "error", err) slog.ErrorContext(r.ctx, "failed to validate webhook data", "error", err)
return errors.Wrap(err, "validating webhook data") return fmt.Errorf("error validating webhook data: %w", err)
} }
if err := poolManager.HandleWorkflowJob(job); err != nil { if err := poolManager.HandleWorkflowJob(job); err != nil {
slog.ErrorContext(r.ctx, "failed to handle workflow job", "error", err) slog.ErrorContext(r.ctx, "failed to handle workflow job", "error", err)
return errors.Wrap(err, "handling workflow job") return fmt.Errorf("error handling workflow job: %w", err)
} }
return nil return nil
@ -735,7 +733,7 @@ func (r *Runner) GetInstance(ctx context.Context, instanceName string) (params.I
instance, err := r.store.GetInstanceByName(ctx, instanceName) instance, err := r.store.GetInstanceByName(ctx, instanceName)
if err != nil { if err != nil {
return params.Instance{}, errors.Wrap(err, "fetching instance") return params.Instance{}, fmt.Errorf("error fetching instance: %w", err)
} }
return instance, nil return instance, nil
} }
@ -747,7 +745,7 @@ func (r *Runner) ListAllInstances(ctx context.Context) ([]params.Instance, error
instances, err := r.store.ListAllInstances(ctx) instances, err := r.store.ListAllInstances(ctx)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching instances") return nil, fmt.Errorf("error fetching instances: %w", err)
} }
return instances, nil return instances, nil
} }
@ -759,7 +757,7 @@ func (r *Runner) AddInstanceStatusMessage(ctx context.Context, param params.Inst
} }
if err := r.store.AddInstanceEvent(ctx, instanceName, params.StatusEvent, params.EventInfo, param.Message); err != nil { if err := r.store.AddInstanceEvent(ctx, instanceName, params.StatusEvent, params.EventInfo, param.Message); err != nil {
return errors.Wrap(err, "adding status update") return fmt.Errorf("error adding status update: %w", err)
} }
updateParams := params.UpdateInstanceParams{ updateParams := params.UpdateInstanceParams{
@ -771,7 +769,7 @@ func (r *Runner) AddInstanceStatusMessage(ctx context.Context, param params.Inst
} }
if _, err := r.store.UpdateInstance(r.ctx, instanceName, updateParams); err != nil { if _, err := r.store.UpdateInstance(r.ctx, instanceName, updateParams); err != nil {
return errors.Wrap(err, "updating runner agent ID") return fmt.Errorf("error updating runner agent ID: %w", err)
} }
return nil return nil
@ -799,7 +797,7 @@ func (r *Runner) UpdateSystemInfo(ctx context.Context, param params.UpdateSystem
} }
if _, err := r.store.UpdateInstance(r.ctx, instanceName, updateParams); err != nil { if _, err := r.store.UpdateInstance(r.ctx, instanceName, updateParams); err != nil {
return errors.Wrap(err, "updating runner system info") return fmt.Errorf("error updating runner system info: %w", err)
} }
return nil return nil
@ -808,7 +806,7 @@ func (r *Runner) UpdateSystemInfo(ctx context.Context, param params.UpdateSystem
func (r *Runner) getPoolManagerFromInstance(ctx context.Context, instance params.Instance) (common.PoolManager, error) { func (r *Runner) getPoolManagerFromInstance(ctx context.Context, instance params.Instance) (common.PoolManager, error) {
pool, err := r.store.GetPoolByID(ctx, instance.PoolID) pool, err := r.store.GetPoolByID(ctx, instance.PoolID)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching pool") return nil, fmt.Errorf("error fetching pool: %w", err)
} }
var poolMgr common.PoolManager var poolMgr common.PoolManager
@ -817,29 +815,29 @@ func (r *Runner) getPoolManagerFromInstance(ctx context.Context, instance params
case pool.RepoID != "": case pool.RepoID != "":
repo, err := r.store.GetRepositoryByID(ctx, pool.RepoID) repo, err := r.store.GetRepositoryByID(ctx, pool.RepoID)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching repo") return nil, fmt.Errorf("error fetching repo: %w", err)
} }
poolMgr, err = r.findRepoPoolManager(repo.Owner, repo.Name, repo.Endpoint.Name) poolMgr, err = r.findRepoPoolManager(repo.Owner, repo.Name, repo.Endpoint.Name)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "fetching pool manager for repo %s", pool.RepoName) return nil, fmt.Errorf("error fetching pool manager for repo %s: %w", pool.RepoName, err)
} }
case pool.OrgID != "": case pool.OrgID != "":
org, err := r.store.GetOrganizationByID(ctx, pool.OrgID) org, err := r.store.GetOrganizationByID(ctx, pool.OrgID)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching org") return nil, fmt.Errorf("error fetching org: %w", err)
} }
poolMgr, err = r.findOrgPoolManager(org.Name, org.Endpoint.Name) poolMgr, err = r.findOrgPoolManager(org.Name, org.Endpoint.Name)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "fetching pool manager for org %s", pool.OrgName) return nil, fmt.Errorf("error fetching pool manager for org %s: %w", pool.OrgName, err)
} }
case pool.EnterpriseID != "": case pool.EnterpriseID != "":
enterprise, err := r.store.GetEnterpriseByID(ctx, pool.EnterpriseID) enterprise, err := r.store.GetEnterpriseByID(ctx, pool.EnterpriseID)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching enterprise") return nil, fmt.Errorf("error fetching enterprise: %w", err)
} }
poolMgr, err = r.findEnterprisePoolManager(enterprise.Name, enterprise.Endpoint.Name) poolMgr, err = r.findEnterprisePoolManager(enterprise.Name, enterprise.Endpoint.Name)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "fetching pool manager for enterprise %s", pool.EnterpriseName) return nil, fmt.Errorf("error fetching pool manager for enterprise %s: %w", pool.EnterpriseName, err)
} }
} }
@ -856,7 +854,7 @@ func (r *Runner) DeleteRunner(ctx context.Context, instanceName string, forceDel
instance, err := r.store.GetInstanceByName(ctx, instanceName) instance, err := r.store.GetInstanceByName(ctx, instanceName)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching instance") return fmt.Errorf("error fetching instance: %w", err)
} }
switch instance.Status { switch instance.Status {
@ -874,7 +872,7 @@ func (r *Runner) DeleteRunner(ctx context.Context, instanceName string, forceDel
ghCli, ssCli, err := r.getGHCliFromInstance(ctx, instance) ghCli, ssCli, err := r.getGHCliFromInstance(ctx, instance)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching github client") return fmt.Errorf("error fetching github client: %w", err)
} }
if instance.AgentID != 0 { if instance.AgentID != 0 {
@ -892,12 +890,12 @@ func (r *Runner) DeleteRunner(ctx context.Context, instanceName string, forceDel
if errors.Is(err, runnerErrors.ErrUnauthorized) && instance.PoolID != "" { if errors.Is(err, runnerErrors.ErrUnauthorized) && instance.PoolID != "" {
poolMgr, err := r.getPoolManagerFromInstance(ctx, instance) poolMgr, err := r.getPoolManagerFromInstance(ctx, instance)
if err != nil { if err != nil {
return errors.Wrap(err, "fetching pool manager for instance") return fmt.Errorf("error fetching pool manager for instance: %w", err)
} }
poolMgr.SetPoolRunningState(false, fmt.Sprintf("failed to remove runner: %q", err)) poolMgr.SetPoolRunningState(false, fmt.Sprintf("failed to remove runner: %q", err))
} }
if !bypassGithubUnauthorized { if !bypassGithubUnauthorized {
return errors.Wrap(err, "removing runner from github") return fmt.Errorf("error removing runner from github: %w", err)
} }
} }
} }
@ -918,7 +916,7 @@ func (r *Runner) DeleteRunner(ctx context.Context, instanceName string, forceDel
} }
_, err = r.store.UpdateInstance(r.ctx, instance.Name, updateParams) _, err = r.store.UpdateInstance(r.ctx, instance.Name, updateParams)
if err != nil { if err != nil {
return errors.Wrap(err, "updating runner state") return fmt.Errorf("error updating runner state: %w", err)
} }
return nil return nil
@ -934,12 +932,12 @@ func (r *Runner) getGHCliFromInstance(ctx context.Context, instance params.Insta
case instance.PoolID != "": case instance.PoolID != "":
entityGetter, err = r.store.GetPoolByID(ctx, instance.PoolID) entityGetter, err = r.store.GetPoolByID(ctx, instance.PoolID)
if err != nil { if err != nil {
return nil, nil, errors.Wrap(err, "fetching pool") return nil, nil, fmt.Errorf("error fetching pool: %w", err)
} }
case instance.ScaleSetID != 0: case instance.ScaleSetID != 0:
entityGetter, err = r.store.GetScaleSetByID(ctx, instance.ScaleSetID) entityGetter, err = r.store.GetScaleSetByID(ctx, instance.ScaleSetID)
if err != nil { if err != nil {
return nil, nil, errors.Wrap(err, "fetching scale set") return nil, nil, fmt.Errorf("error fetching scale set: %w", err)
} }
default: default:
return nil, nil, errors.New("instance does not have a pool or scale set") return nil, nil, errors.New("instance does not have a pool or scale set")
@ -947,23 +945,23 @@ func (r *Runner) getGHCliFromInstance(ctx context.Context, instance params.Insta
entity, err := entityGetter.GetEntity() entity, err := entityGetter.GetEntity()
if err != nil { if err != nil {
return nil, nil, errors.Wrap(err, "fetching entity") return nil, nil, fmt.Errorf("error fetching entity: %w", err)
} }
// Fetching the entity from the database will populate all fields, including credentials. // Fetching the entity from the database will populate all fields, including credentials.
entity, err = r.store.GetForgeEntity(ctx, entity.EntityType, entity.ID) entity, err = r.store.GetForgeEntity(ctx, entity.EntityType, entity.ID)
if err != nil { if err != nil {
return nil, nil, errors.Wrap(err, "fetching entity") return nil, nil, fmt.Errorf("error fetching entity: %w", err)
} }
ghCli, err := github.Client(ctx, entity) ghCli, err := github.Client(ctx, entity)
if err != nil { if err != nil {
return nil, nil, errors.Wrap(err, "creating github client") return nil, nil, fmt.Errorf("error creating github client: %w", err)
} }
scaleSetCli, err := scalesets.NewClient(ghCli) scaleSetCli, err := scalesets.NewClient(ghCli)
if err != nil { if err != nil {
return nil, nil, errors.Wrap(err, "creating scaleset client") return nil, nil, fmt.Errorf("error creating scaleset client: %w", err)
} }
return ghCli, scaleSetCli, nil return ghCli, scaleSetCli, nil
} }

View file

@ -16,11 +16,10 @@ package runner
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"log/slog" "log/slog"
"github.com/pkg/errors"
runnerErrors "github.com/cloudbase/garm-provider-common/errors" runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/auth" "github.com/cloudbase/garm/auth"
"github.com/cloudbase/garm/params" "github.com/cloudbase/garm/params"
@ -36,7 +35,7 @@ func (r *Runner) ListAllScaleSets(ctx context.Context) ([]params.ScaleSet, error
scalesets, err := r.store.ListAllScaleSets(ctx) scalesets, err := r.store.ListAllScaleSets(ctx)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching pools") return nil, fmt.Errorf("error fetching pools: %w", err)
} }
return scalesets, nil return scalesets, nil
} }
@ -48,7 +47,7 @@ func (r *Runner) GetScaleSetByID(ctx context.Context, scaleSet uint) (params.Sca
set, err := r.store.GetScaleSetByID(ctx, scaleSet) set, err := r.store.GetScaleSetByID(ctx, scaleSet)
if err != nil { if err != nil {
return params.ScaleSet{}, errors.Wrap(err, "fetching scale set") return params.ScaleSet{}, fmt.Errorf("error fetching scale set: %w", err)
} }
return set, nil return set, nil
} }
@ -61,7 +60,7 @@ func (r *Runner) DeleteScaleSetByID(ctx context.Context, scaleSetID uint) error
scaleSet, err := r.store.GetScaleSetByID(ctx, scaleSetID) scaleSet, err := r.store.GetScaleSetByID(ctx, scaleSetID)
if err != nil { if err != nil {
if !errors.Is(err, runnerErrors.ErrNotFound) { if !errors.Is(err, runnerErrors.ErrNotFound) {
return errors.Wrap(err, "fetching scale set") return fmt.Errorf("error fetching scale set: %w", err)
} }
return nil return nil
} }
@ -76,22 +75,22 @@ func (r *Runner) DeleteScaleSetByID(ctx context.Context, scaleSetID uint) error
paramEntity, err := scaleSet.GetEntity() paramEntity, err := scaleSet.GetEntity()
if err != nil { if err != nil {
return errors.Wrap(err, "getting entity") return fmt.Errorf("error getting entity: %w", err)
} }
entity, err := r.store.GetForgeEntity(ctx, paramEntity.EntityType, paramEntity.ID) entity, err := r.store.GetForgeEntity(ctx, paramEntity.EntityType, paramEntity.ID)
if err != nil { if err != nil {
return errors.Wrap(err, "getting entity") return fmt.Errorf("error getting entity: %w", err)
} }
ghCli, err := github.Client(ctx, entity) ghCli, err := github.Client(ctx, entity)
if err != nil { if err != nil {
return errors.Wrap(err, "creating github client") return fmt.Errorf("error creating github client: %w", err)
} }
scalesetCli, err := scalesets.NewClient(ghCli) scalesetCli, err := scalesets.NewClient(ghCli)
if err != nil { if err != nil {
return errors.Wrap(err, "getting scaleset client") return fmt.Errorf("error getting scaleset client: %w", err)
} }
slog.DebugContext(ctx, "deleting scale set", "scale_set_id", scaleSet.ScaleSetID) slog.DebugContext(ctx, "deleting scale set", "scale_set_id", scaleSet.ScaleSetID)
@ -101,10 +100,10 @@ func (r *Runner) DeleteScaleSetByID(ctx context.Context, scaleSetID uint) error
return nil return nil
} }
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to delete scale set from github") slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to delete scale set from github")
return errors.Wrap(err, "deleting scale set from github") return fmt.Errorf("error deleting scale set from github: %w", err)
} }
if err := r.store.DeleteScaleSetByID(ctx, scaleSetID); err != nil { if err := r.store.DeleteScaleSetByID(ctx, scaleSetID); err != nil {
return errors.Wrap(err, "deleting scale set") return fmt.Errorf("error deleting scale set: %w", err)
} }
return nil return nil
} }
@ -116,7 +115,7 @@ func (r *Runner) UpdateScaleSetByID(ctx context.Context, scaleSetID uint, param
scaleSet, err := r.store.GetScaleSetByID(ctx, scaleSetID) scaleSet, err := r.store.GetScaleSetByID(ctx, scaleSetID)
if err != nil { if err != nil {
return params.ScaleSet{}, errors.Wrap(err, "fetching scale set") return params.ScaleSet{}, fmt.Errorf("error fetching scale set: %w", err)
} }
maxRunners := scaleSet.MaxRunners maxRunners := scaleSet.MaxRunners
@ -139,22 +138,22 @@ func (r *Runner) UpdateScaleSetByID(ctx context.Context, scaleSetID uint, param
paramEntity, err := scaleSet.GetEntity() paramEntity, err := scaleSet.GetEntity()
if err != nil { if err != nil {
return params.ScaleSet{}, errors.Wrap(err, "getting entity") return params.ScaleSet{}, fmt.Errorf("error getting entity: %w", err)
} }
entity, err := r.store.GetForgeEntity(ctx, paramEntity.EntityType, paramEntity.ID) entity, err := r.store.GetForgeEntity(ctx, paramEntity.EntityType, paramEntity.ID)
if err != nil { if err != nil {
return params.ScaleSet{}, errors.Wrap(err, "getting entity") return params.ScaleSet{}, fmt.Errorf("error getting entity: %w", err)
} }
ghCli, err := github.Client(ctx, entity) ghCli, err := github.Client(ctx, entity)
if err != nil { if err != nil {
return params.ScaleSet{}, errors.Wrap(err, "creating github client") return params.ScaleSet{}, fmt.Errorf("error creating github client: %w", err)
} }
scalesetCli, err := scalesets.NewClient(ghCli) scalesetCli, err := scalesets.NewClient(ghCli)
if err != nil { if err != nil {
return params.ScaleSet{}, errors.Wrap(err, "getting scaleset client") return params.ScaleSet{}, fmt.Errorf("error getting scaleset client: %w", err)
} }
callback := func(old, newSet params.ScaleSet) error { callback := func(old, newSet params.ScaleSet) error {
@ -190,7 +189,7 @@ func (r *Runner) UpdateScaleSetByID(ctx context.Context, scaleSetID uint, param
newScaleSet, err := r.store.UpdateEntityScaleSet(ctx, entity, scaleSetID, param, callback) newScaleSet, err := r.store.UpdateEntityScaleSet(ctx, entity, scaleSetID, param, callback)
if err != nil { if err != nil {
return params.ScaleSet{}, errors.Wrap(err, "updating pool") return params.ScaleSet{}, fmt.Errorf("error updating pool: %w", err)
} }
return newScaleSet, nil return newScaleSet, nil
} }
@ -210,7 +209,7 @@ func (r *Runner) CreateEntityScaleSet(ctx context.Context, entityType params.For
entity, err := r.store.GetForgeEntity(ctx, entityType, entityID) entity, err := r.store.GetForgeEntity(ctx, entityType, entityID)
if err != nil { if err != nil {
return params.ScaleSet{}, errors.Wrap(err, "getting entity") return params.ScaleSet{}, fmt.Errorf("error getting entity: %w", err)
} }
if entity.Credentials.ForgeType != params.GithubEndpointType { if entity.Credentials.ForgeType != params.GithubEndpointType {
@ -219,18 +218,18 @@ func (r *Runner) CreateEntityScaleSet(ctx context.Context, entityType params.For
ghCli, err := github.Client(ctx, entity) ghCli, err := github.Client(ctx, entity)
if err != nil { if err != nil {
return params.ScaleSet{}, errors.Wrap(err, "creating github client") return params.ScaleSet{}, fmt.Errorf("error creating github client: %w", err)
} }
scalesetCli, err := scalesets.NewClient(ghCli) scalesetCli, err := scalesets.NewClient(ghCli)
if err != nil { if err != nil {
return params.ScaleSet{}, errors.Wrap(err, "getting scaleset client") return params.ScaleSet{}, fmt.Errorf("error getting scaleset client: %w", err)
} }
var runnerGroupID int64 = 1 var runnerGroupID int64 = 1
if param.GitHubRunnerGroup != "Default" { if param.GitHubRunnerGroup != "Default" {
runnerGroup, err := scalesetCli.GetRunnerGroupByName(ctx, param.GitHubRunnerGroup) runnerGroup, err := scalesetCli.GetRunnerGroupByName(ctx, param.GitHubRunnerGroup)
if err != nil { if err != nil {
return params.ScaleSet{}, errors.Wrap(err, "getting runner group") return params.ScaleSet{}, fmt.Errorf("error getting runner group: %w", err)
} }
runnerGroupID = runnerGroup.ID runnerGroupID = runnerGroup.ID
} }
@ -253,7 +252,7 @@ func (r *Runner) CreateEntityScaleSet(ctx context.Context, entityType params.For
runnerScaleSet, err := scalesetCli.CreateRunnerScaleSet(ctx, createParam) runnerScaleSet, err := scalesetCli.CreateRunnerScaleSet(ctx, createParam)
if err != nil { if err != nil {
return params.ScaleSet{}, errors.Wrap(err, "creating runner scale set") return params.ScaleSet{}, fmt.Errorf("error creating runner scale set: %w", err)
} }
defer func() { defer func() {
@ -267,7 +266,7 @@ func (r *Runner) CreateEntityScaleSet(ctx context.Context, entityType params.For
scaleSet, err := r.store.CreateEntityScaleSet(ctx, entity, param) scaleSet, err := r.store.CreateEntityScaleSet(ctx, entity, param)
if err != nil { if err != nil {
return params.ScaleSet{}, errors.Wrap(err, "creating scale set") return params.ScaleSet{}, fmt.Errorf("error creating scale set: %w", err)
} }
return scaleSet, nil return scaleSet, nil
@ -280,7 +279,7 @@ func (r *Runner) ListScaleSetInstances(ctx context.Context, scalesetID uint) ([]
instances, err := r.store.ListScaleSetInstances(ctx, scalesetID) instances, err := r.store.ListScaleSetInstances(ctx, scalesetID)
if err != nil { if err != nil {
return []params.Instance{}, errors.Wrap(err, "fetching instances") return []params.Instance{}, fmt.Errorf("error fetching instances: %w", err)
} }
return instances, nil return instances, nil
} }
@ -295,7 +294,7 @@ func (r *Runner) ListEntityScaleSets(ctx context.Context, entityType params.Forg
} }
scaleSets, err := r.store.ListEntityScaleSets(ctx, entity) scaleSets, err := r.store.ListEntityScaleSets(ctx, entity)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching scale sets") return nil, fmt.Errorf("error fetching scale sets: %w", err)
} }
return scaleSets, nil return scaleSets, nil
} }

View file

@ -18,6 +18,7 @@ import (
"context" "context"
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"log/slog" "log/slog"
"net/http" "net/http"
@ -25,7 +26,6 @@ import (
"strings" "strings"
"github.com/google/go-github/v72/github" "github.com/google/go-github/v72/github"
"github.com/pkg/errors"
runnerErrors "github.com/cloudbase/garm-provider-common/errors" runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm/metrics" "github.com/cloudbase/garm/metrics"
@ -309,7 +309,7 @@ func (g *githubClient) RemoveEntityRunner(ctx context.Context, runnerID int64) e
} }
if err := parseError(response, err); err != nil { if err := parseError(response, err); err != nil {
return errors.Wrapf(err, "removing runner %d", runnerID) return fmt.Errorf("error removing runner %d: %w", runnerID, err)
} }
return nil return nil
@ -366,9 +366,9 @@ func (g *githubClient) getOrganizationRunnerGroupIDByName(ctx context.Context, e
entity.LabelScope(), // label: scope entity.LabelScope(), // label: scope
).Inc() ).Inc()
if ghResp != nil && ghResp.StatusCode == http.StatusUnauthorized { if ghResp != nil && ghResp.StatusCode == http.StatusUnauthorized {
return 0, errors.Wrap(runnerErrors.ErrUnauthorized, "fetching runners") return 0, fmt.Errorf("error fetching runners: %w", runnerErrors.ErrUnauthorized)
} }
return 0, errors.Wrap(err, "fetching runners") return 0, fmt.Errorf("error fetching runners: %w", err)
} }
for _, runnerGroup := range runnerGroups.RunnerGroups { for _, runnerGroup := range runnerGroups.RunnerGroups {
if runnerGroup.Name != nil && *runnerGroup.Name == rgName { if runnerGroup.Name != nil && *runnerGroup.Name == rgName {
@ -402,9 +402,9 @@ func (g *githubClient) getEnterpriseRunnerGroupIDByName(ctx context.Context, ent
entity.LabelScope(), // label: scope entity.LabelScope(), // label: scope
).Inc() ).Inc()
if ghResp != nil && ghResp.StatusCode == http.StatusUnauthorized { if ghResp != nil && ghResp.StatusCode == http.StatusUnauthorized {
return 0, errors.Wrap(runnerErrors.ErrUnauthorized, "fetching runners") return 0, fmt.Errorf("error fetching runners: %w", runnerErrors.ErrUnauthorized)
} }
return 0, errors.Wrap(err, "fetching runners") return 0, fmt.Errorf("error fetching runners: %w", err)
} }
for _, runnerGroup := range runnerGroups.RunnerGroups { for _, runnerGroup := range runnerGroups.RunnerGroups {
if runnerGroup.Name != nil && *runnerGroup.Name == rgName { if runnerGroup.Name != nil && *runnerGroup.Name == rgName {
@ -520,7 +520,7 @@ func (g *githubClient) GithubBaseURL() *url.URL {
func NewRateLimitClient(ctx context.Context, credentials params.ForgeCredentials) (common.RateLimitClient, error) { func NewRateLimitClient(ctx context.Context, credentials params.ForgeCredentials) (common.RateLimitClient, error) {
httpClient, err := credentials.GetHTTPClient(ctx) httpClient, err := credentials.GetHTTPClient(ctx)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching http client") return nil, fmt.Errorf("error fetching http client: %w", err)
} }
slog.DebugContext( slog.DebugContext(
@ -531,7 +531,7 @@ func NewRateLimitClient(ctx context.Context, credentials params.ForgeCredentials
ghClient, err := github.NewClient(httpClient).WithEnterpriseURLs( ghClient, err := github.NewClient(httpClient).WithEnterpriseURLs(
credentials.APIBaseURL, credentials.UploadBaseURL) credentials.APIBaseURL, credentials.UploadBaseURL)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching github client") return nil, fmt.Errorf("error fetching github client: %w", err)
} }
cli := &githubClient{ cli := &githubClient{
rateLimit: ghClient.RateLimit, rateLimit: ghClient.RateLimit,
@ -552,7 +552,7 @@ func withGiteaURLs(client *github.Client, apiBaseURL string) (*github.Client, er
parsedBaseURL, err := url.ParseRequestURI(apiBaseURL) parsedBaseURL, err := url.ParseRequestURI(apiBaseURL)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "parsing gitea base URL") return nil, fmt.Errorf("error parsing gitea base URL: %w", err)
} }
if !strings.HasSuffix(parsedBaseURL.Path, "/") { if !strings.HasSuffix(parsedBaseURL.Path, "/") {
@ -573,7 +573,7 @@ func Client(ctx context.Context, entity params.ForgeEntity) (common.GithubClient
// func GithubClient(ctx context.Context, entity params.ForgeEntity) (common.GithubClient, error) { // func GithubClient(ctx context.Context, entity params.ForgeEntity) (common.GithubClient, error) {
httpClient, err := entity.Credentials.GetHTTPClient(ctx) httpClient, err := entity.Credentials.GetHTTPClient(ctx)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching http client") return nil, fmt.Errorf("error fetching http client: %w", err)
} }
slog.DebugContext( slog.DebugContext(
@ -590,7 +590,7 @@ func Client(ctx context.Context, entity params.ForgeEntity) (common.GithubClient
} }
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fetching github client") return nil, fmt.Errorf("error fetching github client: %w", err)
} }
cli := &githubClient{ cli := &githubClient{

View file

@ -16,11 +16,11 @@ package github
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"net/http" "net/http"
"github.com/google/go-github/v72/github" "github.com/google/go-github/v72/github"
"github.com/pkg/errors"
"github.com/cloudbase/garm/metrics" "github.com/cloudbase/garm/metrics"
"github.com/cloudbase/garm/params" "github.com/cloudbase/garm/params"

View file

@ -16,11 +16,10 @@ package util
import ( import (
"context" "context"
"fmt"
"net/http" "net/http"
"unicode/utf8" "unicode/utf8"
"github.com/pkg/errors"
runnerErrors "github.com/cloudbase/garm-provider-common/errors" runnerErrors "github.com/cloudbase/garm-provider-common/errors"
commonParams "github.com/cloudbase/garm-provider-common/params" commonParams "github.com/cloudbase/garm-provider-common/params"
"github.com/cloudbase/garm/runner/common" "github.com/cloudbase/garm/runner/common"
@ -30,9 +29,9 @@ func FetchTools(ctx context.Context, cli common.GithubClient) ([]commonParams.Ru
tools, ghResp, err := cli.ListEntityRunnerApplicationDownloads(ctx) tools, ghResp, err := cli.ListEntityRunnerApplicationDownloads(ctx)
if err != nil { if err != nil {
if ghResp != nil && ghResp.StatusCode == http.StatusUnauthorized { if ghResp != nil && ghResp.StatusCode == http.StatusUnauthorized {
return nil, errors.Wrap(runnerErrors.ErrUnauthorized, "fetching tools") return nil, fmt.Errorf("error fetching tools: %w", runnerErrors.ErrUnauthorized)
} }
return nil, errors.Wrap(err, "fetching runner tools") return nil, fmt.Errorf("error fetching runner tools: %w", err)
} }
ret := []commonParams.RunnerApplicationDownload{} ret := []commonParams.RunnerApplicationDownload{}

View file

@ -1 +0,0 @@
.vscode/

191
vendor/github.com/juju/clock/LICENSE generated vendored
View file

@ -1,191 +0,0 @@
All files in this repository are licensed as follows. If you contribute
to this repository, it is assumed that you license your contribution
under the same license unless you state otherwise.
All files Copyright (C) 2015 Canonical Ltd. unless otherwise specified in the file.
This software is licensed under the LGPLv3, included below.
As a special exception to the GNU Lesser General Public License version 3
("LGPL3"), the copyright holders of this Library give you permission to
convey to a third party a Combined Work that links statically or dynamically
to this Library without providing any Minimal Corresponding Source or
Minimal Application Code as set out in 4d or providing the installation
information set out in section 4e, provided that you comply with the other
provisions of LGPL3 and provided that you meet, for the Application the
terms and conditions of the license(s) which apply to the Application.
Except as stated in this special exception, the provisions of LGPL3 will
continue to comply in full to this Library. If you modify this Library, you
may apply this exception to your version of this Library, but you are not
obliged to do so. If you do not wish to do so, delete this exception
statement from your version. This exception does not (and cannot) modify any
license terms which apply to the Application, with which you must still
comply.
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

View file

@ -1,20 +0,0 @@
PROJECT := github.com/juju/clock
.PHONY: check-licence check-go check
check: check-licence check-go
go test $(PROJECT)/...
check-licence:
@(fgrep -rl "Licensed under the LGPLv3" --exclude *.s .;\
fgrep -rl "MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT" --exclude *.s .;\
find . -name "*.go") | sed -e 's,\./,,' | sort | uniq -u | \
xargs -I {} echo FAIL: licence missed: {}
check-go:
$(eval GOFMT := $(strip $(shell gofmt -l .| sed -e "s/^/ /g")))
@(if [ x$(GOFMT) != x"" ]; then \
echo go fmt is sad: $(GOFMT); \
exit 1; \
fi )
@(go vet -all -composites=false -copylocks=false .)

View file

@ -1,7 +0,0 @@
# clock
An interface definition for a fully defined clock.
An WallClock implementation of that interface using the time package.
A testing clock.

View file

@ -1,77 +0,0 @@
// Copyright 2015 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package clock
import "time"
// Clock provides an interface for dealing with clocks.
type Clock interface {
// Now returns the current clock time.
Now() time.Time
// After waits for the duration to elapse and then sends the
// current time on the returned channel.
After(time.Duration) <-chan time.Time
// AfterFunc waits for the duration to elapse and then calls f in its own goroutine.
// It returns a Timer that can be used to cancel the call using its Stop method.
AfterFunc(d time.Duration, f func()) Timer
// NewTimer creates a new Timer that will send the current time
// on its channel after at least duration d.
NewTimer(d time.Duration) Timer
// At waits for the time to pass and then sends the
// current time on the returned channel.
At(t time.Time) <-chan time.Time
// AtFunc waits for the time to pass and then calls f in its own goroutine.
// It returns an Alarm that can be used to cancel the call using its Stop method.
AtFunc(t time.Time, f func()) Alarm
// NewAlarm creates a new Alarm that will send the current time
// on its channel at or after time t has passed.
NewAlarm(t time.Time) Alarm
}
// Timer type represents a single event.
// Timers must be created with AfterFunc or NewTimer.
// This interface follows time.Timer's methods but provides easier mocking.
type Timer interface {
// When the timer expires, the current time will be sent on the
// channel returned from Chan, unless the timer was created by
// AfterFunc.
Chan() <-chan time.Time
// Reset changes the timer to expire after duration d.
// It returns true if the timer had been active, false if
// the timer had expired or been stopped.
Reset(d time.Duration) bool
// Stop prevents the Timer from firing. It returns true if
// the call stops the timer, false if the timer has already expired or been stopped.
// Stop does not close the channel, to prevent a read
// from the channel succeeding incorrectly.
Stop() bool
}
// Alarm type represents a single event.
// Alarms must be created with AtFunc or NewAlarm.
type Alarm interface {
// When the alarm expires, the current time will be sent on the
// channel returned from Chan, unless the alarm was created by
// AtFunc.
Chan() <-chan time.Time
// Reset changes the alarm to expire at or after time t.
// It returns true if the alarm had been active, false if
// the alarm had fired or been stopped.
Reset(t time.Time) bool
// Stop prevents the alarm from firing. It returns true if
// the call stops the alarm, false if the alarm has already fired or been stopped.
// Stop does not close the channel, to prevent a read
// from the channel succeeding incorrectly.
Stop() bool
}

77
vendor/github.com/juju/clock/wall.go generated vendored
View file

@ -1,77 +0,0 @@
// Copyright 2015 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package clock
import (
"time"
)
// WallClock exposes wall-clock time via the Clock interface.
var WallClock wallClock
// ensure that WallClock does actually implement the Clock interface.
var _ Clock = WallClock
// WallClock exposes wall-clock time as returned by time.Now.
type wallClock struct{}
// Now is part of the Clock interface.
func (wallClock) Now() time.Time {
return time.Now()
}
// After implements Clock.After.
func (wallClock) After(d time.Duration) <-chan time.Time {
return time.After(d)
}
// AfterFunc implements Clock.AfterFunc.
func (wallClock) AfterFunc(d time.Duration, f func()) Timer {
return wallTimer{time.AfterFunc(d, f)}
}
// NewTimer implements Clock.NewTimer.
func (wallClock) NewTimer(d time.Duration) Timer {
return wallTimer{time.NewTimer(d)}
}
// wallTimer implements the Timer interface.
type wallTimer struct {
*time.Timer
}
// Chan implements Timer.Chan.
func (t wallTimer) Chan() <-chan time.Time {
return t.C
}
// At implements Clock.At.
func (wallClock) At(t time.Time) <-chan time.Time {
return time.After(time.Until(t))
}
// AtFunc implements Clock.AtFunc.
func (wallClock) AtFunc(t time.Time, f func()) Alarm {
return wallAlarm{time.AfterFunc(time.Until(t), f)}
}
// NewAlarm implements Clock.NewAlarm.
func (wallClock) NewAlarm(t time.Time) Alarm {
return wallAlarm{time.NewTimer(time.Until(t))}
}
// wallAlarm implements the Alarm interface.
type wallAlarm struct {
*time.Timer
}
// Chan implements Alarm.Chan.
func (a wallAlarm) Chan() <-chan time.Time {
return a.C
}
// Reset implements Alarm.Reset
func (a wallAlarm) Reset(t time.Time) bool {
return a.Timer.Reset(time.Until(t))
}

View file

@ -1,23 +0,0 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test

191
vendor/github.com/juju/errors/LICENSE generated vendored
View file

@ -1,191 +0,0 @@
All files in this repository are licensed as follows. If you contribute
to this repository, it is assumed that you license your contribution
under the same license unless you state otherwise.
All files Copyright (C) 2015 Canonical Ltd. unless otherwise specified in the file.
This software is licensed under the LGPLv3, included below.
As a special exception to the GNU Lesser General Public License version 3
("LGPL3"), the copyright holders of this Library give you permission to
convey to a third party a Combined Work that links statically or dynamically
to this Library without providing any Minimal Corresponding Source or
Minimal Application Code as set out in 4d or providing the installation
information set out in section 4e, provided that you comply with the other
provisions of LGPL3 and provided that you meet, for the Application the
terms and conditions of the license(s) which apply to the Application.
Except as stated in this special exception, the provisions of LGPL3 will
continue to comply in full to this Library. If you modify this Library, you
may apply this exception to your version of this Library, but you are not
obliged to do so. If you do not wish to do so, delete this exception
statement from your version. This exception does not (and cannot) modify any
license terms which apply to the Application, with which you must still
comply.
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

View file

@ -1,24 +0,0 @@
PROJECT := github.com/juju/errors
.PHONY: check-licence check-go check docs
check: check-licence check-go
go test $(PROJECT)/...
check-licence:
@(fgrep -rl "Licensed under the LGPLv3" --exclude *.s .;\
fgrep -rl "MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT" --exclude *.s .;\
find . -name "*.go") | sed -e 's,\./,,' | sort | uniq -u | \
xargs -I {} echo FAIL: licence missed: {}
check-go:
$(eval GOFMT := $(strip $(shell gofmt -l .| sed -e "s/^/ /g")))
@(if [ x$(GOFMT) != x"" ]; then \
echo go fmt is sad: $(GOFMT); \
exit 1; \
fi )
@(go vet -all -composites=false -copylocks=false .)
docs:
godoc2md github.com/juju/errors > README.md
sed -i '5i[\[GoDoc](https://godoc.org/github.com/juju/errors?status.svg)](https://godoc.org/github.com/juju/errors)' README.md

View file

@ -1,707 +0,0 @@
# errors
import "github.com/juju/errors"
[![GoDoc](https://godoc.org/github.com/juju/errors?status.svg)](https://godoc.org/github.com/juju/errors)
The juju/errors provides an easy way to annotate errors without losing the
original error context.
The exported `New` and `Errorf` functions are designed to replace the
`errors.New` and `fmt.Errorf` functions respectively. The same underlying
error is there, but the package also records the location at which the error
was created.
A primary use case for this library is to add extra context any time an
error is returned from a function.
if err := SomeFunc(); err != nil {
return err
}
This instead becomes:
if err := SomeFunc(); err != nil {
return errors.Trace(err)
}
which just records the file and line number of the Trace call, or
if err := SomeFunc(); err != nil {
return errors.Annotate(err, "more context")
}
which also adds an annotation to the error.
When you want to check to see if an error is of a particular type, a helper
function is normally exported by the package that returned the error, like the
`os` package does. The underlying cause of the error is available using the
`Cause` function.
os.IsNotExist(errors.Cause(err))
The result of the `Error()` call on an annotated error is the annotations joined
with colons, then the result of the `Error()` method for the underlying error
that was the cause.
err := errors.Errorf("original")
err = errors.Annotatef(err, "context")
err = errors.Annotatef(err, "more context")
err.Error() -> "more context: context: original"
Obviously recording the file, line and functions is not very useful if you
cannot get them back out again.
errors.ErrorStack(err)
will return something like:
first error
github.com/juju/errors/annotation_test.go:193:
github.com/juju/errors/annotation_test.go:194: annotation
github.com/juju/errors/annotation_test.go:195:
github.com/juju/errors/annotation_test.go:196: more context
github.com/juju/errors/annotation_test.go:197:
The first error was generated by an external system, so there was no location
associated. The second, fourth, and last lines were generated with Trace calls,
and the other two through Annotate.
Sometimes when responding to an error you want to return a more specific error
for the situation.
if err := FindField(field); err != nil {
return errors.Wrap(err, errors.NotFoundf(field))
}
This returns an error where the complete error stack is still available, and
`errors.Cause()` will return the `NotFound` error.
## func AlreadyExistsf
``` go
func AlreadyExistsf(format string, args ...interface{}) error
```
AlreadyExistsf returns an error which satisfies IsAlreadyExists().
## func Annotate
``` go
func Annotate(other error, message string) error
```
Annotate is used to add extra context to an existing error. The location of
the Annotate call is recorded with the annotations. The file, line and
function are also recorded.
For example:
if err := SomeFunc(); err != nil {
return errors.Annotate(err, "failed to frombulate")
}
## func Annotatef
``` go
func Annotatef(other error, format string, args ...interface{}) error
```
Annotatef is used to add extra context to an existing error. The location of
the Annotate call is recorded with the annotations. The file, line and
function are also recorded.
For example:
if err := SomeFunc(); err != nil {
return errors.Annotatef(err, "failed to frombulate the %s", arg)
}
## func BadRequestf
``` go
func BadRequestf(format string, args ...interface{}) error
```
BadRequestf returns an error which satisfies IsBadRequest().
## func Cause
``` go
func Cause(err error) error
```
Cause returns the cause of the given error. This will be either the
original error, or the result of a Wrap or Mask call.
Cause is the usual way to diagnose errors that may have been wrapped by
the other errors functions.
## func DeferredAnnotatef
``` go
func DeferredAnnotatef(err *error, format string, args ...interface{})
```
DeferredAnnotatef annotates the given error (when it is not nil) with the given
format string and arguments (like fmt.Sprintf). If *err is nil, DeferredAnnotatef
does nothing. This method is used in a defer statement in order to annotate any
resulting error with the same message.
For example:
defer DeferredAnnotatef(&err, "failed to frombulate the %s", arg)
## func Details
``` go
func Details(err error) string
```
Details returns information about the stack of errors wrapped by err, in
the format:
[{filename:99: error one} {otherfile:55: cause of error one}]
This is a terse alternative to ErrorStack as it returns a single line.
## func ErrorStack
``` go
func ErrorStack(err error) string
```
ErrorStack returns a string representation of the annotated error. If the
error passed as the parameter is not an annotated error, the result is
simply the result of the Error() method on that error.
If the error is an annotated error, a multi-line string is returned where
each line represents one entry in the annotation stack. The full filename
from the call stack is used in the output.
first error
github.com/juju/errors/annotation_test.go:193:
github.com/juju/errors/annotation_test.go:194: annotation
github.com/juju/errors/annotation_test.go:195:
github.com/juju/errors/annotation_test.go:196: more context
github.com/juju/errors/annotation_test.go:197:
## func Errorf
``` go
func Errorf(format string, args ...interface{}) error
```
Errorf creates a new annotated error and records the location that the
error is created. This should be a drop in replacement for fmt.Errorf.
For example:
return errors.Errorf("validation failed: %s", message)
## func Forbiddenf
``` go
func Forbiddenf(format string, args ...interface{}) error
```
Forbiddenf returns an error which satistifes IsForbidden()
## func IsAlreadyExists
``` go
func IsAlreadyExists(err error) bool
```
IsAlreadyExists reports whether the error was created with
AlreadyExistsf() or NewAlreadyExists().
## func IsBadRequest
``` go
func IsBadRequest(err error) bool
```
IsBadRequest reports whether err was created with BadRequestf() or
NewBadRequest().
## func IsForbidden
``` go
func IsForbidden(err error) bool
```
IsForbidden reports whether err was created with Forbiddenf() or
NewForbidden().
## func IsMethodNotAllowed
``` go
func IsMethodNotAllowed(err error) bool
```
IsMethodNotAllowed reports whether err was created with MethodNotAllowedf() or
NewMethodNotAllowed().
## func IsNotAssigned
``` go
func IsNotAssigned(err error) bool
```
IsNotAssigned reports whether err was created with NotAssignedf() or
NewNotAssigned().
## func IsNotFound
``` go
func IsNotFound(err error) bool
```
IsNotFound reports whether err was created with NotFoundf() or
NewNotFound().
## func IsNotImplemented
``` go
func IsNotImplemented(err error) bool
```
IsNotImplemented reports whether err was created with
NotImplementedf() or NewNotImplemented().
## func IsNotProvisioned
``` go
func IsNotProvisioned(err error) bool
```
IsNotProvisioned reports whether err was created with NotProvisionedf() or
NewNotProvisioned().
## func IsNotSupported
``` go
func IsNotSupported(err error) bool
```
IsNotSupported reports whether the error was created with
NotSupportedf() or NewNotSupported().
## func IsNotValid
``` go
func IsNotValid(err error) bool
```
IsNotValid reports whether the error was created with NotValidf() or
NewNotValid().
## func IsUnauthorized
``` go
func IsUnauthorized(err error) bool
```
IsUnauthorized reports whether err was created with Unauthorizedf() or
NewUnauthorized().
## func IsUserNotFound
``` go
func IsUserNotFound(err error) bool
```
IsUserNotFound reports whether err was created with UserNotFoundf() or
NewUserNotFound().
## func Mask
``` go
func Mask(other error) error
```
Mask hides the underlying error type, and records the location of the masking.
## func Maskf
``` go
func Maskf(other error, format string, args ...interface{}) error
```
Mask masks the given error with the given format string and arguments (like
fmt.Sprintf), returning a new error that maintains the error stack, but
hides the underlying error type. The error string still contains the full
annotations. If you want to hide the annotations, call Wrap.
## func MethodNotAllowedf
``` go
func MethodNotAllowedf(format string, args ...interface{}) error
```
MethodNotAllowedf returns an error which satisfies IsMethodNotAllowed().
## func New
``` go
func New(message string) error
```
New is a drop in replacement for the standard library errors module that records
the location that the error is created.
For example:
return errors.New("validation failed")
## func NewAlreadyExists
``` go
func NewAlreadyExists(err error, msg string) error
```
NewAlreadyExists returns an error which wraps err and satisfies
IsAlreadyExists().
## func NewBadRequest
``` go
func NewBadRequest(err error, msg string) error
```
NewBadRequest returns an error which wraps err that satisfies
IsBadRequest().
## func NewForbidden
``` go
func NewForbidden(err error, msg string) error
```
NewForbidden returns an error which wraps err that satisfies
IsForbidden().
## func NewMethodNotAllowed
``` go
func NewMethodNotAllowed(err error, msg string) error
```
NewMethodNotAllowed returns an error which wraps err that satisfies
IsMethodNotAllowed().
## func NewNotAssigned
``` go
func NewNotAssigned(err error, msg string) error
```
NewNotAssigned returns an error which wraps err that satisfies
IsNotAssigned().
## func NewNotFound
``` go
func NewNotFound(err error, msg string) error
```
NewNotFound returns an error which wraps err that satisfies
IsNotFound().
## func NewNotImplemented
``` go
func NewNotImplemented(err error, msg string) error
```
NewNotImplemented returns an error which wraps err and satisfies
IsNotImplemented().
## func NewNotProvisioned
``` go
func NewNotProvisioned(err error, msg string) error
```
NewNotProvisioned returns an error which wraps err that satisfies
IsNotProvisioned().
## func NewNotSupported
``` go
func NewNotSupported(err error, msg string) error
```
NewNotSupported returns an error which wraps err and satisfies
IsNotSupported().
## func NewNotValid
``` go
func NewNotValid(err error, msg string) error
```
NewNotValid returns an error which wraps err and satisfies IsNotValid().
## func NewUnauthorized
``` go
func NewUnauthorized(err error, msg string) error
```
NewUnauthorized returns an error which wraps err and satisfies
IsUnauthorized().
## func NewUserNotFound
``` go
func NewUserNotFound(err error, msg string) error
```
NewUserNotFound returns an error which wraps err and satisfies
IsUserNotFound().
## func NotAssignedf
``` go
func NotAssignedf(format string, args ...interface{}) error
```
NotAssignedf returns an error which satisfies IsNotAssigned().
## func NotFoundf
``` go
func NotFoundf(format string, args ...interface{}) error
```
NotFoundf returns an error which satisfies IsNotFound().
## func NotImplementedf
``` go
func NotImplementedf(format string, args ...interface{}) error
```
NotImplementedf returns an error which satisfies IsNotImplemented().
## func NotProvisionedf
``` go
func NotProvisionedf(format string, args ...interface{}) error
```
NotProvisionedf returns an error which satisfies IsNotProvisioned().
## func NotSupportedf
``` go
func NotSupportedf(format string, args ...interface{}) error
```
NotSupportedf returns an error which satisfies IsNotSupported().
## func NotValidf
``` go
func NotValidf(format string, args ...interface{}) error
```
NotValidf returns an error which satisfies IsNotValid().
## func Trace
``` go
func Trace(other error) error
```
Trace adds the location of the Trace call to the stack. The Cause of the
resulting error is the same as the error parameter. If the other error is
nil, the result will be nil.
For example:
if err := SomeFunc(); err != nil {
return errors.Trace(err)
}
## func Unauthorizedf
``` go
func Unauthorizedf(format string, args ...interface{}) error
```
Unauthorizedf returns an error which satisfies IsUnauthorized().
## func UserNotFoundf
``` go
func UserNotFoundf(format string, args ...interface{}) error
```
UserNotFoundf returns an error which satisfies IsUserNotFound().
## func Wrap
``` go
func Wrap(other, newDescriptive error) error
```
Wrap changes the Cause of the error. The location of the Wrap call is also
stored in the error stack.
For example:
if err := SomeFunc(); err != nil {
newErr := &packageError{"more context", private_value}
return errors.Wrap(err, newErr)
}
## func Wrapf
``` go
func Wrapf(other, newDescriptive error, format string, args ...interface{}) error
```
Wrapf changes the Cause of the error, and adds an annotation. The location
of the Wrap call is also stored in the error stack.
For example:
if err := SomeFunc(); err != nil {
return errors.Wrapf(err, simpleErrorType, "invalid value %q", value)
}
## type Err
``` go
type Err struct {
// contains filtered or unexported fields
}
```
Err holds a description of an error along with information about
where the error was created.
It may be embedded in custom error types to add extra information that
this errors package can understand.
### func NewErr
``` go
func NewErr(format string, args ...interface{}) Err
```
NewErr is used to return an Err for the purpose of embedding in other
structures. The location is not specified, and needs to be set with a call
to SetLocation.
For example:
type FooError struct {
errors.Err
code int
}
func NewFooError(code int) error {
err := &FooError{errors.NewErr("foo"), code}
err.SetLocation(1)
return err
}
### func NewErrWithCause
``` go
func NewErrWithCause(other error, format string, args ...interface{}) Err
```
NewErrWithCause is used to return an Err with cause by other error for the purpose of embedding in other
structures. The location is not specified, and needs to be set with a call
to SetLocation.
For example:
type FooError struct {
errors.Err
code int
}
func (e *FooError) Annotate(format string, args ...interface{}) error {
err := &FooError{errors.NewErrWithCause(e.Err, format, args...), e.code}
err.SetLocation(1)
return err
})
### func (\*Err) Cause
``` go
func (e *Err) Cause() error
```
The Cause of an error is the most recent error in the error stack that
meets one of these criteria: the original error that was raised; the new
error that was passed into the Wrap function; the most recently masked
error; or nil if the error itself is considered the Cause. Normally this
method is not invoked directly, but instead through the Cause stand alone
function.
### func (\*Err) Error
``` go
func (e *Err) Error() string
```
Error implements error.Error.
### func (\*Err) Format
``` go
func (e *Err) Format(s fmt.State, verb rune)
```
Format implements fmt.Formatter
When printing errors with %+v it also prints the stack trace.
%#v unsurprisingly will print the real underlying type.
### func (\*Err) Location
``` go
func (e *Err) Location() (filename string, line int)
```
Location is the file and line of where the error was most recently
created or annotated.
### func (\*Err) Message
``` go
func (e *Err) Message() string
```
Message returns the message stored with the most recent location. This is
the empty string if the most recent call was Trace, or the message stored
with Annotate or Mask.
### func (\*Err) SetLocation
``` go
func (e *Err) SetLocation(callDepth int)
```
SetLocation records the source location of the error at callDepth stack
frames above the call.
### func (\*Err) StackTrace
``` go
func (e *Err) StackTrace() []string
```
StackTrace returns one string for each location recorded in the stack of
errors. The first value is the originating error, with a line for each
other annotation or tracing of the error.
### func (\*Err) Underlying
``` go
func (e *Err) Underlying() error
```
Underlying returns the previous error in the error stack, if any. A client
should not ever really call this method. It is used to build the error
stack and should not be introspected by client calls. Or more
specifically, clients should not depend on anything but the `Cause` of an
error.
- - -
Generated by [godoc2md](http://godoc.org/github.com/davecheney/godoc2md)

79
vendor/github.com/juju/errors/doc.go generated vendored
View file

@ -1,79 +0,0 @@
// Copyright 2013, 2014 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
/*
Package errors provides an easy way to annotate errors without losing the
original error context.
The exported `New` and `Errorf` functions are designed to replace the
`errors.New` and `fmt.Errorf` functions respectively. The same underlying
error is there, but the package also records the location at which the error
was created.
A primary use case for this library is to add extra context any time an
error is returned from a function.
if err := SomeFunc(); err != nil {
return err
}
This instead becomes:
if err := SomeFunc(); err != nil {
return errors.Trace(err)
}
which just records the file and line number of the Trace call, or
if err := SomeFunc(); err != nil {
return errors.Annotate(err, "more context")
}
which also adds an annotation to the error.
When you want to check to see if an error is of a particular type, a helper
function is normally exported by the package that returned the error, like the
`os` package does. The underlying cause of the error is available using the
`Cause` function.
os.IsNotExist(errors.Cause(err))
The result of the `Error()` call on an annotated error is the annotations joined
with colons, then the result of the `Error()` method for the underlying error
that was the cause.
err := errors.Errorf("original")
err = errors.Annotatef(err, "context")
err = errors.Annotatef(err, "more context")
err.Error() -> "more context: context: original"
Obviously recording the file, line and functions is not very useful if you
cannot get them back out again.
errors.ErrorStack(err)
will return something like:
first error
github.com/juju/errors/annotation_test.go:193:
github.com/juju/errors/annotation_test.go:194: annotation
github.com/juju/errors/annotation_test.go:195:
github.com/juju/errors/annotation_test.go:196: more context
github.com/juju/errors/annotation_test.go:197:
The first error was generated by an external system, so there was no location
associated. The second, fourth, and last lines were generated with Trace calls,
and the other two through Annotate.
Sometimes when responding to an error you want to return a more specific error
for the situation.
if err := FindField(field); err != nil {
return errors.Wrap(err, errors.NotFoundf(field))
}
This returns an error where the complete error stack is still available, and
`errors.Cause()` will return the `NotFound` error.
*/
package errors

View file

@ -1,227 +0,0 @@
// Copyright 2014 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package errors
import (
"fmt"
"reflect"
)
// Err holds a description of an error along with information about
// where the error was created.
//
// It may be embedded in custom error types to add extra information that
// this errors package can understand.
type Err struct {
// message holds an annotation of the error.
message string
// cause holds the cause of the error as returned
// by the Cause method.
cause error
// previous holds the previous error in the error stack, if any.
previous error
// function is the package path-qualified function name where the
// error was created.
function string
// line is the line number the error was created on inside of function
line int
}
// Locationer is an interface that represents a certain class of errors that
// contain the location information from where they were raised.
type Locationer interface {
// Location returns the path-qualified function name where the error was
// created and the line number
Location() (function string, line int)
}
// locationError is the internal implementation of the Locationer interface.
type locationError struct {
error
// function is the package path-qualified function name where the
// error was created.
function string
// line is the line number the error was created on inside of function
line int
}
// newLocationError constructs a new Locationer error from the supplied error
// with the location set to callDepth in the stack. If a nill error is provided
// to this function then a new empty error is constructed.
func newLocationError(err error, callDepth int) *locationError {
le := &locationError{error: err}
le.function, le.line = getLocation(callDepth + 1)
return le
}
// Error implementes the error interface.
func (l *locationError) Error() string {
if l.error == nil {
return ""
}
return l.error.Error()
}
// *locationError implements Locationer.Location interface
func (l *locationError) Location() (string, int) {
return l.function, l.line
}
func (l *locationError) Unwrap() error {
return l.error
}
// NewErr is used to return an Err for the purpose of embedding in other
// structures. The location is not specified, and needs to be set with a call
// to SetLocation.
//
// For example:
// type FooError struct {
// errors.Err
// code int
// }
//
// func NewFooError(code int) error {
// err := &FooError{errors.NewErr("foo"), code}
// err.SetLocation(1)
// return err
// }
func NewErr(format string, args ...interface{}) Err {
return Err{
message: fmt.Sprintf(format, args...),
}
}
// NewErrWithCause is used to return an Err with cause by other error for the purpose of embedding in other
// structures. The location is not specified, and needs to be set with a call
// to SetLocation.
//
// For example:
// type FooError struct {
// errors.Err
// code int
// }
//
// func (e *FooError) Annotate(format string, args ...interface{}) error {
// err := &FooError{errors.NewErrWithCause(e.Err, format, args...), e.code}
// err.SetLocation(1)
// return err
// })
func NewErrWithCause(other error, format string, args ...interface{}) Err {
return Err{
message: fmt.Sprintf(format, args...),
cause: Cause(other),
previous: other,
}
}
// Location returns the package path-qualified function name and line of where
// the error was most recently created or annotated.
func (e *Err) Location() (function string, line int) {
return e.function, e.line
}
// Underlying returns the previous error in the error stack, if any. A client
// should not ever really call this method. It is used to build the error
// stack and should not be introspected by client calls. Or more
// specifically, clients should not depend on anything but the `Cause` of an
// error.
func (e *Err) Underlying() error {
return e.previous
}
// Cause returns the most recent error in the error stack that
// meets one of these criteria: the original error that was raised; the new
// error that was passed into the Wrap function; the most recently masked
// error; or nil if the error itself is considered the Cause. Normally this
// method is not invoked directly, but instead through the Cause stand alone
// function.
func (e *Err) Cause() error {
return e.cause
}
// Message returns the message stored with the most recent location. This is
// the empty string if the most recent call was Trace, or the message stored
// with Annotate or Mask.
func (e *Err) Message() string {
return e.message
}
// Error implements error.Error.
func (e *Err) Error() string {
// We want to walk up the stack of errors showing the annotations
// as long as the cause is the same.
err := e.previous
if !sameError(Cause(err), e.cause) && e.cause != nil {
err = e.cause
}
switch {
case err == nil:
return e.message
case e.message == "":
return err.Error()
}
return fmt.Sprintf("%s: %v", e.message, err)
}
// Format implements fmt.Formatter
// When printing errors with %+v it also prints the stack trace.
// %#v unsurprisingly will print the real underlying type.
func (e *Err) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
switch {
case s.Flag('+'):
fmt.Fprintf(s, "%s", ErrorStack(e))
return
case s.Flag('#'):
// avoid infinite recursion by wrapping e into a type
// that doesn't implement Formatter.
fmt.Fprintf(s, "%#v", (*unformatter)(e))
return
}
fallthrough
case 's':
fmt.Fprintf(s, "%s", e.Error())
case 'q':
fmt.Fprintf(s, "%q", e.Error())
default:
fmt.Fprintf(s, "%%!%c(%T=%s)", verb, e, e.Error())
}
}
// helper for Format
type unformatter Err
func (unformatter) Format() { /* break the fmt.Formatter interface */ }
// SetLocation records the package path-qualified function name of the error at
// callDepth stack frames above the call.
func (e *Err) SetLocation(callDepth int) {
e.function, e.line = getLocation(callDepth + 1)
}
// StackTrace returns one string for each location recorded in the stack of
// errors. The first value is the originating error, with a line for each
// other annotation or tracing of the error.
func (e *Err) StackTrace() []string {
return errorStack(e)
}
// Ideally we'd have a way to check identity, but deep equals will do.
func sameError(e1, e2 error) bool {
return reflect.DeepEqual(e1, e2)
}
// Unwrap is a synonym for Underlying, which allows Err to be used with the
// Unwrap, Is and As functions in Go's standard `errors` library.
func (e *Err) Unwrap() error {
return e.previous
}

View file

@ -1,473 +0,0 @@
// Copyright 2014 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package errors
import (
"errors"
stderror "errors"
"fmt"
"strings"
)
// a ConstError is a prototype for a certain type of error
type ConstError string
// ConstError implements error
func (e ConstError) Error() string {
return string(e)
}
// Different types of errors
const (
// Timeout represents an error on timeout.
Timeout = ConstError("timeout")
// NotFound represents an error when something has not been found.
NotFound = ConstError("not found")
// UserNotFound represents an error when a non-existent user is looked up.
UserNotFound = ConstError("user not found")
// Unauthorized represents an error when an operation is unauthorized.
Unauthorized = ConstError("unauthorized")
// NotImplemented represents an error when something is not
// implemented.
NotImplemented = ConstError("not implemented")
// AlreadyExists represents and error when something already exists.
AlreadyExists = ConstError("already exists")
// NotSupported represents an error when something is not supported.
NotSupported = ConstError("not supported")
// NotValid represents an error when something is not valid.
NotValid = ConstError("not valid")
// NotProvisioned represents an error when something is not yet provisioned.
NotProvisioned = ConstError("not provisioned")
// NotAssigned represents an error when something is not yet assigned to
// something else.
NotAssigned = ConstError("not assigned")
// BadRequest represents an error when a request has bad parameters.
BadRequest = ConstError("bad request")
// MethodNotAllowed represents an error when an HTTP request
// is made with an inappropriate method.
MethodNotAllowed = ConstError("method not allowed")
// Forbidden represents an error when a request cannot be completed because of
// missing privileges.
Forbidden = ConstError("forbidden")
// QuotaLimitExceeded is emitted when an action failed due to a quota limit check.
QuotaLimitExceeded = ConstError("quota limit exceeded")
// NotYetAvailable is the error returned when a resource is not yet available
// but it might be in the future.
NotYetAvailable = ConstError("not yet available")
)
// errWithType is an Err bundled with its error type (a ConstError)
type errWithType struct {
error
errType ConstError
}
// Is compares `target` with e's error type
func (e *errWithType) Is(target error) bool {
if &e.errType == nil {
return false
}
return target == e.errType
}
// Unwrap an errWithType gives the underlying Err
func (e *errWithType) Unwrap() error {
return e.error
}
func wrapErrorWithMsg(err error, msg string) error {
if err == nil {
return stderror.New(msg)
}
if msg == "" {
return err
}
return fmt.Errorf("%s: %w", msg, err)
}
func makeWrappedConstError(err error, format string, args ...interface{}) error {
separator := " "
if err.Error() == "" || errors.Is(err, &fmtNoop{}) {
separator = ""
}
return fmt.Errorf(strings.Join([]string{format, "%w"}, separator), append(args, err)...)
}
// WithType is responsible for annotating an already existing error so that it
// also satisfies that of a ConstError. The resultant error returned should
// satisfy Is(err, errType). If err is nil then a nil error will also be returned.
//
// Now with Go's Is, As and Unwrap support it no longer makes sense to Wrap()
// 2 errors as both of those errors could be chains of errors in their own right.
// WithType aims to solve some of the usefulness of Wrap with the ability to
// make a pre-existing error also satisfy a ConstError type.
func WithType(err error, errType ConstError) error {
if err == nil {
return nil
}
return &errWithType{
error: err,
errType: errType,
}
}
// Timeoutf returns an error which satisfies Is(err, Timeout) and the Locationer
// interface.
func Timeoutf(format string, args ...interface{}) error {
return newLocationError(
makeWrappedConstError(Timeout, format, args...),
1,
)
}
// NewTimeout returns an error which wraps err and satisfies Is(err, Timeout)
// and the Locationer interface.
func NewTimeout(err error, msg string) error {
return &errWithType{
error: newLocationError(wrapErrorWithMsg(err, msg), 1),
errType: Timeout,
}
}
// Deprecated: IsTimeout reports whether err is a Timeout error. Use
// Is(err, Timeout).
func IsTimeout(err error) bool {
return Is(err, Timeout)
}
// NotFoundf returns an error which satisfies Is(err, NotFound) and the
// Locationer interface.
func NotFoundf(format string, args ...interface{}) error {
return newLocationError(
makeWrappedConstError(NotFound, format, args...),
1,
)
}
// NewNotFound returns an error which wraps err and satisfies Is(err, NotFound)
// and the Locationer interface.
func NewNotFound(err error, msg string) error {
return &errWithType{
error: newLocationError(wrapErrorWithMsg(err, msg), 1),
errType: NotFound,
}
}
// Deprecated: IsNotFound reports whether err is a NotFound error. Use
// Is(err, NotFound).
func IsNotFound(err error) bool {
return Is(err, NotFound)
}
// UserNotFoundf returns an error which satisfies Is(err, UserNotFound) and the
// Locationer interface.
func UserNotFoundf(format string, args ...interface{}) error {
return newLocationError(
makeWrappedConstError(UserNotFound, format, args...),
1,
)
}
// NewUserNotFound returns an error which wraps err and satisfies
// Is(err, UserNotFound) and the Locationer interface.
func NewUserNotFound(err error, msg string) error {
return &errWithType{
error: newLocationError(wrapErrorWithMsg(err, msg), 1),
errType: UserNotFound,
}
}
// Deprecated: IsUserNotFound reports whether err is a UserNotFound error. Use
// Is(err, UserNotFound).
func IsUserNotFound(err error) bool {
return Is(err, UserNotFound)
}
// Unauthorizedf returns an error that satisfies Is(err, Unauthorized) and
// the Locationer interface.
func Unauthorizedf(format string, args ...interface{}) error {
return newLocationError(
makeWrappedConstError(Hide(Unauthorized), format, args...),
1,
)
}
// NewUnauthorized returns an error which wraps err and satisfies
// Is(err, Unathorized) and the Locationer interface.
func NewUnauthorized(err error, msg string) error {
return &errWithType{
error: newLocationError(wrapErrorWithMsg(err, msg), 1),
errType: Unauthorized,
}
}
// Deprecated: IsUnauthorized reports whether err is a Unauthorized error. Use
// Is(err, Unauthorized).
func IsUnauthorized(err error) bool {
return Is(err, Unauthorized)
}
// NotImplementedf returns an error which satisfies Is(err, NotImplemented) and
// the Locationer interface.
func NotImplementedf(format string, args ...interface{}) error {
return newLocationError(
makeWrappedConstError(NotImplemented, format, args...),
1,
)
}
// NewNotImplemented returns an error which wraps err and satisfies
// Is(err, NotImplemented) and the Locationer interface.
func NewNotImplemented(err error, msg string) error {
return &errWithType{
error: newLocationError(wrapErrorWithMsg(err, msg), 1),
errType: NotImplemented,
}
}
// Deprecated: IsNotImplemented reports whether err is a NotImplemented error.
// Use Is(err, NotImplemented).
func IsNotImplemented(err error) bool {
return Is(err, NotImplemented)
}
// AlreadyExistsf returns an error which satisfies Is(err, AlreadyExists) and
// the Locationer interface.
func AlreadyExistsf(format string, args ...interface{}) error {
return newLocationError(
makeWrappedConstError(AlreadyExists, format, args...),
1,
)
}
// NewAlreadyExists returns an error which wraps err and satisfies
// Is(err, AlreadyExists) and the Locationer interface.
func NewAlreadyExists(err error, msg string) error {
return &errWithType{
error: newLocationError(wrapErrorWithMsg(err, msg), 1),
errType: AlreadyExists,
}
}
// Deprecated: IsAlreadyExists reports whether the err is a AlreadyExists
// error. Use Is(err, AlreadyExists).
func IsAlreadyExists(err error) bool {
return Is(err, AlreadyExists)
}
// NotSupportedf returns an error which satisfies Is(err, NotSupported) and the
// Locationer interface.
func NotSupportedf(format string, args ...interface{}) error {
return newLocationError(
makeWrappedConstError(NotSupported, format, args...),
1,
)
}
// NewNotSupported returns an error which satisfies Is(err, NotSupported) and
// the Locationer interface.
func NewNotSupported(err error, msg string) error {
return &errWithType{
error: newLocationError(wrapErrorWithMsg(err, msg), 1),
errType: NotSupported,
}
}
// Deprecated: IsNotSupported reports whether err is a NotSupported error. Use
// Is(err, NotSupported).
func IsNotSupported(err error) bool {
return Is(err, NotSupported)
}
// NotValidf returns an error which satisfies Is(err, NotValid) and the
// Locationer interface.
func NotValidf(format string, args ...interface{}) error {
return newLocationError(
makeWrappedConstError(NotValid, format, args...),
1,
)
}
// NewNotValid returns an error which wraps err and satisfies Is(err, NotValid)
// and the Locationer interface.
func NewNotValid(err error, msg string) error {
return &errWithType{
error: newLocationError(wrapErrorWithMsg(err, msg), 1),
errType: NotValid,
}
}
// Deprecated: IsNotValid reports whether err is a NotValid error. Use
// Is(err, NotValid).
func IsNotValid(err error) bool {
return Is(err, NotValid)
}
// NotProvisionedf returns an error which satisfies Is(err, NotProvisioned) and
// the Locationer interface.
func NotProvisionedf(format string, args ...interface{}) error {
return newLocationError(
makeWrappedConstError(NotProvisioned, format, args...),
1,
)
}
// NewNotProvisioned returns an error which wraps err and satisfies
// Is(err, NotProvisioned) and the Locationer interface.
func NewNotProvisioned(err error, msg string) error {
return &errWithType{
error: newLocationError(wrapErrorWithMsg(err, msg), 1),
errType: NotProvisioned,
}
}
// Deprecated: IsNotProvisioned reports whether err is a NotProvisioned error.
// Use Is(err, NotProvisioned).
func IsNotProvisioned(err error) bool {
return Is(err, NotProvisioned)
}
// NotAssignedf returns an error which satisfies Is(err, NotAssigned) and the
// Locationer interface.
func NotAssignedf(format string, args ...interface{}) error {
return newLocationError(
makeWrappedConstError(NotAssigned, format, args...),
1,
)
}
// NewNotAssigned returns an error which wraps err and satisfies
// Is(err, NotAssigned) and the Locationer interface.
func NewNotAssigned(err error, msg string) error {
return &errWithType{
error: newLocationError(wrapErrorWithMsg(err, msg), 1),
errType: NotAssigned,
}
}
// Deprecated: IsNotAssigned reports whether err is a NotAssigned error.
// Use Is(err, NotAssigned)
func IsNotAssigned(err error) bool {
return Is(err, NotAssigned)
}
// BadRequestf returns an error which satisfies Is(err, BadRequest) and the
// Locationer interface.
func BadRequestf(format string, args ...interface{}) error {
return newLocationError(
makeWrappedConstError(Hide(BadRequest), format, args...),
1,
)
}
// NewBadRequest returns an error which wraps err and satisfies
// Is(err, BadRequest) and the Locationer interface.
func NewBadRequest(err error, msg string) error {
return &errWithType{
error: newLocationError(wrapErrorWithMsg(err, msg), 1),
errType: BadRequest,
}
}
// Deprecated: IsBadRequest reports whether err is a BadRequest error.
// Use Is(err, BadRequest)
func IsBadRequest(err error) bool {
return Is(err, BadRequest)
}
// MethodNotAllowedf returns an error which satisfies Is(err, MethodNotAllowed)
// and the Locationer interface.
func MethodNotAllowedf(format string, args ...interface{}) error {
return newLocationError(
makeWrappedConstError(Hide(MethodNotAllowed), format, args...),
1,
)
}
// NewMethodNotAllowed returns an error which wraps err and satisfies
// Is(err, MethodNotAllowed) and the Locationer interface.
func NewMethodNotAllowed(err error, msg string) error {
return &errWithType{
error: newLocationError(wrapErrorWithMsg(err, msg), 1),
errType: MethodNotAllowed,
}
}
// Deprecated: IsMethodNotAllowed reports whether err is a MethodNotAllowed
// error. Use Is(err, MethodNotAllowed)
func IsMethodNotAllowed(err error) bool {
return Is(err, MethodNotAllowed)
}
// Forbiddenf returns an error which satistifes Is(err, Forbidden) and the
// Locationer interface.
func Forbiddenf(format string, args ...interface{}) error {
return newLocationError(
makeWrappedConstError(Hide(Forbidden), format, args...),
1,
)
}
// NewForbidden returns an error which wraps err and satisfies
// Is(err, Forbidden) and the Locationer interface.
func NewForbidden(err error, msg string) error {
return &errWithType{
error: newLocationError(wrapErrorWithMsg(err, msg), 1),
errType: Forbidden,
}
}
// Deprecated: IsForbidden reports whether err is a Forbidden error. Use
// Is(err, Forbidden).
func IsForbidden(err error) bool {
return Is(err, Forbidden)
}
// QuotaLimitExceededf returns an error which satisfies
// Is(err, QuotaLimitExceeded) and the Locationer interface.
func QuotaLimitExceededf(format string, args ...interface{}) error {
return newLocationError(
makeWrappedConstError(Hide(QuotaLimitExceeded), format, args...),
1,
)
}
// NewQuotaLimitExceeded returns an error which wraps err and satisfies
// Is(err, QuotaLimitExceeded) and the Locationer interface.
func NewQuotaLimitExceeded(err error, msg string) error {
return &errWithType{
error: newLocationError(wrapErrorWithMsg(err, msg), 1),
errType: QuotaLimitExceeded,
}
}
// Deprecated: IsQuotaLimitExceeded reports whether err is a QuoteLimitExceeded
// err. Use Is(err, QuotaLimitExceeded).
func IsQuotaLimitExceeded(err error) bool {
return Is(err, QuotaLimitExceeded)
}
// NotYetAvailablef returns an error which satisfies Is(err, NotYetAvailable)
// and the Locationer interface.
func NotYetAvailablef(format string, args ...interface{}) error {
return newLocationError(
makeWrappedConstError(Hide(NotYetAvailable), format, args...),
1,
)
}
// NewNotYetAvailable returns an error which wraps err and satisfies
// Is(err, NotYetAvailable) and the Locationer interface.
func NewNotYetAvailable(err error, msg string) error {
return &errWithType{
error: newLocationError(wrapErrorWithMsg(err, msg), 1),
errType: NotYetAvailable,
}
}
// Deprecated: IsNotYetAvailable reports whether err is a NotYetAvailable err.
// Use Is(err, NotYetAvailable)
func IsNotYetAvailable(err error) bool {
return Is(err, NotYetAvailable)
}

View file

@ -1,454 +0,0 @@
// Copyright 2014 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package errors
import (
stderrors "errors"
"fmt"
"runtime"
"strings"
)
// New is a drop in replacement for the standard library errors module that records
// the location that the error is created.
//
// For example:
// return errors.New("validation failed")
//
func New(message string) error {
err := &Err{message: message}
err.SetLocation(1)
return err
}
// Errorf creates a new annotated error and records the location that the
// error is created. This should be a drop in replacement for fmt.Errorf.
//
// For example:
// return errors.Errorf("validation failed: %s", message)
//
func Errorf(format string, args ...interface{}) error {
err := &Err{message: fmt.Sprintf(format, args...)}
err.SetLocation(1)
return err
}
// getLocation records the package path-qualified function name of the error at
// callDepth stack frames above the call.
func getLocation(callDepth int) (string, int) {
rpc := make([]uintptr, 1)
n := runtime.Callers(callDepth+2, rpc[:])
if n < 1 {
return "", 0
}
frame, _ := runtime.CallersFrames(rpc).Next()
return frame.Function, frame.Line
}
// Trace adds the location of the Trace call to the stack. The Cause of the
// resulting error is the same as the error parameter. If the other error is
// nil, the result will be nil.
//
// For example:
// if err := SomeFunc(); err != nil {
// return errors.Trace(err)
// }
//
func Trace(other error) error {
//return SetLocation(other, 2)
if other == nil {
return nil
}
err := &Err{previous: other, cause: Cause(other)}
err.SetLocation(1)
return err
}
// Annotate is used to add extra context to an existing error. The location of
// the Annotate call is recorded with the annotations. The file, line and
// function are also recorded.
//
// For example:
// if err := SomeFunc(); err != nil {
// return errors.Annotate(err, "failed to frombulate")
// }
//
func Annotate(other error, message string) error {
if other == nil {
return nil
}
err := &Err{
previous: other,
cause: Cause(other),
message: message,
}
err.SetLocation(1)
return err
}
// Annotatef is used to add extra context to an existing error. The location of
// the Annotate call is recorded with the annotations. The file, line and
// function are also recorded.
//
// For example:
// if err := SomeFunc(); err != nil {
// return errors.Annotatef(err, "failed to frombulate the %s", arg)
// }
//
func Annotatef(other error, format string, args ...interface{}) error {
if other == nil {
return nil
}
err := &Err{
previous: other,
cause: Cause(other),
message: fmt.Sprintf(format, args...),
}
err.SetLocation(1)
return err
}
// DeferredAnnotatef annotates the given error (when it is not nil) with the given
// format string and arguments (like fmt.Sprintf). If *err is nil, DeferredAnnotatef
// does nothing. This method is used in a defer statement in order to annotate any
// resulting error with the same message.
//
// For example:
//
// defer DeferredAnnotatef(&err, "failed to frombulate the %s", arg)
//
func DeferredAnnotatef(err *error, format string, args ...interface{}) {
if *err == nil {
return
}
newErr := &Err{
message: fmt.Sprintf(format, args...),
cause: Cause(*err),
previous: *err,
}
newErr.SetLocation(1)
*err = newErr
}
// Wrap changes the Cause of the error. The location of the Wrap call is also
// stored in the error stack.
//
// For example:
// if err := SomeFunc(); err != nil {
// newErr := &packageError{"more context", private_value}
// return errors.Wrap(err, newErr)
// }
//
func Wrap(other, newDescriptive error) error {
err := &Err{
previous: other,
cause: newDescriptive,
}
err.SetLocation(1)
return err
}
// Wrapf changes the Cause of the error, and adds an annotation. The location
// of the Wrap call is also stored in the error stack.
//
// For example:
// if err := SomeFunc(); err != nil {
// return errors.Wrapf(err, simpleErrorType, "invalid value %q", value)
// }
//
func Wrapf(other, newDescriptive error, format string, args ...interface{}) error {
err := &Err{
message: fmt.Sprintf(format, args...),
previous: other,
cause: newDescriptive,
}
err.SetLocation(1)
return err
}
// Maskf masks the given error with the given format string and arguments (like
// fmt.Sprintf), returning a new error that maintains the error stack, but
// hides the underlying error type. The error string still contains the full
// annotations. If you want to hide the annotations, call Wrap.
func Maskf(other error, format string, args ...interface{}) error {
if other == nil {
return nil
}
err := &Err{
message: fmt.Sprintf(format, args...),
previous: other,
}
err.SetLocation(1)
return err
}
// Mask hides the underlying error type, and records the location of the masking.
func Mask(other error) error {
if other == nil {
return nil
}
err := &Err{
previous: other,
}
err.SetLocation(1)
return err
}
// Cause returns the cause of the given error. This will be either the
// original error, or the result of a Wrap or Mask call.
//
// Cause is the usual way to diagnose errors that may have been wrapped by
// the other errors functions.
func Cause(err error) error {
var diag error
if err, ok := err.(causer); ok {
diag = err.Cause()
}
if diag != nil {
return diag
}
return err
}
type causer interface {
Cause() error
}
type wrapper interface {
// Message returns the top level error message,
// not including the message from the Previous
// error.
Message() string
// Underlying returns the Previous error, or nil
// if there is none.
Underlying() error
}
var (
_ wrapper = (*Err)(nil)
_ Locationer = (*Err)(nil)
_ causer = (*Err)(nil)
)
// Details returns information about the stack of errors wrapped by err, in
// the format:
//
// [{filename:99: error one} {otherfile:55: cause of error one}]
//
// This is a terse alternative to ErrorStack as it returns a single line.
func Details(err error) string {
if err == nil {
return "[]"
}
var s []byte
s = append(s, '[')
for {
s = append(s, '{')
if err, ok := err.(Locationer); ok {
file, line := err.Location()
if file != "" {
s = append(s, fmt.Sprintf("%s:%d", file, line)...)
s = append(s, ": "...)
}
}
if cerr, ok := err.(wrapper); ok {
s = append(s, cerr.Message()...)
err = cerr.Underlying()
} else {
s = append(s, err.Error()...)
err = nil
}
s = append(s, '}')
if err == nil {
break
}
s = append(s, ' ')
}
s = append(s, ']')
return string(s)
}
// ErrorStack returns a string representation of the annotated error. If the
// error passed as the parameter is not an annotated error, the result is
// simply the result of the Error() method on that error.
//
// If the error is an annotated error, a multi-line string is returned where
// each line represents one entry in the annotation stack. The full filename
// from the call stack is used in the output.
//
// first error
// github.com/juju/errors/annotation_test.go:193:
// github.com/juju/errors/annotation_test.go:194: annotation
// github.com/juju/errors/annotation_test.go:195:
// github.com/juju/errors/annotation_test.go:196: more context
// github.com/juju/errors/annotation_test.go:197:
func ErrorStack(err error) string {
return strings.Join(errorStack(err), "\n")
}
func errorStack(err error) []string {
if err == nil {
return nil
}
// We want the first error first
var lines []string
for {
var buff []byte
if err, ok := err.(Locationer); ok {
file, line := err.Location()
// Strip off the leading GOPATH/src path elements.
if file != "" {
buff = append(buff, fmt.Sprintf("%s:%d", file, line)...)
buff = append(buff, ": "...)
}
}
if cerr, ok := err.(wrapper); ok {
message := cerr.Message()
buff = append(buff, message...)
// If there is a cause for this error, and it is different to the cause
// of the underlying error, then output the error string in the stack trace.
var cause error
if err1, ok := err.(causer); ok {
cause = err1.Cause()
}
err = cerr.Underlying()
if cause != nil && !sameError(Cause(err), cause) {
if message != "" {
buff = append(buff, ": "...)
}
buff = append(buff, cause.Error()...)
}
} else {
buff = append(buff, err.Error()...)
err = nil
}
lines = append(lines, string(buff))
if err == nil {
break
}
}
// reverse the lines to get the original error, which was at the end of
// the list, back to the start.
var result []string
for i := len(lines); i > 0; i-- {
result = append(result, lines[i-1])
}
return result
}
// Unwrap is a proxy for the Unwrap function in Go's standard `errors` library
// (pkg.go.dev/errors).
func Unwrap(err error) error {
return stderrors.Unwrap(err)
}
// Is is a proxy for the Is function in Go's standard `errors` library
// (pkg.go.dev/errors).
func Is(err, target error) bool {
return stderrors.Is(err, target)
}
// HasType is a function wrapper around AsType dropping the where return value
// from AsType() making a function that can be used like this:
//
// return HasType[*MyError](err)
//
// Or
//
// if HasType[*MyError](err) {}
func HasType[T error](err error) bool {
_, rval := AsType[T](err)
return rval
}
// As is a proxy for the As function in Go's standard `errors` library
// (pkg.go.dev/errors).
func As(err error, target interface{}) bool {
return stderrors.As(err, target)
}
// AsType is a convenience method for checking and getting an error from within
// a chain that is of type T. If no error is found of type T in the chain the
// zero value of T is returned with false. If an error in the chain implementes
// As(any) bool then it's As method will be called if it's type is not of type T.
// AsType finds the first error in err's chain that is assignable to type T, and
// if a match is found, returns that error value and true. Otherwise, it returns
// T's zero value and false.
//
// AsType is equivalent to errors.As, but uses a type parameter and returns
// the target, to avoid having to define a variable before the call. For
// example, callers can replace this:
//
// var pathError *fs.PathError
// if errors.As(err, &pathError) {
// fmt.Println("Failed at path:", pathError.Path)
// }
//
// With:
//
// if pathError, ok := errors.AsType[*fs.PathError](err); ok {
// fmt.Println("Failed at path:", pathError.Path)
// }
func AsType[T error](err error) (T, bool) {
for err != nil {
if e, is := err.(T); is {
return e, true
}
var res T
if x, ok := err.(interface{ As(any) bool }); ok && x.As(&res) {
return res, true
}
err = stderrors.Unwrap(err)
}
var zero T
return zero, false
}
// SetLocation takes a given error and records where in the stack SetLocation
// was called from and returns the wrapped error with the location information
// set. The returned error implements the Locationer interface. If err is nil
// then a nil error is returned.
func SetLocation(err error, callDepth int) error {
if err == nil {
return nil
}
return newLocationError(err, callDepth)
}
// fmtNoop provides an internal type for wrapping errors so they won't be
// printed in fmt type commands. As this type is used by the Hide function it's
// expected that error not be nil.
type fmtNoop struct {
error
}
// Format implements the fmt.Formatter interface so that the error wrapped by
// fmtNoop will not be printed.
func (*fmtNoop) Format(_ fmt.State, r rune) {}
// Is implements errors.Is. It useful for us to be able to check if an error
// chain has fmtNoop for formatting purposes.
func (f *fmtNoop) Is(err error) bool {
_, is := err.(*fmtNoop)
return is
}
// Unwrap implements the errors.Unwrap method returning the error wrapped by
// fmtNoop.
func (f *fmtNoop) Unwrap() error {
return f.error
}
// Hide takes an error and silences it's error string from appearing in fmt
// like
func Hide(err error) error {
if err == nil {
return nil
}
return &fmtNoop{err}
}

View file

@ -1 +0,0 @@
*.test

191
vendor/github.com/juju/retry/LICENSE generated vendored
View file

@ -1,191 +0,0 @@
All files in this repository are licensed as follows. If you contribute
to this repository, it is assumed that you license your contribution
under the same license unless you state otherwise.
All files Copyright (C) 2015 Canonical Ltd. unless otherwise specified in the file.
This software is licensed under the LGPLv3, included below.
As a special exception to the GNU Lesser General Public License version 3
("LGPL3"), the copyright holders of this Library give you permission to
convey to a third party a Combined Work that links statically or dynamically
to this Library without providing any Minimal Corresponding Source or
Minimal Application Code as set out in 4d or providing the installation
information set out in section 4e, provided that you comply with the other
provisions of LGPL3 and provided that you meet, for the Application the
terms and conditions of the license(s) which apply to the Application.
Except as stated in this special exception, the provisions of LGPL3 will
continue to comply in full to this Library. If you modify this Library, you
may apply this exception to your version of this Library, but you are not
obliged to do so. If you do not wish to do so, delete this exception
statement from your version. This exception does not (and cannot) modify any
license terms which apply to the Application, with which you must still
comply.
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

View file

@ -1,15 +0,0 @@
PROJECT := github.com/juju/retry
default: check
check-licence:
@(fgrep -rl "Licensed under the LGPLv3" .;\
fgrep -rl "MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT" .;\
find . -name "*.go") | sed -e 's,\./,,' | sort | uniq -u | \
xargs -I {} echo FAIL: licence missed: {}
check: check-licence
go test $(PROJECT)/...
docs:
godoc2md $(PROJECT) > README.md

View file

@ -1,277 +0,0 @@
# retry
import "github.com/juju/retry"
The retry package encapsulates the mechanism around retrying commands.
The simple use is to call retry.Call with a function closure.
```go
err := retry.Call(retry.CallArgs{
Func: func() error { ... },
Attempts: 5,
Delay: time.Minute,
Clock: clock.WallClock,
})
```
The bare minimum arguments that need to be specified are:
* Func - the function to call
* Attempts - the number of times to try Func before giving up, or a negative number for unlimited attempts (`retry.UnlimitedAttempts`)
* Delay - how long to wait between each try that returns an error
* Clock - either the wall clock, or some testing clock
Any error that is returned from the `Func` is considered transient.
In order to identify some errors as fatal, pass in a function for the
`IsFatalError` CallArgs value.
In order to have the `Delay` change for each iteration, a `BackoffFunc`
needs to be set on the CallArgs. A simple doubling delay function is
provided by `DoubleDelay`.
An example of a more complex `BackoffFunc` could be a stepped function such
as:
```go
func StepDelay(last time.Duration, attempt int) time.Duration {
switch attempt{
case 1:
return time.Second
case 2:
return 5 * time.Second
case 3:
return 20 * time.Second
case 4:
return time.Minute
case 5:
return 5 * time.Minute
default:
return 2 * last
}
}
```
Consider some package `foo` that has a `TryAgainError`, which looks something
like this:
```go
type TryAgainError struct {
After time.Duration
}
```
and we create something that looks like this:
```go
type TryAgainHelper struct {
next time.Duration
}
func (h *TryAgainHelper) notify(lastError error, attempt int) {
if tryAgain, ok := lastError.(*foo.TryAgainError); ok {
h.next = tryAgain.After
} else {
h.next = 0
}
}
func (h *TryAgainHelper) next(last time.Duration) time.Duration {
if h.next != 0 {
return h.next
}
return last
}
```
Then we could do this:
```go
helper := TryAgainHelper{}
retry.Call(retry.CallArgs{
Func: func() error {
return foo.SomeFunc()
},
NotifyFunc: helper.notify,
BackoffFunc: helper.next,
Attempts: 20,
Delay: 100 * time.Millisecond,
Clock: clock.WallClock,
})
```
## Constants
``` go
const (
// UnlimitedAttempts can be used as a value for `Attempts` to clearly
// show to the reader that there is no limit to the number of attempts.
UnlimitedAttempts = -1
)
```
## func Call
``` go
func Call(args CallArgs) error
```
Call will repeatedly execute the Func until either the function returns no
error, the retry count is exceeded or the stop channel is closed.
## func DoubleDelay
``` go
func DoubleDelay(delay time.Duration, attempt int) time.Duration
```
DoubleDelay provides a simple function that doubles the duration passed in.
This can then be easily used as the `BackoffFunc` in the `CallArgs`
structure.
## func ExpBackoff
``` go
func ExpBackoff(minDelay, maxDelay time.Duration, exp float64, applyJitter bool) func(time.Duration, int) time.Duration {
```
ExpBackoff returns a function a which generates time.Duration values using an
exponential back-off algorithm with the specified parameters. The returned value
can then be easily used as the `BackoffFunc` in the `CallArgs` structure.
The next delay value is calculated using the following formula:
`newDelay = min(minDelay * exp^attempt, maxDelay)`
If `applyJitter` is set to `true`, the function will randomly select and return
back a value in the `[minDelay, newDelay]` range.
## func IsAttemptsExceeded
``` go
func IsAttemptsExceeded(err error) bool
```
IsAttemptsExceeded returns true if the error is the result of the `Call`
function finishing due to hitting the requested number of `Attempts`.
## func IsDurationExceeded
``` go
func IsDurationExceeded(err error) bool
```
IsDurationExceeded returns true if the error is the result of the `Call`
function finishing due to the total duration exceeding the specified
`MaxDuration` value.
## func IsRetryStopped
``` go
func IsRetryStopped(err error) bool
```
IsRetryStopped returns true if the error is the result of the `Call`
function finishing due to the stop channel being closed.
## func LastError
``` go
func LastError(err error) error
```
LastError retrieves the last error returned from `Func` before iteration
was terminated due to the attempt count being exceeded, the maximum
duration being exceeded, or the stop channel being closed.
## type CallArgs
``` go
type CallArgs struct {
// Func is the function that will be retried if it returns an error result.
Func func() error
// IsFatalError is a function that, if set, will be called for every non-
// nil error result from `Func`. If `IsFatalError` returns true, the error
// is immediately returned breaking out from any further retries.
IsFatalError func(error) bool
// NotifyFunc is a function that is called if Func fails, and the attempt
// number. The first time this function is called attempt is 1, the second
// time, attempt is 2 and so on.
NotifyFunc func(lastError error, attempt int)
// Attempts specifies the number of times Func should be retried before
// giving up and returning the `AttemptsExceeded` error. If a negative
// value is specified, the `Call` will retry forever.
Attempts int
// Delay specifies how long to wait between retries.
Delay time.Duration
// MaxDelay specifies how longest time to wait between retries. If no
// value is specified there is no maximum delay.
MaxDelay time.Duration
// MaxDuration specifies the maximum time the `Call` function should spend
// iterating over `Func`. The duration is calculated from the start of the
// `Call` function. If the next delay time would take the total duration
// of the call over MaxDuration, then a DurationExceeded error is
// returned. If no value is specified, Call will continue until the number
// of attempts is complete.
MaxDuration time.Duration
// BackoffFunc allows the caller to provide a function that alters the
// delay each time through the loop. If this function is not provided the
// delay is the same each iteration. Alternatively a function such as
// `retry.DoubleDelay` can be used that will provide an exponential
// backoff. The first time this function is called attempt is 1, the
// second time, attempt is 2 and so on.
BackoffFunc func(delay time.Duration, attempt int) time.Duration
// Clock provides the mechanism for waiting. Normal program execution is
// expected to use something like clock.WallClock, and tests can override
// this to not actually sleep in tests.
Clock clock.Clock
// Stop is a channel that can be used to indicate that the waiting should
// be interrupted. If Stop is nil, then the Call function cannot be interrupted.
// If the channel is closed prior to the Call function being executed, the
// Func is still attempted once.
Stop <-chan struct{}
}
```
CallArgs is a simple structure used to define the behaviour of the Call
function.
### func (\*CallArgs) Validate
``` go
func (args *CallArgs) Validate() error
```
Validate the values are valid. The ensures that the Func, Delay, Attempts
and Clock have been specified.
- - -
Generated by [godoc2md](http://godoc.org/github.com/davecheney/godoc2md)

View file

@ -1,16 +0,0 @@
// Copyright 2015 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package retry
import "time"
// Clock provides an interface for dealing with clocks.
type Clock interface {
// Now returns the current clock time.
Now() time.Time
// After waits for the duration to elapse and then sends the
// current time on the returned channel.
After(time.Duration) <-chan time.Time
}

90
vendor/github.com/juju/retry/doc.go generated vendored
View file

@ -1,90 +0,0 @@
// Copyright 2015 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
// The retry package encapsulates the mechanism around retrying commands.
//
// The simple use is to call retry.Call with a function closure.
//
// err := retry.Call(retry.CallArgs{
// Func: func() error { ... },
// Attempts: 5,
// Delay: time.Minute,
// Clock: clock.WallClock,
// })
//
// The bare minimum arguments that need to be specified are:
// - Func - the function to call
// - Attempts - the number of times to try Func before giving up, or a negative number for unlimited attempts (`retry.UnlimitedAttempts`)
// - Delay - how long to wait between each try that returns an error
// - Clock - either the wall clock, or some testing clock
//
// Any error that is returned from the Func is considered transient.
// In order to identify some errors as fatal, pass in a function for the
// IsFatalError CallArgs value.
//
// In order to have the Delay change for each iteration, a BackoffFunc
// needs to be set on the CallArgs. A simple doubling delay function is
// provided by DoubleDelay.
//
// An example of a more complex BackoffFunc could be a stepped function such
// as:
//
// func StepDelay(last time.Duration, attempt int) time.Duration {
// switch attempt{
// case 1:
// return time.Second
// case 2:
// return 5 * time.Second
// case 3:
// return 20 * time.Second
// case 4:
// return time.Minute
// case 5:
// return 5 * time.Minute
// default:
// return 2 * last
// }
// }
//
// Consider some package foo that has a TryAgainError, which looks something
// like this:
//
// type TryAgainError struct {
// After time.Duration
// }
//
// and we create something that looks like this:
//
// type TryAgainHelper struct {
// next time.Duration
// }
//
// func (h *TryAgainHelper) notify(lastError error, attempt int) {
// if tryAgain, ok := lastError.(*foo.TryAgainError); ok {
// h.next = tryAgain.After
// } else {
// h.next = 0
// }
// }
//
// func (h *TryAgainHelper) next(last time.Duration) time.Duration {
// if h.next != 0 {
// return h.next
// }
// return last
// }
//
// Then we could do this:
//
// helper := TryAgainHelper{}
// retry.Call(retry.CallArgs{
// Func: func() error {
// return foo.SomeFunc()
// },
// NotifyFunc: helper.notify,
// BackoffFunc: helper.next,
// Attempts: 20,
// Delay: 100 * time.Millisecond,
// Clock: clock.WallClock,
// })
package retry

260
vendor/github.com/juju/retry/retry.go generated vendored
View file

@ -1,260 +0,0 @@
// Copyright 2015 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package retry
import (
"fmt"
"math"
"math/rand"
"time"
"github.com/juju/errors"
)
const (
// UnlimitedAttempts can be used as a value for Attempts to clearly
// show to the reader that there is no limit to the number of attempts.
UnlimitedAttempts = -1
)
// retryStopped is the error that is returned from the Call function
// when the stop channel has been closed.
type retryStopped struct {
lastError error
}
// Error provides the implementation for the error interface method.
func (e *retryStopped) Error() string {
return fmt.Sprintf("retry stopped")
}
// attemptsExceeded is the error that is returned when the retry count has
// been hit without the function returning a nil error result. The last error
// returned from the function being retried is available as the LastError
// attribute.
type attemptsExceeded struct {
lastError error
}
// Error provides the implementation for the error interface method.
func (e *attemptsExceeded) Error() string {
return fmt.Sprintf("attempt count exceeded: %s", e.lastError)
}
// durationExceeded is the error that is returned when the total time that the
// Call function would have executed exceeds the MaxDuration specified.
// The last error returned from the function being retried is available as the
// LastError attribute.
type durationExceeded struct {
lastError error
}
// Error provides the implementation for the error interface method.
func (e *durationExceeded) Error() string {
return fmt.Sprintf("max duration exceeded: %s", e.lastError)
}
// LastError retrieves the last error returned from Func before iteration
// was terminated due to the attempt count being exceeded, the maximum
// duration being exceeded, or the stop channel being closed.
func LastError(err error) error {
cause := errors.Cause(err)
switch err := cause.(type) {
case *attemptsExceeded:
return err.lastError
case *retryStopped:
return err.lastError
case *durationExceeded:
return err.lastError
}
return errors.Errorf("unexpected error type: %T, %s", cause, cause)
}
// IsAttemptsExceeded returns true if the error is the result of the Call
// function finishing due to hitting the requested number of Attempts.
func IsAttemptsExceeded(err error) bool {
cause := errors.Cause(err)
_, ok := cause.(*attemptsExceeded)
return ok
}
// IsDurationExceeded returns true if the error is the result of the Call
// function finishing due to the total duration exceeding the specified
// MaxDuration value.
func IsDurationExceeded(err error) bool {
cause := errors.Cause(err)
_, ok := cause.(*durationExceeded)
return ok
}
// IsRetryStopped returns true if the error is the result of the Call
// function finishing due to the stop channel being closed.
func IsRetryStopped(err error) bool {
cause := errors.Cause(err)
_, ok := cause.(*retryStopped)
return ok
}
// CallArgs is a simple structure used to define the behaviour of the Call
// function.
type CallArgs struct {
// Func is the function that will be retried if it returns an error result.
Func func() error
// IsFatalError is a function that, if set, will be called for every non-
// nil error result from Func. If IsFatalError returns true, the error
// is immediately returned breaking out from any further retries.
IsFatalError func(error) bool
// NotifyFunc is a function that is called if Func fails, and the attempt
// number. The first time this function is called attempt is 1, the second
// time, attempt is 2 and so on.
NotifyFunc func(lastError error, attempt int)
// Attempts specifies the number of times Func should be retried before
// giving up and returning the AttemptsExceeded error. If a negative
// value is specified, the Call will retry forever.
Attempts int
// Delay specifies how long to wait between retries.
Delay time.Duration
// MaxDelay specifies how longest time to wait between retries. If no
// value is specified there is no maximum delay.
MaxDelay time.Duration
// MaxDuration specifies the maximum time the Call function should spend
// iterating over Func. The duration is calculated from the start of the
// Call function. If the next delay time would take the total duration
// of the call over MaxDuration, then a DurationExceeded error is
// returned. If no value is specified, Call will continue until the number
// of attempts is complete.
MaxDuration time.Duration
// BackoffFunc allows the caller to provide a function that alters the
// delay each time through the loop. If this function is not provided the
// delay is the same each iteration. Alternatively a function such as
// retry.DoubleDelay can be used that will provide an exponential
// backoff. The first time this function is called attempt is 1, the
// second time, attempt is 2 and so on.
BackoffFunc func(delay time.Duration, attempt int) time.Duration
// Clock provides the mechanism for waiting. Normal program execution is
// expected to use something like clock.WallClock, and tests can override
// this to not actually sleep in tests.
Clock Clock
// Stop is a channel that can be used to indicate that the waiting should
// be interrupted. If Stop is nil, then the Call function cannot be interrupted.
// If the channel is closed prior to the Call function being executed, the
// Func is still attempted once.
Stop <-chan struct{}
}
// Validate the values are valid. The ensures that the Func, Delay, Attempts
// and Clock have been specified.
func (args *CallArgs) Validate() error {
if args.Func == nil {
return errors.NotValidf("missing Func")
}
if args.Delay == 0 {
return errors.NotValidf("missing Delay")
}
if args.Clock == nil {
return errors.NotValidf("missing Clock")
}
// One of Attempts or MaxDuration need to be specified
if args.Attempts == 0 && args.MaxDuration == 0 {
return errors.NotValidf("missing Attempts or MaxDuration")
}
return nil
}
// Call will repeatedly execute the Func until either the function returns no
// error, the retry count is exceeded or the stop channel is closed.
func Call(args CallArgs) error {
err := args.Validate()
if err != nil {
return errors.Trace(err)
}
start := args.Clock.Now()
for i := 1; args.Attempts <= 0 || i <= args.Attempts; i++ {
err = args.Func()
if err == nil {
return nil
}
if args.IsFatalError != nil && args.IsFatalError(err) {
return errors.Trace(err)
}
if args.NotifyFunc != nil {
args.NotifyFunc(err, i)
}
if i == args.Attempts && args.Attempts > 0 {
break // don't wait before returning the error
}
if args.BackoffFunc != nil {
delay := args.BackoffFunc(args.Delay, i)
if delay > args.MaxDelay && args.MaxDelay > 0 {
delay = args.MaxDelay
}
args.Delay = delay
}
elapsedTime := args.Clock.Now().Sub(start)
if args.MaxDuration > 0 && (elapsedTime+args.Delay) > args.MaxDuration {
return errors.Wrap(err, &durationExceeded{err})
}
// Wait for the delay, and retry
select {
case <-args.Clock.After(args.Delay):
case <-args.Stop:
return errors.Wrap(err, &retryStopped{err})
}
}
return errors.Wrap(err, &attemptsExceeded{err})
}
// DoubleDelay provides a simple function that doubles the duration passed in.
// This can then be easily used as the BackoffFunc in the CallArgs
// structure.
func DoubleDelay(delay time.Duration, attempt int) time.Duration {
if attempt == 1 {
return delay
}
return delay * 2
}
// ExpBackoff returns a function a which generates time.Duration values using
// an exponential back-off algorithm with the specified parameters. The
// returned value can then be easily used as the BackoffFunc in the CallArgs
// structure.
//
// The next delay value is calculated using the following formula:
//
// newDelay = min(minDelay * exp^attempt, maxDelay)
//
// If applyJitter is set to true, the function will randomly select and return
// back a value in the [minDelay, newDelay] range.
func ExpBackoff(minDelay, maxDelay time.Duration, exp float64, applyJitter bool) func(time.Duration, int) time.Duration {
minDelayF := float64(minDelay)
maxDelayF := float64(maxDelay)
return func(_ time.Duration, attempt int) time.Duration {
newDelay := minDelayF * math.Pow(exp, float64(attempt))
// Return a random value in the [minDelay, newDelay) range.
if applyJitter {
// We want to go +/- 20%, which is a 40% swing, and
// Float64 returns in the range 0-1
newDelay = (1 + rand.Float64()*0.4 - 0.2) * newDelay
}
if newDelay < minDelayF {
newDelay = minDelayF
}
if newDelay > maxDelayF {
newDelay = maxDelayF
}
return time.Duration(newDelay).Round(time.Millisecond)
}
}

13
vendor/modules.txt vendored
View file

@ -131,19 +131,6 @@ github.com/jinzhu/now
# github.com/josharian/intern v1.0.0 # github.com/josharian/intern v1.0.0
## explicit; go 1.5 ## explicit; go 1.5
github.com/josharian/intern github.com/josharian/intern
# github.com/juju/clock v1.1.1
## explicit; go 1.18
github.com/juju/clock
# github.com/juju/errors v1.0.0
## explicit; go 1.18
github.com/juju/errors
# github.com/juju/loggo v1.0.0
## explicit; go 1.14
# github.com/juju/retry v1.0.1
## explicit; go 1.17
github.com/juju/retry
# github.com/juju/testing v1.0.2
## explicit; go 1.17
# github.com/mailru/easyjson v0.9.0 # github.com/mailru/easyjson v0.9.0
## explicit; go 1.20 ## explicit; go 1.20
github.com/mailru/easyjson/buffer github.com/mailru/easyjson/buffer

View file

@ -16,6 +16,7 @@ package websocket
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"log/slog" "log/slog"
"net" "net"
@ -24,7 +25,6 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
"github.com/pkg/errors"
"github.com/cloudbase/garm/auth" "github.com/cloudbase/garm/auth"
"github.com/cloudbase/garm/database/common" "github.com/cloudbase/garm/database/common"
@ -63,7 +63,7 @@ func NewClient(ctx context.Context, conn *websocket.Conn) (*Client, error) {
watcher.WithUserIDFilter(user), watcher.WithUserIDFilter(user),
) )
if err != nil { if err != nil {
return nil, errors.Wrap(err, "registering consumer") return nil, fmt.Errorf("error registering consumer: %w", err)
} }
return &Client{ return &Client{
id: clientID.String(), id: clientID.String(),