mirror of
https://gitea.com/gitea/act_runner.git
synced 2026-07-22 20:47:45 +00:00
feat: honour GITEA_RUNNER_LABELS on daemon start and accept labels containing a colon (#1085)
Fixes #648 Fixes #656 Fixes #664 --------- Co-authored-by: silverwind <me@silverwind.io> Reviewed-on: https://gitea.com/gitea/runner/pulls/1085 Reviewed-by: silverwind <2021+silverwind@noreply.gitea.com>
This commit is contained in:
@@ -51,6 +51,7 @@ func Execute(ctx context.Context) {
|
||||
RunE: runDaemon(ctx, &daemArgs, &configFile),
|
||||
}
|
||||
daemonCmd.Flags().BoolVar(&daemArgs.Once, "once", false, "Run one job then exit")
|
||||
daemonCmd.Flags().StringVar(&daemArgs.Labels, "labels", os.Getenv("GITEA_RUNNER_LABELS"), "Runner labels, comma separated. Overrides the labels of an already registered runner")
|
||||
rootCmd.AddCommand(daemonCmd)
|
||||
|
||||
// ./gitea-runner exec
|
||||
|
||||
@@ -49,10 +49,7 @@ func runDaemon(ctx context.Context, daemArgs *daemonArgs, configFile *string) fu
|
||||
return fmt.Errorf("failed to load registration file: %w", err)
|
||||
}
|
||||
|
||||
lbls := reg.Labels
|
||||
if len(cfg.Runner.Labels) > 0 {
|
||||
lbls = cfg.Runner.Labels
|
||||
}
|
||||
lbls := resolveLabels(daemArgs.Labels, cfg.Runner.Labels, reg.Labels)
|
||||
|
||||
ls := labels.Labels{}
|
||||
for _, l := range lbls {
|
||||
@@ -203,7 +200,30 @@ func runDaemon(ctx context.Context, daemArgs *daemonArgs, configFile *string) fu
|
||||
}
|
||||
|
||||
type daemonArgs struct {
|
||||
Once bool
|
||||
Once bool
|
||||
Labels string
|
||||
}
|
||||
|
||||
// resolveLabels picks the labels to run with: --labels/GITEA_RUNNER_LABELS > config > .runner.
|
||||
// The flag lets a registered runner change its labels without deleting the .runner file.
|
||||
func resolveLabels(argLabels string, cfgLabels, regLabels []string) []string {
|
||||
if lbls := splitLabels(argLabels); len(lbls) > 0 {
|
||||
return lbls
|
||||
}
|
||||
if len(cfgLabels) > 0 {
|
||||
return cfgLabels
|
||||
}
|
||||
return regLabels
|
||||
}
|
||||
|
||||
func splitLabels(s string) []string {
|
||||
var lbls []string
|
||||
for l := range strings.SplitSeq(s, ",") {
|
||||
if l = strings.TrimSpace(l); l != "" {
|
||||
lbls = append(lbls, l)
|
||||
}
|
||||
}
|
||||
return lbls
|
||||
}
|
||||
|
||||
// initLogging setup the global logrus logger.
|
||||
|
||||
@@ -12,6 +12,32 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestResolveLabels(t *testing.T) {
|
||||
var (
|
||||
cfgLabels = []string{"cfg:host"}
|
||||
regLabels = []string{"reg:host"}
|
||||
)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
arg string
|
||||
cfg []string
|
||||
reg []string
|
||||
want []string
|
||||
}{
|
||||
{"flag wins", "flag:host,other", cfgLabels, regLabels, []string{"flag:host", "other"}},
|
||||
{"config wins over registration", "", cfgLabels, regLabels, cfgLabels},
|
||||
{"registration is the fallback", "", nil, regLabels, regLabels},
|
||||
{"blank flag is ignored", " , ", cfgLabels, regLabels, cfgLabels},
|
||||
{"nothing configured", "", nil, nil, nil},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
require.Equal(t, tt.want, resolveLabels(tt.arg, tt.cfg, tt.reg))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDockerSocketPathUsesConfigAndEnvironment(t *testing.T) {
|
||||
got, err := getDockerSocketPath("tcp://docker.example:2376")
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -387,7 +387,10 @@ func doRegister(ctx context.Context, cfg *config.Config, inputs *registerInputs)
|
||||
|
||||
ls := make([]string, len(reg.Labels))
|
||||
for i, v := range reg.Labels {
|
||||
l, _ := labels.Parse(v)
|
||||
l, err := labels.Parse(v)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse label %q: %w", v, err)
|
||||
}
|
||||
ls[i] = l.Name
|
||||
}
|
||||
// register new runner.
|
||||
|
||||
@@ -15,11 +15,11 @@ import (
|
||||
|
||||
func TestRegisterNonInteractiveReturnsLabelValidationError(t *testing.T) {
|
||||
err := registerNoInteractive(t.Context(), "", ®isterArgs{
|
||||
Labels: "label:invalid",
|
||||
Labels: "ubuntu:host,,broken",
|
||||
Token: "token",
|
||||
InstanceAddr: "http://localhost:3000",
|
||||
})
|
||||
assert.Error(t, err, "unsupported schema: invalid")
|
||||
assert.ErrorContains(t, err, "empty label")
|
||||
}
|
||||
|
||||
func TestRegisterInputsValidate(t *testing.T) {
|
||||
@@ -40,8 +40,8 @@ func TestRegisterInputsValidate(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "invalid label",
|
||||
inputs: registerInputs{InstanceAddr: "http://localhost:3000", Token: "token", Labels: []string{"ubuntu:vm:bad"}},
|
||||
wantErr: "unsupported schema: vm",
|
||||
inputs: registerInputs{InstanceAddr: "http://localhost:3000", Token: "token", Labels: []string{""}},
|
||||
wantErr: "empty label",
|
||||
},
|
||||
{
|
||||
name: "valid",
|
||||
@@ -62,7 +62,9 @@ func TestRegisterInputsValidate(t *testing.T) {
|
||||
|
||||
func TestValidateLabels(t *testing.T) {
|
||||
require.NoError(t, validateLabels([]string{"ubuntu:host", "ubuntu:docker://node:18"}))
|
||||
require.Error(t, validateLabels([]string{"ubuntu:host", "ubuntu:vm:bad"}))
|
||||
// a colon that is not a supported schema is part of the label name
|
||||
require.NoError(t, validateLabels([]string{"pool:e57e18d4-10d4-406f-93bf-60f127221bdd"}))
|
||||
require.Error(t, validateLabels([]string{"ubuntu:host", ""}))
|
||||
}
|
||||
|
||||
func TestRegisterInputsStageValue(t *testing.T) {
|
||||
@@ -106,11 +108,10 @@ func TestRegisterInputsAssignToNext(t *testing.T) {
|
||||
|
||||
t.Run("labels from config skip the labels stage", func(t *testing.T) {
|
||||
cfg := &config.Config{}
|
||||
cfg.Runner.Labels = []string{"ubuntu:host", "ubuntu:vm:bad"}
|
||||
cfg.Runner.Labels = []string{"ubuntu:host", "", "pool:e57e18d4"}
|
||||
inputs := ®isterInputs{}
|
||||
require.Equal(t, StageWaitingForRegistration, inputs.assignToNext(StageInputRunnerName, "runner", cfg))
|
||||
// only the valid label survives
|
||||
require.Equal(t, []string{"ubuntu:host"}, inputs.Labels)
|
||||
require.Equal(t, []string{"ubuntu:host", "pool:e57e18d4"}, inputs.Labels)
|
||||
})
|
||||
|
||||
t.Run("blank labels input uses defaults", func(t *testing.T) {
|
||||
@@ -121,10 +122,16 @@ func TestRegisterInputsAssignToNext(t *testing.T) {
|
||||
|
||||
t.Run("invalid labels input loops back", func(t *testing.T) {
|
||||
inputs := ®isterInputs{}
|
||||
require.Equal(t, StageInputLabels, inputs.assignToNext(StageInputLabels, "ubuntu:vm:bad", emptyCfg))
|
||||
require.Equal(t, StageInputLabels, inputs.assignToNext(StageInputLabels, "ubuntu:host,,bad", emptyCfg))
|
||||
require.Nil(t, inputs.Labels)
|
||||
})
|
||||
|
||||
t.Run("labels containing a colon are accepted", func(t *testing.T) {
|
||||
inputs := ®isterInputs{}
|
||||
require.Equal(t, StageWaitingForRegistration, inputs.assignToNext(StageInputLabels, "pool:e57e18d4,ubuntu:host", emptyCfg))
|
||||
require.Equal(t, []string{"pool:e57e18d4", "ubuntu:host"}, inputs.Labels)
|
||||
})
|
||||
|
||||
t.Run("overwrite local config", func(t *testing.T) {
|
||||
inputs := ®isterInputs{}
|
||||
require.Equal(t, StageInputInstance, inputs.assignToNext(StageOverwriteLocalConfig, "Y", emptyCfg))
|
||||
|
||||
Reference in New Issue
Block a user