diff --git a/models/bots/runner.go b/models/bots/runner.go index 39de26830a..047945e1a3 100644 --- a/models/bots/runner.go +++ b/models/bots/runner.go @@ -43,7 +43,7 @@ type Runner struct { Description string `xorm:"TEXT"` Base int // 0 native 1 docker 2 virtual machine RepoRange string // glob match which repositories could use this runner - Token string + Token string `xorm:"CHAR(36) UNIQUE"` // instance status (idle) Status core.RunnerStatus @@ -148,7 +148,7 @@ func GetRunnerByToken(token string) (*Runner, error) { return nil, err } else if !has { return nil, ErrRunnerNotExist{ - UUID: "", + Token: token, } } return &runner, nil @@ -177,3 +177,9 @@ func FindRunnersByRepoID(repoID int64) ([]*Runner, error) { err = db.GetEngine(db.DefaultContext).Join("INNER", "repository", "repository.owner_id = bot_runner.owner_id").Find(&runners) return runners, err } + +// NewRunner creates new runner. +func NewRunner(ctx context.Context, t *Runner) error { + _, err := db.GetEngine(ctx).Insert(t) + return err +} diff --git a/models/bots/runner_token.go b/models/bots/runner_token.go index 234b396151..90070c57bb 100644 --- a/models/bots/runner_token.go +++ b/models/bots/runner_token.go @@ -5,6 +5,9 @@ package bots import ( + "context" + "fmt" + "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" @@ -14,14 +17,24 @@ import ( gouuid "github.com/google/uuid" ) +// ErrRunnerNotExist represents an error for bot runner not exist +type ErrRunnerTokenNotExist struct { + Token string +} + +func (err ErrRunnerTokenNotExist) Error() string { + return fmt.Sprintf("runner token [%s] is not exist", err.Token) +} + // RunnerToken represents runner tokens type RunnerToken struct { - ID int64 - Token string `xorm:"CHAR(36) UNIQUE"` - OwnerID int64 `xorm:"index"` // org level runner, 0 means system - Owner *user_model.User `xorm:"-"` - RepoID int64 `xorm:"index"` // repo level runner, if orgid also is zero, then it's a global - Repo *repo_model.Repository `xorm:"-"` + ID int64 + Token string `xorm:"CHAR(36) UNIQUE"` + OwnerID int64 `xorm:"index"` // org level runner, 0 means system + Owner *user_model.User `xorm:"-"` + RepoID int64 `xorm:"index"` // repo level runner, if orgid also is zero, then it's a global + Repo *repo_model.Repository `xorm:"-"` + IsActive bool CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` @@ -35,9 +48,35 @@ func init() { db.RegisterModel(new(RunnerToken)) } -// NewAccessToken creates new access token. +// NewRunnerToken creates new runner token. func NewRunnerToken(t *RunnerToken) error { t.Token = base.EncodeSha1(gouuid.New().String()) _, err := db.GetEngine(db.DefaultContext).Insert(t) return err } + +// GetRunnerByToken returns a bot runner via token +func GetRunnerToken(token string) (*RunnerToken, error) { + var runnerToken RunnerToken + has, err := db.GetEngine(db.DefaultContext).Where("token=?", token).Get(&runnerToken) + if err != nil { + return nil, err + } else if !has { + return nil, ErrRunnerTokenNotExist{ + Token: token, + } + } + return &runnerToken, nil +} + +// UpdateRunnerToken updates runner token information. +func UpdateRunnerToken(ctx context.Context, r *RunnerToken, cols ...string) (err error) { + e := db.GetEngine(ctx) + + if len(cols) == 0 { + _, err = e.ID(r.ID).AllCols().Update(r) + } else { + _, err = e.ID(r.ID).Cols(cols...).Update(r) + } + return err +} diff --git a/routers/api/bots/runner/runner.go b/routers/api/bots/runner/runner.go index 7dbd4d5ca0..07575b1db2 100644 --- a/routers/api/bots/runner/runner.go +++ b/routers/api/bots/runner/runner.go @@ -15,6 +15,7 @@ import ( "gitea.com/gitea/proto-go/runner/v1/runnerv1connect" "github.com/bufbuild/connect-go" + gouuid "github.com/google/uuid" ) var _ runnerv1connect.RunnerServiceClient = (*Service)(nil) @@ -30,33 +31,49 @@ func (s *Service) Register( ctx context.Context, req *connect.Request[runnerv1.RegisterRequest], ) (*connect.Response[runnerv1.RegisterResponse], error) { - log.Info("Request headers: %v", req.Header()) - - token := req.Header().Get("X-Runner-Token") - log.Info("token: %v", token) - - if token == "" { - return nil, errors.New("missing runner token") + if req.Msg.Token == "" || req.Msg.Name == "" { + return nil, errors.New("missing runner token or name") } - // TODO: Get token data from runner_token table - runner, err := bots_model.GetRunnerByToken(token) + runnerToken, err := bots_model.GetRunnerToken(req.Msg.Token) if err != nil { - return nil, errors.New("runner not found") + return nil, errors.New("runner token not found") } - // update runner information - runner.AgentLabels = req.Msg.AgentLabels - runner.CustomLabels = req.Msg.CustomLabels - runner.Name = req.Msg.Name - if err := bots_model.UpdateRunner(ctx, runner, []string{"name", "agent_labels", "custom_labels"}...); err != nil { - return nil, errors.New("can't update runner") + if runnerToken.IsActive { + return nil, errors.New("runner token has already activated") + } + + // create new runner + runner := &bots_model.Runner{ + UUID: gouuid.New().String(), + Name: req.Msg.Name, + OwnerID: runnerToken.OwnerID, + RepoID: runnerToken.RepoID, + Token: req.Msg.Token, + Status: core.StatusOffline, + AgentLabels: req.Msg.AgentLabels, + CustomLabels: req.Msg.CustomLabels, + } + + // create new runner + if err := bots_model.NewRunner(ctx, runner); err != nil { + return nil, errors.New("can't create new runner") + } + + // update token status + runnerToken.IsActive = true + if err := bots_model.UpdateRunnerToken(ctx, runnerToken, "is_active"); err != nil { + return nil, errors.New("can't update runner token status") } res := connect.NewResponse(&runnerv1.RegisterResponse{ Runner: &runnerv1.Runner{ - Uuid: runner.UUID, - Token: runner.Token, + Uuid: runner.UUID, + Token: runner.Token, + Name: runner.Name, + AgentLabels: runner.AgentLabels, + CustomLabels: runner.CustomLabels, }, })