Skip to content

Commit 67b1363

Browse files
Support changing labels (#201)
Implement proposal: go-gitea/gitea#24540 Related: - Protocol: https://gitea.com/gitea/actions-proto-def/pulls/9 - Gitea side: go-gitea/gitea#24806 Co-authored-by: Jason Song <[email protected]> Reviewed-on: https://gitea.com/gitea/act_runner/pulls/201 Reviewed-by: Jason Song <[email protected]> Co-authored-by: sillyguodong <[email protected]> Co-committed-by: sillyguodong <[email protected]>
1 parent 946c41c commit 67b1363

File tree

12 files changed

+142
-25
lines changed

12 files changed

+142
-25
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ GO_PACKAGES_TO_VET ?= $(filter-out gitea.com/gitea/act_runner/internal/pkg/clien
7070

7171

7272
TAGS ?=
73-
LDFLAGS ?= -X "gitea.com/gitea/act_runner/internal/pkg/ver.version=$(RELASE_VERSION)"
73+
LDFLAGS ?= -X "gitea.com/gitea/act_runner/internal/pkg/ver.version=v$(RELASE_VERSION)"
7474

7575
all: build
7676

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ module gitea.com/gitea/act_runner
33
go 1.20
44

55
require (
6-
code.gitea.io/actions-proto-go v0.2.1
6+
code.gitea.io/actions-proto-go v0.3.0
77
code.gitea.io/gitea-vet v0.2.3-0.20230113022436-2b1561217fa5
88
github.com/avast/retry-go/v4 v4.3.1
99
github.com/bufbuild/connect-go v1.3.1

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
code.gitea.io/actions-proto-go v0.2.1 h1:ToMN/8thz2q10TuCq8dL2d8mI+/pWpJcHCvG+TELwa0=
2-
code.gitea.io/actions-proto-go v0.2.1/go.mod h1:00ys5QDo1iHN1tHNvvddAcy2W/g+425hQya1cCSvq9A=
1+
code.gitea.io/actions-proto-go v0.3.0 h1:9Tvg8+TaaCXPKi6EnWl9vVgs2VZsj1Cs5afnsHa4AmM=
2+
code.gitea.io/actions-proto-go v0.3.0/go.mod h1:00ys5QDo1iHN1tHNvvddAcy2W/g+425hQya1cCSvq9A=
33
code.gitea.io/gitea-vet v0.2.3-0.20230113022436-2b1561217fa5 h1:daBEK2GQeqGikJESctP5Cu1i33z5ztAD4kyQWiw185M=
44
code.gitea.io/gitea-vet v0.2.3-0.20230113022436-2b1561217fa5/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE=
55
gitea.com/gitea/act v0.245.2-0.20230606002131-6ce5c93cc815 h1:u4rHwJLJnH6mej1BjEc4iubwknVeJmRVq9xQP9cAMeQ=

internal/app/cmd/daemon.go

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"strconv"
1313
"strings"
1414

15+
"github.com/bufbuild/connect-go"
1516
"github.com/mattn/go-isatty"
1617
log "github.com/sirupsen/logrus"
1718
"github.com/spf13/cobra"
@@ -43,8 +44,13 @@ func runDaemon(ctx context.Context, configFile *string) func(cmd *cobra.Command,
4344
return fmt.Errorf("failed to load registration file: %w", err)
4445
}
4546

47+
lbls := reg.Labels
48+
if len(cfg.Runner.Labels) > 0 {
49+
lbls = cfg.Runner.Labels
50+
}
51+
4652
ls := labels.Labels{}
47-
for _, l := range reg.Labels {
53+
for _, l := range lbls {
4854
label, err := labels.Parse(l)
4955
if err != nil {
5056
log.WithError(err).Warnf("ignored invalid label %q", l)
@@ -71,6 +77,24 @@ func runDaemon(ctx context.Context, configFile *string) func(cmd *cobra.Command,
7177
)
7278

7379
runner := run.NewRunner(cfg, reg, cli)
80+
// declare the labels of the runner before fetching tasks
81+
resp, err := runner.Declare(ctx, ls.Names())
82+
if err != nil && connect.CodeOf(err) == connect.CodeUnimplemented {
83+
// Gitea instance is older version. skip declare step.
84+
log.Warn("Because the Gitea instance is an old version, skip declare labels and version.")
85+
} else if err != nil {
86+
log.WithError(err).Error("fail to invoke Declare")
87+
return err
88+
} else {
89+
log.Infof("runner: %s, with version: %s, with labels: %v, declare successfully",
90+
resp.Msg.Runner.Name, resp.Msg.Runner.Version, resp.Msg.Runner.Labels)
91+
// if declare successfully, override the labels in the.runner file with valid labels in the config file (if specified)
92+
reg.Labels = ls.ToStrings()
93+
if err := config.SaveRegistration(cfg.Runner.File, reg); err != nil {
94+
return fmt.Errorf("failed to save runner config: %w", err)
95+
}
96+
}
97+
7498
poller := poll.New(cfg, cli, runner)
7599

76100
poller.Poll(ctx)

internal/app/cmd/register.go

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ const (
8585
StageInputInstance
8686
StageInputToken
8787
StageInputRunnerName
88-
StageInputCustomLabels
88+
StageInputLabels
8989
StageWaitingForRegistration
9090
StageExit
9191
)
@@ -101,7 +101,7 @@ type registerInputs struct {
101101
InstanceAddr string
102102
Token string
103103
RunnerName string
104-
CustomLabels []string
104+
Labels []string
105105
}
106106

107107
func (r *registerInputs) validate() error {
@@ -111,8 +111,8 @@ func (r *registerInputs) validate() error {
111111
if r.Token == "" {
112112
return fmt.Errorf("token is empty")
113113
}
114-
if len(r.CustomLabels) > 0 {
115-
return validateLabels(r.CustomLabels)
114+
if len(r.Labels) > 0 {
115+
return validateLabels(r.Labels)
116116
}
117117
return nil
118118
}
@@ -126,7 +126,7 @@ func validateLabels(ls []string) error {
126126
return nil
127127
}
128128

129-
func (r *registerInputs) assignToNext(stage registerStage, value string) registerStage {
129+
func (r *registerInputs) assignToNext(stage registerStage, value string, cfg *config.Config) registerStage {
130130
// must set instance address and token.
131131
// if empty, keep current stage.
132132
if stage == StageInputInstance || stage == StageInputToken {
@@ -154,16 +154,33 @@ func (r *registerInputs) assignToNext(stage registerStage, value string) registe
154154
return StageInputRunnerName
155155
case StageInputRunnerName:
156156
r.RunnerName = value
157-
return StageInputCustomLabels
158-
case StageInputCustomLabels:
159-
r.CustomLabels = defaultLabels
157+
// if there are some labels configured in config file, skip input labels stage
158+
if len(cfg.Runner.Labels) > 0 {
159+
ls := make([]string, 0, len(cfg.Runner.Labels))
160+
for _, l := range cfg.Runner.Labels {
161+
_, err := labels.Parse(l)
162+
if err != nil {
163+
log.WithError(err).Warnf("ignored invalid label %q", l)
164+
continue
165+
}
166+
ls = append(ls, l)
167+
}
168+
if len(ls) == 0 {
169+
log.Warn("no valid labels configured in config file, runner may not be able to pick up jobs")
170+
}
171+
r.Labels = ls
172+
return StageWaitingForRegistration
173+
}
174+
return StageInputLabels
175+
case StageInputLabels:
176+
r.Labels = defaultLabels
160177
if value != "" {
161-
r.CustomLabels = strings.Split(value, ",")
178+
r.Labels = strings.Split(value, ",")
162179
}
163180

164-
if validateLabels(r.CustomLabels) != nil {
181+
if validateLabels(r.Labels) != nil {
165182
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,linux_arm:host)")
166-
return StageInputCustomLabels
183+
return StageInputLabels
167184
}
168185
return StageWaitingForRegistration
169186
}
@@ -192,10 +209,10 @@ func registerInteractive(configFile string) error {
192209
if err != nil {
193210
return err
194211
}
195-
stage = inputs.assignToNext(stage, strings.TrimSpace(cmdString))
212+
stage = inputs.assignToNext(stage, strings.TrimSpace(cmdString), cfg)
196213

197214
if stage == StageWaitingForRegistration {
198-
log.Infof("Registering runner, name=%s, instance=%s, labels=%v.", inputs.RunnerName, inputs.InstanceAddr, inputs.CustomLabels)
215+
log.Infof("Registering runner, name=%s, instance=%s, labels=%v.", inputs.RunnerName, inputs.InstanceAddr, inputs.Labels)
199216
if err := doRegister(cfg, inputs); err != nil {
200217
return fmt.Errorf("Failed to register runner: %w", err)
201218
} else {
@@ -226,7 +243,7 @@ func printStageHelp(stage registerStage) {
226243
case StageInputRunnerName:
227244
hostname, _ := os.Hostname()
228245
log.Infof("Enter the runner name (if set empty, use hostname: %s):\n", hostname)
229-
case StageInputCustomLabels:
246+
case StageInputLabels:
230247
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,linux_arm:host):")
231248
case StageWaitingForRegistration:
232249
log.Infoln("Waiting for registration...")
@@ -242,12 +259,21 @@ func registerNoInteractive(configFile string, regArgs *registerArgs) error {
242259
InstanceAddr: regArgs.InstanceAddr,
243260
Token: regArgs.Token,
244261
RunnerName: regArgs.RunnerName,
245-
CustomLabels: defaultLabels,
262+
Labels: defaultLabels,
246263
}
247264
regArgs.Labels = strings.TrimSpace(regArgs.Labels)
265+
// command line flag.
248266
if regArgs.Labels != "" {
249-
inputs.CustomLabels = strings.Split(regArgs.Labels, ",")
267+
inputs.Labels = strings.Split(regArgs.Labels, ",")
250268
}
269+
// specify labels in config file.
270+
if len(cfg.Runner.Labels) > 0 {
271+
if regArgs.Labels != "" {
272+
log.Warn("Labels from command will be ignored, use labels defined in config file.")
273+
}
274+
inputs.Labels = cfg.Runner.Labels
275+
}
276+
251277
if inputs.RunnerName == "" {
252278
inputs.RunnerName, _ = os.Hostname()
253279
log.Infof("Runner name is empty, use hostname '%s'.", inputs.RunnerName)
@@ -302,7 +328,7 @@ func doRegister(cfg *config.Config, inputs *registerInputs) error {
302328
Name: inputs.RunnerName,
303329
Token: inputs.Token,
304330
Address: inputs.InstanceAddr,
305-
Labels: inputs.CustomLabels,
331+
Labels: inputs.Labels,
306332
}
307333

308334
ls := make([]string, len(reg.Labels))
@@ -314,7 +340,9 @@ func doRegister(cfg *config.Config, inputs *registerInputs) error {
314340
resp, err := cli.Register(ctx, connect.NewRequest(&runnerv1.RegisterRequest{
315341
Name: reg.Name,
316342
Token: reg.Token,
317-
AgentLabels: ls,
343+
Version: ver.Version(),
344+
AgentLabels: ls, // Could be removed after Gitea 1.20
345+
Labels: ls,
318346
}))
319347
if err != nil {
320348
log.WithError(err).Error("poller: cannot register new runner")

internal/app/run/runner.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"time"
1414

1515
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
16+
"github.com/bufbuild/connect-go"
1617
"github.com/docker/docker/api/types/container"
1718
"github.com/nektos/act/pkg/artifactcache"
1819
"github.com/nektos/act/pkg/common"
@@ -224,3 +225,10 @@ func parseDefaultActionsURLs(s string) []string {
224225
}
225226
return trimmed
226227
}
228+
229+
func (r *Runner) Declare(ctx context.Context, labels []string) (*connect.Response[runnerv1.DeclareResponse], error) {
230+
return r.client.Declare(ctx, connect.NewRequest(&runnerv1.DeclareRequest{
231+
Version: ver.Version(),
232+
Labels: labels,
233+
}))
234+
}

internal/pkg/client/header.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
package client
55

66
const (
7-
UUIDHeader = "x-runner-uuid"
8-
TokenHeader = "x-runner-token"
7+
UUIDHeader = "x-runner-uuid"
8+
TokenHeader = "x-runner-token"
9+
// Deprecated: could be removed after Gitea 1.20 released
910
VersionHeader = "x-runner-version"
1011
)

internal/pkg/client/http.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ func New(endpoint string, insecure bool, uuid, token, version string, opts ...co
3939
if token != "" {
4040
req.Header().Set(TokenHeader, token)
4141
}
42+
// TODO: version will be removed from request header after Gitea 1.20 released.
4243
if version != "" {
4344
req.Header().Set(VersionHeader, version)
4445
}

internal/pkg/client/mocks/Client.go

Lines changed: 26 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/pkg/config/config.example.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ runner:
2626
fetch_timeout: 5s
2727
# The interval for fetching the job from the Gitea instance.
2828
fetch_interval: 2s
29+
# The labels of a runner are used to determine which jobs the runner can run, and how to run them.
30+
# Like: ["macos-arm64:host", "ubuntu-latest:docker://node:16-bullseye", "ubuntu-22.04:docker://node:16-bullseye"]
31+
# If it's empty when registering, it will ask for inputting labels.
32+
# If it's empty when execute `deamon`, will use labels in `.runner` file.
33+
labels: []
2934

3035
cache:
3136
# Enable cache server to use actions/cache.

0 commit comments

Comments
 (0)