Skip to content

Commit 8228751

Browse files
authored
Support changing labels of Actions runner without re-registration (#24806)
close #24540 related: - Protocol: https://gitea.com/gitea/actions-proto-def/pulls/9 - Runner side: https://gitea.com/gitea/act_runner/pulls/201 changes: - Add column of `labels` to table `action_runner`, and combine the value of `agent_labels` and `custom_labels` column to `labels` column. - Store `labels` when registering `act_runner`. - Update `labels` when `act_runner` starting and calling `Declare`. - Users cannot modify the `custom labels` in edit page any more. other changes: - Store `version` when registering `act_runner`. - If runner is latest version, parse version from `Declare`. But older version runner still parse version from request header.
1 parent 6bbccdd commit 8228751

File tree

15 files changed

+113
-63
lines changed

15 files changed

+113
-63
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ module code.gitea.io/gitea
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.2
88
code.gitea.io/sdk/gitea v0.15.1
99
codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
4040
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
4141
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
4242
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
43-
code.gitea.io/actions-proto-go v0.2.1 h1:ToMN/8thz2q10TuCq8dL2d8mI+/pWpJcHCvG+TELwa0=
44-
code.gitea.io/actions-proto-go v0.2.1/go.mod h1:00ys5QDo1iHN1tHNvvddAcy2W/g+425hQya1cCSvq9A=
43+
code.gitea.io/actions-proto-go v0.3.0 h1:9Tvg8+TaaCXPKi6EnWl9vVgs2VZsj1Cs5afnsHa4AmM=
44+
code.gitea.io/actions-proto-go v0.3.0/go.mod h1:00ys5QDo1iHN1tHNvvddAcy2W/g+425hQya1cCSvq9A=
4545
code.gitea.io/gitea-vet v0.2.1/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE=
4646
code.gitea.io/gitea-vet v0.2.2 h1:TEOV/Glf38iGmKzKP0EB++Z5OSL4zGg3RrAvlwaMuvk=
4747
code.gitea.io/gitea-vet v0.2.2/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE=

models/actions/runner.go

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,8 @@ type ActionRunner struct {
4343
LastOnline timeutil.TimeStamp `xorm:"index"`
4444
LastActive timeutil.TimeStamp `xorm:"index"`
4545

46-
// Store OS and Artch.
47-
AgentLabels []string
48-
// Store custom labes use defined.
49-
CustomLabels []string
46+
// Store labels defined in state file (default: .runner file) of `act_runner`
47+
AgentLabels []string `xorm:"TEXT"`
5048

5149
Created timeutil.TimeStamp `xorm:"created"`
5250
Updated timeutil.TimeStamp `xorm:"updated"`
@@ -104,11 +102,6 @@ func (r *ActionRunner) IsOnline() bool {
104102
return false
105103
}
106104

107-
// AllLabels returns agent and custom labels
108-
func (r *ActionRunner) AllLabels() []string {
109-
return append(r.AgentLabels, r.CustomLabels...)
110-
}
111-
112105
// Editable checks if the runner is editable by the user
113106
func (r *ActionRunner) Editable(ownerID, repoID int64) bool {
114107
if ownerID == 0 && repoID == 0 {

models/actions/task.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -241,11 +241,9 @@ func CreateTaskForRunner(ctx context.Context, runner *ActionRunner) (*ActionTask
241241

242242
// TODO: a more efficient way to filter labels
243243
var job *ActionRunJob
244-
labels := runner.AgentLabels
245-
labels = append(labels, runner.CustomLabels...)
246-
log.Trace("runner labels: %v", labels)
244+
log.Trace("runner labels: %v", runner.AgentLabels)
247245
for _, v := range jobs {
248-
if isSubset(labels, v.RunsOn) {
246+
if isSubset(runner.AgentLabels, v.RunsOn) {
249247
job = v
250248
break
251249
}

models/migrations/migrations.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"code.gitea.io/gitea/models/migrations/v1_18"
2121
"code.gitea.io/gitea/models/migrations/v1_19"
2222
"code.gitea.io/gitea/models/migrations/v1_20"
23+
"code.gitea.io/gitea/models/migrations/v1_21"
2324
"code.gitea.io/gitea/models/migrations/v1_6"
2425
"code.gitea.io/gitea/models/migrations/v1_7"
2526
"code.gitea.io/gitea/models/migrations/v1_8"
@@ -497,6 +498,11 @@ var migrations = []Migration{
497498
NewMigration("Add PinOrder Column", v1_20.AddPinOrderToIssue),
498499
// v259 -> 260
499500
NewMigration("Convert scoped access tokens", v1_20.ConvertScopedAccessTokens),
501+
502+
// Gitea 1.21.0 ends at 260
503+
504+
// v260 -> v261
505+
NewMigration("Add label column to action_run table, and combine labels", v1_21.DropCustomLabelsColumnToActRunner),
500506
}
501507

502508
// GetCurrentDBVersion returns the current db version

models/migrations/v1_21/main_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2023 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package v1_21 //nolint
5+
6+
import (
7+
"testing"
8+
9+
"code.gitea.io/gitea/models/migrations/base"
10+
)
11+
12+
func TestMain(m *testing.M) {
13+
base.MainTest(m)
14+
}

models/migrations/v1_21/v260.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2023 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package v1_21 //nolint
5+
6+
import (
7+
"code.gitea.io/gitea/models/migrations/base"
8+
9+
"xorm.io/xorm"
10+
)
11+
12+
func DropCustomLabelsColumnToActRunner(x *xorm.Engine) error {
13+
sess := x.NewSession()
14+
defer sess.Close()
15+
16+
if err := sess.Begin(); err != nil {
17+
return err
18+
}
19+
20+
// drop "custom_labels" cols
21+
if err := base.DropTableColumns(sess, "action_runner", "custom_labels"); err != nil {
22+
return err
23+
}
24+
25+
return sess.Commit()
26+
}

options/locale/locale_en-US.ini

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3426,11 +3426,9 @@ runners.owner_type = Type
34263426
runners.description = Description
34273427
runners.labels = Labels
34283428
runners.last_online = Last Online Time
3429-
runners.agent_labels = Agent Labels
3430-
runners.custom_labels = Custom Labels
3431-
runners.custom_labels_helper = Custom labels are labels that are added manually by an administrator. A comma separates labels, whitespace at the start and end of each label is ignored.
34323429
runners.runner_title = Runner
34333430
runners.task_list = Recent tasks on this runner
3431+
runners.task_list.no_tasks = There is no task yet.
34343432
runners.task_list.run = Run
34353433
runners.task_list.status = Status
34363434
runners.task_list.repository = Repository

routers/api/actions/runner/interceptor.go

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,10 @@ import (
2121
)
2222

2323
const (
24-
uuidHeaderKey = "x-runner-uuid"
25-
tokenHeaderKey = "x-runner-token"
24+
uuidHeaderKey = "x-runner-uuid"
25+
tokenHeaderKey = "x-runner-token"
26+
// Deprecated: will be removed after Gitea 1.20 released.
2627
versionHeaderKey = "x-runner-version"
27-
28-
versionUnknown = "Unknown"
2928
)
3029

3130
var withRunner = connect.WithInterceptors(connect.UnaryInterceptorFunc(func(unaryFunc connect.UnaryFunc) connect.UnaryFunc {
@@ -36,11 +35,9 @@ var withRunner = connect.WithInterceptors(connect.UnaryInterceptorFunc(func(unar
3635
}
3736
uuid := request.Header().Get(uuidHeaderKey)
3837
token := request.Header().Get(tokenHeaderKey)
38+
// TODO: version will be removed from request header after Gitea 1.20 released.
39+
// And Gitea will not try to read version from reuqest header
3940
version := request.Header().Get(versionHeaderKey)
40-
if util.IsEmptyString(version) {
41-
version = versionUnknown
42-
}
43-
version, _ = util.SplitStringAtByteN(version, 64)
4441

4542
runner, err := actions_model.GetRunnerByUUID(ctx, uuid)
4643
if err != nil {
@@ -54,7 +51,11 @@ var withRunner = connect.WithInterceptors(connect.UnaryInterceptorFunc(func(unar
5451
}
5552

5653
cols := []string{"last_online"}
57-
if runner.Version != version {
54+
55+
// TODO: version will be removed from request header after Gitea 1.20 released.
56+
// And Gitea will not try to read version from reuqest header
57+
version, _ = util.SplitStringAtByteN(version, 64)
58+
if !util.IsEmptyString(version) && runner.Version != version {
5859
runner.Version = version
5960
cols = append(cols, "version")
6061
}

routers/api/actions/runner/runner.go

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,23 @@ func (s *Service) Register(
5454
return nil, errors.New("runner token has already been activated")
5555
}
5656

57+
labels := req.Msg.Labels
58+
// TODO: agent_labels should be removed from pb after Gitea 1.20 released.
59+
// Old version runner's agent_labels slice is not empty and labels slice is empty.
60+
// And due to compatibility with older versions, it is temporarily marked as Deprecated in pb, so use `//nolint` here.
61+
if len(req.Msg.AgentLabels) > 0 && len(req.Msg.Labels) == 0 { //nolint:staticcheck
62+
labels = req.Msg.AgentLabels //nolint:staticcheck
63+
}
64+
5765
// create new runner
5866
name, _ := util.SplitStringAtByteN(req.Msg.Name, 255)
5967
runner := &actions_model.ActionRunner{
60-
UUID: gouuid.New().String(),
61-
Name: name,
62-
OwnerID: runnerToken.OwnerID,
63-
RepoID: runnerToken.RepoID,
64-
AgentLabels: req.Msg.AgentLabels,
65-
CustomLabels: req.Msg.CustomLabels,
68+
UUID: gouuid.New().String(),
69+
Name: name,
70+
OwnerID: runnerToken.OwnerID,
71+
RepoID: runnerToken.RepoID,
72+
Version: req.Msg.Version,
73+
AgentLabels: labels,
6674
}
6775
if err := runner.GenerateToken(); err != nil {
6876
return nil, errors.New("can't generate token")
@@ -81,18 +89,41 @@ func (s *Service) Register(
8189

8290
res := connect.NewResponse(&runnerv1.RegisterResponse{
8391
Runner: &runnerv1.Runner{
84-
Id: runner.ID,
85-
Uuid: runner.UUID,
86-
Token: runner.Token,
87-
Name: runner.Name,
88-
AgentLabels: runner.AgentLabels,
89-
CustomLabels: runner.CustomLabels,
92+
Id: runner.ID,
93+
Uuid: runner.UUID,
94+
Token: runner.Token,
95+
Name: runner.Name,
96+
Version: runner.Version,
97+
Labels: runner.AgentLabels,
9098
},
9199
})
92100

93101
return res, nil
94102
}
95103

104+
func (s *Service) Declare(
105+
ctx context.Context,
106+
req *connect.Request[runnerv1.DeclareRequest],
107+
) (*connect.Response[runnerv1.DeclareResponse], error) {
108+
runner := GetRunner(ctx)
109+
runner.AgentLabels = req.Msg.Labels
110+
runner.Version = req.Msg.Version
111+
if err := actions_model.UpdateRunner(ctx, runner, "agent_labels", "version"); err != nil {
112+
return nil, status.Errorf(codes.Internal, "update runner: %v", err)
113+
}
114+
115+
return connect.NewResponse(&runnerv1.DeclareResponse{
116+
Runner: &runnerv1.Runner{
117+
Id: runner.ID,
118+
Uuid: runner.UUID,
119+
Token: runner.Token,
120+
Name: runner.Name,
121+
Version: runner.Version,
122+
Labels: runner.AgentLabels,
123+
},
124+
}), nil
125+
}
126+
96127
// FetchTask assigns a task to the runner
97128
func (s *Service) FetchTask(
98129
ctx context.Context,

0 commit comments

Comments
 (0)