feat: use specified labels

This commit is contained in:
Jason Song 2022-11-24 11:55:52 +08:00
parent 5781e233c1
commit 2354f5bb18
10 changed files with 76 additions and 72 deletions

View file

@ -5,12 +5,6 @@ import (
"code.gitea.io/bots-proto-go/runner/v1/runnerv1connect" "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. // A Client manages communication with the runner.
type Client interface { type Client interface {
pingv1connect.PingServiceClient pingv1connect.PingServiceClient

View file

@ -52,6 +52,7 @@ func runDaemon(ctx context.Context, envFile string) func(cmd *cobra.Command, arg
Machine: cfg.Runner.Name, Machine: cfg.Runner.Name,
ForgeInstance: cfg.Client.Address, ForgeInstance: cfg.Client.Address,
Environ: cfg.Runner.Environ, Environ: cfg.Runner.Environ,
Labels: cfg.Runner.Labels,
} }
poller := poller.New( poller := poller.New(

View file

@ -14,7 +14,7 @@ import (
"gitea.com/gitea/act_runner/client" "gitea.com/gitea/act_runner/client"
"gitea.com/gitea/act_runner/config" "gitea.com/gitea/act_runner/config"
"gitea.com/gitea/act_runner/register" "gitea.com/gitea/act_runner/register"
"github.com/appleboy/com/file"
"github.com/bufbuild/connect-go" "github.com/bufbuild/connect-go"
"github.com/joho/godotenv" "github.com/joho/godotenv"
"github.com/mattn/go-isatty" "github.com/mattn/go-isatty"
@ -148,12 +148,19 @@ func (r *registerInputs) assignToNext(stage registerStage, value string) registe
r.RunnerName = value r.RunnerName = value
return StageInputCustomLabels return StageInputCustomLabels
case StageInputCustomLabels: case StageInputCustomLabels:
if value == "" { if value != "" {
return StageWaitingForRegistration
}
r.CustomLabels = strings.Split(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",
}
}
if validateLabels(r.CustomLabels) != nil { 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 StageInputCustomLabels
} }
return StageWaitingForRegistration return StageWaitingForRegistration
@ -171,7 +178,7 @@ func registerInteractive(envFile string) error {
// check if overwrite local config // check if overwrite local config
_ = godotenv.Load(envFile) _ = godotenv.Load(envFile)
cfg, _ := config.FromEnviron() cfg, _ := config.FromEnviron()
if file.IsFile(cfg.Runner.File) { if f, err := os.Stat(cfg.Runner.File); err == nil && !f.IsDir() {
stage = StageOverwriteLocalConfig stage = StageOverwriteLocalConfig
} }
@ -217,7 +224,7 @@ func printStageHelp(stage registerStage) {
hostname, _ := os.Hostname() hostname, _ := os.Hostname()
log.Infof("Enter the runner name (if set empty, use hostname:%s ):\n", hostname) log.Infof("Enter the runner name (if set empty, use hostname:%s ):\n", hostname)
case StageInputCustomLabels: 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: case StageWaitingForRegistration:
log.Infoln("Waiting for registration...") 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.Name = inputs.RunnerName
cfg.Runner.Token = inputs.Token cfg.Runner.Token = inputs.Token
cfg.Runner.Labels = inputs.CustomLabels cfg.Runner.Labels = inputs.CustomLabels
_, err := register.Register(ctx, cfg.Runner) _, err := register.New(cli).Register(ctx, cfg.Runner)
if err != nil { if err != nil {
log.WithError(err).Errorln("Cannot register the runner") log.WithError(err).Errorln("Cannot register the runner")
return nil return nil

View file

@ -7,7 +7,7 @@ import (
"runtime" "runtime"
"gitea.com/gitea/act_runner/core" "gitea.com/gitea/act_runner/core"
"github.com/appleboy/com/file"
"github.com/joho/godotenv" "github.com/joho/godotenv"
"github.com/kelseyhightower/envconfig" "github.com/kelseyhightower/envconfig"
) )
@ -54,7 +54,7 @@ func FromEnviron() (Config, error) {
} }
// check runner config exist // 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) jsonFile, _ := os.Open(cfg.Runner.File)
defer jsonFile.Close() defer jsonFile.Close()
byteValue, _ := io.ReadAll(jsonFile) byteValue, _ := io.ReadAll(jsonFile)
@ -68,6 +68,9 @@ func FromEnviron() (Config, error) {
if runner.Token != "" { if runner.Token != "" {
cfg.Runner.Token = runner.Token cfg.Runner.Token = runner.Token
} }
if len(runner.Labels) != 0 {
cfg.Runner.Labels = runner.Labels
}
if runner.Address != "" { if runner.Address != "" {
cfg.Client.Address = runner.Address cfg.Client.Address = runner.Address
} }

1
go.mod
View file

@ -4,7 +4,6 @@ go 1.18
require ( require (
code.gitea.io/bots-proto-go v0.1.0 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/avast/retry-go/v4 v4.1.0
github.com/bufbuild/connect-go v1.1.0 github.com/bufbuild/connect-go v1.1.0
github.com/docker/docker v20.10.21+incompatible github.com/docker/docker v20.10.21+incompatible

2
go.sum
View file

@ -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 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= 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/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/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 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=

View file

@ -28,7 +28,6 @@ func New(cli client.Client, dispatch func(context.Context, *runnerv1.Task) error
type Poller struct { type Poller struct {
Client client.Client Client client.Client
Filter *client.Filter
Dispatch func(context.Context, *runnerv1.Task) error Dispatch func(context.Context, *runnerv1.Task) error
sync.Mutex sync.Mutex

View file

@ -4,6 +4,7 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"os" "os"
"strings"
runnerv1 "code.gitea.io/bots-proto-go/runner/v1" runnerv1 "code.gitea.io/bots-proto-go/runner/v1"
"gitea.com/gitea/act_runner/client" "gitea.com/gitea/act_runner/client"
@ -14,27 +15,26 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
var defaultLabels = []string{"self-hosted"} func New(cli client.Client) *Register {
func New(cli client.Client, filter *client.Filter) *Register {
return &Register{ return &Register{
Client: cli, Client: cli,
Filter: filter,
} }
} }
type Register struct { type Register struct {
Client client.Client Client client.Client
Filter *client.Filter
} }
func (p *Register) Register(ctx context.Context, cfg config.Runner) (*core.Runner, error) { 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. // register new runner.
resp, err := p.Client.Register(ctx, connect.NewRequest(&runnerv1.RegisterRequest{ resp, err := p.Client.Register(ctx, connect.NewRequest(&runnerv1.RegisterRequest{
Name: cfg.Name, Name: cfg.Name,
Token: cfg.Token, Token: cfg.Token,
AgentLabels: append(defaultLabels, []string{p.Filter.OS, p.Filter.Arch}...), AgentLabels: labels,
CustomLabels: p.Filter.Labels,
})) }))
if err != nil { if err != nil {
log.WithError(err).Error("poller: cannot register new runner") log.WithError(err).Error("poller: cannot register new runner")

View file

@ -2,6 +2,7 @@ package runtime
import ( import (
"context" "context"
"strings"
runnerv1 "code.gitea.io/bots-proto-go/runner/v1" runnerv1 "code.gitea.io/bots-proto-go/runner/v1"
"gitea.com/gitea/act_runner/client" "gitea.com/gitea/act_runner/client"
@ -13,9 +14,45 @@ type Runner struct {
ForgeInstance string ForgeInstance string
Environ map[string]string Environ map[string]string
Client client.Client Client client.Client
Labels []string
} }
// Run runs the pipeline stage. // Run runs the pipeline stage.
func (s *Runner) Run(ctx context.Context, task *runnerv1.Task) error { 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"
} }

View file

@ -68,10 +68,11 @@ type Task struct {
client client.Client client client.Client
log *log.Entry log *log.Entry
platformPicker func([]string) string
} }
// NewTask creates a new task // 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{ task := &Task{
Input: &TaskInput{ Input: &TaskInput{
envs: runnerEnvs, envs: runnerEnvs,
@ -81,6 +82,7 @@ func NewTask(forgeInstance string, buildID int64, client client.Client, runnerEn
client: client, client: client,
log: log.WithField("buildID", buildID), log: log.WithField("buildID", buildID),
platformPicker: picker,
} }
task.Input.repoDirectory, _ = os.Getwd() task.Input.repoDirectory, _ = os.Getwd()
return task return task
@ -99,34 +101,6 @@ func getWorkflowsPath(dir string) (string, error) {
return p, nil 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 { func getToken(task *runnerv1.Task) string {
token := task.Secrets["GITHUB_TOKEN"] token := task.Secrets["GITHUB_TOKEN"]
if task.Secrets["GITEA_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 ContainerMaxLifetime: 3 * time.Hour, // maybe should be specified by Gitea server
ContainerNetworkMode: input.containerNetworkMode, ContainerNetworkMode: input.containerNetworkMode,
DefaultActionInstance: dataContext["gitea_default_bots_url"].GetStringValue(), DefaultActionInstance: dataContext["gitea_default_bots_url"].GetStringValue(),
PlatformPicker: platformPicker, PlatformPicker: t.platformPicker,
} }
r, err := runner.New(config) r, err := runner.New(config)
if err != nil { if err != nil {