diff --git a/client/client.go b/client/client.go index c271538..1c8bfd0 100644 --- a/client/client.go +++ b/client/client.go @@ -5,12 +5,6 @@ import ( "code.gitea.io/bots-proto-go/runner/v1/runnerv1connect" ) -type Filter struct { - OS string `json:"os"` - Arch string `json:"arch"` - Labels []string `json:"labels"` -} - // A Client manages communication with the runner. type Client interface { pingv1connect.PingServiceClient diff --git a/cmd/daemon.go b/cmd/daemon.go index d3c1393..875b804 100644 --- a/cmd/daemon.go +++ b/cmd/daemon.go @@ -52,6 +52,7 @@ func runDaemon(ctx context.Context, envFile string) func(cmd *cobra.Command, arg Machine: cfg.Runner.Name, ForgeInstance: cfg.Client.Address, Environ: cfg.Runner.Environ, + Labels: cfg.Runner.Labels, } poller := poller.New( diff --git a/cmd/register.go b/cmd/register.go index 6a6d46b..fced14b 100644 --- a/cmd/register.go +++ b/cmd/register.go @@ -14,7 +14,7 @@ import ( "gitea.com/gitea/act_runner/client" "gitea.com/gitea/act_runner/config" "gitea.com/gitea/act_runner/register" - "github.com/appleboy/com/file" + "github.com/bufbuild/connect-go" "github.com/joho/godotenv" "github.com/mattn/go-isatty" @@ -148,12 +148,19 @@ func (r *registerInputs) assignToNext(stage registerStage, value string) registe r.RunnerName = value return StageInputCustomLabels case StageInputCustomLabels: - if value == "" { - return StageWaitingForRegistration + if value != "" { + r.CustomLabels = strings.Split(value, ",") + } else { + r.CustomLabels = []string{ + "ubuntu-latest:docker://node:16-bullseye", + "ubuntu-22.04:docker://node:16-bullseye", // There's no node:16-bookworm yet + "ubuntu-20.04:docker://node:16-bullseye", + "ubuntu-18.04:docker://node:16-buster", + } } - r.CustomLabels = strings.Split(value, ",") + if validateLabels(r.CustomLabels) != nil { - log.Infoln("Invalid labels, please input again (for example, ubuntu-latest:docker://node:16-buster)") + log.Infoln("Invalid labels, please input again, leave blank to use the default labels (for example, ubuntu-20.04:docker://node:16-bullseye,ubuntu-18.04:docker://node:16-buster)") return StageInputCustomLabels } return StageWaitingForRegistration @@ -171,7 +178,7 @@ func registerInteractive(envFile string) error { // check if overwrite local config _ = godotenv.Load(envFile) cfg, _ := config.FromEnviron() - if file.IsFile(cfg.Runner.File) { + if f, err := os.Stat(cfg.Runner.File); err == nil && !f.IsDir() { stage = StageOverwriteLocalConfig } @@ -217,7 +224,7 @@ func printStageHelp(stage registerStage) { hostname, _ := os.Hostname() log.Infof("Enter the runner name (if set empty, use hostname:%s ):\n", hostname) case StageInputCustomLabels: - log.Infoln("Enter the runner custom labels (comma-separated, for example, ubuntu-latest:docker://node:16-buster,ubuntu-2204:docker://node:18-buster):") + log.Infoln("Enter the runner labels, leave blank to use the default labels (comma-separated, for example, ubuntu-20.04:docker://node:16-bullseye,ubuntu-18.04:docker://node:16-buster):") case StageWaitingForRegistration: log.Infoln("Waiting for registration...") } @@ -285,18 +292,10 @@ func doRegister(cfg *config.Config, inputs *registerInputs) error { } } - register := register.New( - cli, - &client.Filter{ - OS: cfg.Platform.OS, - Arch: cfg.Platform.Arch, - Labels: inputs.CustomLabels, - }, - ) cfg.Runner.Name = inputs.RunnerName cfg.Runner.Token = inputs.Token cfg.Runner.Labels = inputs.CustomLabels - _, err := register.Register(ctx, cfg.Runner) + _, err := register.New(cli).Register(ctx, cfg.Runner) if err != nil { log.WithError(err).Errorln("Cannot register the runner") return nil diff --git a/config/config.go b/config/config.go index 1cf8858..f5bfa8d 100644 --- a/config/config.go +++ b/config/config.go @@ -7,7 +7,7 @@ import ( "runtime" "gitea.com/gitea/act_runner/core" - "github.com/appleboy/com/file" + "github.com/joho/godotenv" "github.com/kelseyhightower/envconfig" ) @@ -54,7 +54,7 @@ func FromEnviron() (Config, error) { } // check runner config exist - if file.IsFile(cfg.Runner.File) { + if f, err := os.Stat(cfg.Runner.File); err == nil && !f.IsDir() { jsonFile, _ := os.Open(cfg.Runner.File) defer jsonFile.Close() byteValue, _ := io.ReadAll(jsonFile) @@ -68,6 +68,9 @@ func FromEnviron() (Config, error) { if runner.Token != "" { cfg.Runner.Token = runner.Token } + if len(runner.Labels) != 0 { + cfg.Runner.Labels = runner.Labels + } if runner.Address != "" { cfg.Client.Address = runner.Address } diff --git a/go.mod b/go.mod index 2537953..f9821cd 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ go 1.18 require ( code.gitea.io/bots-proto-go v0.1.0 - github.com/appleboy/com v0.1.6 github.com/avast/retry-go/v4 v4.1.0 github.com/bufbuild/connect-go v1.1.0 github.com/docker/docker v20.10.21+incompatible diff --git a/go.sum b/go.sum index e12df32..7e160ee 100644 --- a/go.sum +++ b/go.sum @@ -87,8 +87,6 @@ github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:C github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/appleboy/com v0.1.6 h1:vP9ryTIbSFaXSrZcFTU7RRcgPbrpGJ0Oy5wpgEkQ2m8= -github.com/appleboy/com v0.1.6/go.mod h1:jnufjIC3opMlReyPPPye+8JqNvUzLm25o7h6SOy8nv0= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= diff --git a/poller/poller.go b/poller/poller.go index 3d9035c..a94cbd1 100644 --- a/poller/poller.go +++ b/poller/poller.go @@ -28,7 +28,6 @@ func New(cli client.Client, dispatch func(context.Context, *runnerv1.Task) error type Poller struct { Client client.Client - Filter *client.Filter Dispatch func(context.Context, *runnerv1.Task) error sync.Mutex diff --git a/register/register.go b/register/register.go index c5556e7..86f9932 100644 --- a/register/register.go +++ b/register/register.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "os" + "strings" runnerv1 "code.gitea.io/bots-proto-go/runner/v1" "gitea.com/gitea/act_runner/client" @@ -14,27 +15,26 @@ import ( log "github.com/sirupsen/logrus" ) -var defaultLabels = []string{"self-hosted"} - -func New(cli client.Client, filter *client.Filter) *Register { +func New(cli client.Client) *Register { return &Register{ Client: cli, - Filter: filter, } } type Register struct { Client client.Client - Filter *client.Filter } func (p *Register) Register(ctx context.Context, cfg config.Runner) (*core.Runner, error) { + labels := make([]string, len(cfg.Labels)) + for i, v := range cfg.Labels { + labels[i] = strings.SplitN(v, ":", 2)[0] + } // register new runner. resp, err := p.Client.Register(ctx, connect.NewRequest(&runnerv1.RegisterRequest{ - Name: cfg.Name, - Token: cfg.Token, - AgentLabels: append(defaultLabels, []string{p.Filter.OS, p.Filter.Arch}...), - CustomLabels: p.Filter.Labels, + Name: cfg.Name, + Token: cfg.Token, + AgentLabels: labels, })) if err != nil { log.WithError(err).Error("poller: cannot register new runner") diff --git a/runtime/runtime.go b/runtime/runtime.go index 439e8fa..6b88fb5 100644 --- a/runtime/runtime.go +++ b/runtime/runtime.go @@ -2,6 +2,7 @@ package runtime import ( "context" + "strings" runnerv1 "code.gitea.io/bots-proto-go/runner/v1" "gitea.com/gitea/act_runner/client" @@ -13,9 +14,45 @@ type Runner struct { ForgeInstance string Environ map[string]string Client client.Client + Labels []string } // Run runs the pipeline stage. func (s *Runner) Run(ctx context.Context, task *runnerv1.Task) error { - return NewTask(s.ForgeInstance, task.Id, s.Client, s.Environ).Run(ctx, task) + return NewTask(s.ForgeInstance, task.Id, s.Client, s.Environ, s.platformPicker).Run(ctx, task) +} + +func (s *Runner) platformPicker(labels []string) string { + // "ubuntu-18.04:docker://node:16-buster" + + platforms := make(map[string]string, len(labels)) + for _, l := range s.Labels { + // "ubuntu-18.04:docker://node:16-buster" + splits := strings.SplitN(l, ":", 2) + // ["ubuntu-18.04", "docker://node:16-buster"] + k, v := splits[0], splits[1] + + if prefix := "docker://"; !strings.HasPrefix(v, prefix) { + continue + } else { + v = strings.TrimPrefix(v, prefix) + } + // ubuntu-18.04 => node:16-buster + platforms[k] = v + } + + for _, label := range labels { + if v, ok := platforms[label]; ok { + return v + } + } + + // TODO: support multiple labels + // like: + // ["ubuntu-22.04"] => "ubuntu:22.04" + // ["with-gpu"] => "linux:with-gpu" + // ["ubuntu-22.04", "with-gpu"] => "ubuntu:22.04_with-gpu" + + // return default + return "node:16-bullseye" } diff --git a/runtime/task.go b/runtime/task.go index ef70e9d..062e40f 100644 --- a/runtime/task.go +++ b/runtime/task.go @@ -66,12 +66,13 @@ type Task struct { BuildID int64 Input *TaskInput - client client.Client - log *log.Entry + client client.Client + log *log.Entry + platformPicker func([]string) string } // NewTask creates a new task -func NewTask(forgeInstance string, buildID int64, client client.Client, runnerEnvs map[string]string) *Task { +func NewTask(forgeInstance string, buildID int64, client client.Client, runnerEnvs map[string]string, picker func([]string) string) *Task { task := &Task{ Input: &TaskInput{ envs: runnerEnvs, @@ -79,8 +80,9 @@ func NewTask(forgeInstance string, buildID int64, client client.Client, runnerEn }, BuildID: buildID, - client: client, - log: log.WithField("buildID", buildID), + client: client, + log: log.WithField("buildID", buildID), + platformPicker: picker, } task.Input.repoDirectory, _ = os.Getwd() return task @@ -99,34 +101,6 @@ func getWorkflowsPath(dir string) (string, error) { return p, nil } -func platformPicker(labels []string) string { - - // FIXME: read custom labels - - preset := map[string]string{ - // FIXME: shouldn't be the same - "ubuntu-latest": "node:16-buster", - "ubuntu-22.04": "node:16-buster", - "ubuntu-20.04": "node:16-buster", - "ubuntu-18.04": "node:16-buster", - } - - for _, label := range labels { - if v, ok := preset[label]; ok { - return v - } - } - - // TODO: support multiple labels - // like: - // ["ubuntu-22.04"] => "ubuntu:22.04" - // ["with-gpu"] => "linux:with-gpu" - // ["ubuntu-22.04", "with-gpu"] => "ubuntu:22.04_with-gpu" - - // FIXME: shall we need to support default? - return "node:16-buster" -} - func getToken(task *runnerv1.Task) string { token := task.Secrets["GITHUB_TOKEN"] if task.Secrets["GITEA_TOKEN"] != "" { @@ -247,7 +221,7 @@ func (t *Task) Run(ctx context.Context, task *runnerv1.Task) error { ContainerMaxLifetime: 3 * time.Hour, // maybe should be specified by Gitea server ContainerNetworkMode: input.containerNetworkMode, DefaultActionInstance: dataContext["gitea_default_bots_url"].GetStringValue(), - PlatformPicker: platformPicker, + PlatformPicker: t.platformPicker, } r, err := runner.New(config) if err != nil {