建立 Go Task Scheduler 协议骨架
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
// Package taskscheduler owns tasks fetched through Gitea's RunnerService and
|
||||
// dispatches them to an executor only after their identity is known.
|
||||
package taskscheduler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
runnerv1 "gitea.dev/actionslib/runner/v1"
|
||||
|
||||
"git.ddupan.top/panxiao81/gitea-dynamic-runner/internal/taskidentity"
|
||||
)
|
||||
|
||||
// Assignment is the immutable input handed to a Pod or VM provisioner.
|
||||
type Assignment struct {
|
||||
Task *runnerv1.Task
|
||||
Identity taskidentity.Identity
|
||||
}
|
||||
|
||||
// Dispatcher creates exactly one executor for an already assigned Gitea task.
|
||||
// It must not register another runner or ask Gitea for a task.
|
||||
type Dispatcher interface {
|
||||
Dispatch(context.Context, Assignment) error
|
||||
}
|
||||
|
||||
// Scheduler implements the TaskRunner boundary used by Gitea Runner's poller.
|
||||
type Scheduler struct {
|
||||
TrustDomain string
|
||||
Dispatcher Dispatcher
|
||||
}
|
||||
|
||||
// Run derives identity from the fetched task before provisioning its executor.
|
||||
func (s *Scheduler) Run(ctx context.Context, task *runnerv1.Task) error {
|
||||
if s.Dispatcher == nil {
|
||||
return errors.New("executor dispatcher is required")
|
||||
}
|
||||
identity, err := taskidentity.FromTask(task, s.TrustDomain)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.Dispatcher.Dispatch(ctx, Assignment{Task: task, Identity: identity})
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package taskscheduler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
runnerv1 "gitea.dev/actionslib/runner/v1"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
)
|
||||
|
||||
type recordingDispatcher struct {
|
||||
assignment Assignment
|
||||
}
|
||||
|
||||
func (d *recordingDispatcher) Dispatch(_ context.Context, assignment Assignment) error {
|
||||
d.assignment = assignment
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestRunDerivesIdentityBeforeDispatch(t *testing.T) {
|
||||
taskContext, err := structpb.NewStruct(map[string]any{
|
||||
"repository": "panxiao81/gitea-dynamic-runner",
|
||||
"job": "test",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
task := &runnerv1.Task{Id: 42, Context: taskContext}
|
||||
dispatcher := &recordingDispatcher{}
|
||||
scheduler := Scheduler{TrustDomain: "ddupan.top", Dispatcher: dispatcher}
|
||||
|
||||
if err := scheduler.Run(context.Background(), task); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if dispatcher.assignment.Task != task {
|
||||
t.Fatal("dispatcher did not receive the fetched task")
|
||||
}
|
||||
want := "spiffe://ddupan.top/ci/panxiao81/gitea-dynamic-runner/test"
|
||||
if dispatcher.assignment.Identity.SPIFFEID != want {
|
||||
t.Fatalf("SPIFFE ID = %q, want %q", dispatcher.assignment.Identity.SPIFFEID, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunRequiresDispatcher(t *testing.T) {
|
||||
scheduler := Scheduler{TrustDomain: "ddupan.top"}
|
||||
if err := scheduler.Run(context.Background(), &runnerv1.Task{}); err == nil {
|
||||
t.Fatal("expected missing dispatcher to fail")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user