chore(runner): remove client secret and add UUID in runner

Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
pull/2/head
Bo-Yi.Wu 2022-10-15 20:03:33 +08:00 committed by Jason Song
parent bf5e3dc302
commit e08495af09
9 changed files with 122 additions and 167 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
act_runner act_runner
.env .env
.runner

View File

@ -1,22 +1,19 @@
package client package client
import ( import (
"context"
"crypto/tls" "crypto/tls"
"net" "net"
"net/http" "net/http"
"time" "time"
"gitea.com/gitea/act_runner/core"
"gitea.com/gitea/proto-go/ping/v1/pingv1connect" "gitea.com/gitea/proto-go/ping/v1/pingv1connect"
"gitea.com/gitea/proto-go/runner/v1/runnerv1connect" "gitea.com/gitea/proto-go/runner/v1/runnerv1connect"
"github.com/bufbuild/connect-go"
"golang.org/x/net/http2" "golang.org/x/net/http2"
) )
// New returns a new runner client. // New returns a new runner client.
func New(endpoint, secret string, opts ...Option) *HTTPClient { func New(endpoint string, opts ...Option) *HTTPClient {
cfg := &config{} cfg := &config{}
// Loop through each option // Loop through each option
@ -25,15 +22,6 @@ func New(endpoint, secret string, opts ...Option) *HTTPClient {
opt.apply(cfg) opt.apply(cfg)
} }
interceptor := connect.UnaryInterceptorFunc(func(next connect.UnaryFunc) connect.UnaryFunc {
return func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) {
req.Header().Set(core.UUIDHeader, secret)
return next(ctx, req)
}
})
cfg.opts = append(cfg.opts, connect.WithInterceptors(interceptor))
if cfg.httpClient == nil { if cfg.httpClient == nil {
cfg.httpClient = &http.Client{ cfg.httpClient = &http.Client{
Timeout: 1 * time.Minute, Timeout: 1 * time.Minute,

View File

@ -1,8 +1,11 @@
package client package client
import ( import (
"context"
"net/http" "net/http"
"gitea.com/gitea/act_runner/core"
"github.com/bufbuild/connect-go" "github.com/bufbuild/connect-go"
) )
@ -56,3 +59,21 @@ func WithGRPCWeb(c bool) Option {
cfg.opts = append(cfg.opts, connect.WithGRPCWeb()) cfg.opts = append(cfg.opts, connect.WithGRPCWeb())
}) })
} }
// WithUUIDHeader add runner uuid in header
func WithUUIDHeader(uuid string) Option {
return OptionFunc(func(cfg *config) {
if uuid == "" {
return
}
cfg.opts = append(
cfg.opts,
connect.WithInterceptors(connect.UnaryInterceptorFunc(func(next connect.UnaryFunc) connect.UnaryFunc {
return func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) {
req.Header().Set(core.UUIDHeader, uuid)
return next(ctx, req)
}
})),
)
})
}

View File

@ -8,6 +8,7 @@ import (
"gitea.com/gitea/act_runner/config" "gitea.com/gitea/act_runner/config"
"gitea.com/gitea/act_runner/engine" "gitea.com/gitea/act_runner/engine"
"gitea.com/gitea/act_runner/poller" "gitea.com/gitea/act_runner/poller"
"gitea.com/gitea/act_runner/register"
"gitea.com/gitea/act_runner/runtime" "gitea.com/gitea/act_runner/runtime"
pingv1 "gitea.com/gitea/proto-go/ping/v1" pingv1 "gitea.com/gitea/proto-go/ping/v1"
runnerv1 "gitea.com/gitea/proto-go/runner/v1" runnerv1 "gitea.com/gitea/proto-go/runner/v1"
@ -32,15 +33,9 @@ func runDaemon(ctx context.Context, task *runtime.Task) func(cmd *cobra.Command,
initLogging(cfg) initLogging(cfg)
// try to connect to docker daemon // initial http client
// if failed, exit with error
if err := engine.Start(ctx); err != nil {
log.WithError(err).Fatalln("failed to connect docker daemon engine")
}
cli := client.New( cli := client.New(
cfg.Client.Address, cfg.Client.Address,
cfg.Client.Secret,
client.WithSkipVerify(cfg.Client.SkipVerify), client.WithSkipVerify(cfg.Client.SkipVerify),
client.WithGRPC(cfg.Client.GRPC), client.WithGRPC(cfg.Client.GRPC),
client.WithGRPCWeb(cfg.Client.GRPCWeb), client.WithGRPCWeb(cfg.Client.GRPCWeb),
@ -69,8 +64,42 @@ func runDaemon(ctx context.Context, task *runtime.Task) func(cmd *cobra.Command,
} }
} }
// register new runner
if cfg.Runner.UUID == "" {
register := register.New(
cli,
&client.Filter{
OS: cfg.Platform.OS,
Arch: cfg.Platform.Arch,
Labels: cfg.Runner.Labels,
},
)
data, err := register.Register(ctx, cfg.Runner)
if err != nil {
return err
}
if data.UUID != "" {
cfg.Runner.UUID = data.UUID
}
}
// try to connect to docker daemon
// if failed, exit with error
if err := engine.Start(ctx); err != nil {
log.WithError(err).Fatalln("failed to connect docker daemon engine")
}
var g errgroup.Group var g errgroup.Group
cli = client.New(
cfg.Client.Address,
client.WithSkipVerify(cfg.Client.SkipVerify),
client.WithGRPC(cfg.Client.GRPC),
client.WithGRPCWeb(cfg.Client.GRPCWeb),
client.WithUUIDHeader(cfg.Runner.UUID),
)
runner := &runtime.Runner{ runner := &runtime.Runner{
Client: cli, Client: cli,
Machine: cfg.Runner.Name, Machine: cfg.Runner.Name,
@ -80,11 +109,6 @@ func runDaemon(ctx context.Context, task *runtime.Task) func(cmd *cobra.Command,
poller := poller.New( poller := poller.New(
cli, cli,
runner.Run, runner.Run,
&client.Filter{
OS: cfg.Platform.OS,
Arch: cfg.Platform.Arch,
Labels: cfg.Runner.Labels,
},
) )
g.Go(func() error { g.Go(func() error {

View File

@ -1,88 +0,0 @@
package cmd
import (
"context"
"time"
"gitea.com/gitea/act_runner/client"
"gitea.com/gitea/act_runner/config"
"gitea.com/gitea/act_runner/poller"
"gitea.com/gitea/act_runner/runtime"
pingv1 "gitea.com/gitea/proto-go/ping/v1"
"github.com/bufbuild/connect-go"
"github.com/joho/godotenv"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
func runRegister(ctx context.Context, task *runtime.Task) func(cmd *cobra.Command, args []string) error {
return func(cmd *cobra.Command, args []string) error {
log.Infoln("Starting runner daemon")
_ = godotenv.Load(task.Input.EnvFile)
cfg, err := config.FromEnviron()
if err != nil {
log.WithError(err).
Fatalln("invalid configuration")
}
initLogging(cfg)
cli := client.New(
cfg.Client.Address,
cfg.Client.Secret,
client.WithSkipVerify(cfg.Client.SkipVerify),
client.WithGRPC(cfg.Client.GRPC),
client.WithGRPCWeb(cfg.Client.GRPCWeb),
)
for {
_, err := cli.Ping(ctx, connect.NewRequest(&pingv1.PingRequest{
Data: cfg.Runner.Name,
}))
select {
case <-ctx.Done():
return nil
default:
}
if ctx.Err() != nil {
break
}
if err != nil {
log.WithError(err).
Errorln("cannot ping the remote server")
// TODO: if ping failed, retry or exit
time.Sleep(time.Second)
} else {
log.Infoln("successfully connected the remote server")
break
}
}
runner := &runtime.Runner{
Client: cli,
Machine: cfg.Runner.Name,
Environ: cfg.Runner.Environ,
}
poller := poller.New(
cli,
runner.Run,
&client.Filter{
OS: cfg.Platform.OS,
Arch: cfg.Platform.Arch,
Labels: cfg.Runner.Labels,
},
)
// register new runner
if err := poller.Register(ctx, cfg.Runner); err != nil {
return err
}
log.Infoln("successfully registered new runner")
return nil
}
}

View File

@ -56,17 +56,8 @@ func Execute(ctx context.Context) {
Args: cobra.MaximumNArgs(1), Args: cobra.MaximumNArgs(1),
RunE: runDaemon(ctx, task), RunE: runDaemon(ctx, task),
} }
// ./act_runner daemon
registerCmd := &cobra.Command{
Aliases: []string{"register"},
Use: "register new runner",
Args: cobra.MaximumNArgs(1),
RunE: runRegister(ctx, task),
}
// add all command // add all command
rootCmd.AddCommand(daemonCmd, registerCmd) rootCmd.AddCommand(daemonCmd)
if err := rootCmd.Execute(); err != nil { if err := rootCmd.Execute(); err != nil {
os.Exit(1) os.Exit(1)

View File

@ -27,13 +27,13 @@ type (
Address string `ignored:"true"` Address string `ignored:"true"`
Proto string `envconfig:"GITEA_RPC_PROTO" default:"http"` Proto string `envconfig:"GITEA_RPC_PROTO" default:"http"`
Host string `envconfig:"GITEA_RPC_HOST"` Host string `envconfig:"GITEA_RPC_HOST"`
Secret string `envconfig:"GITEA_RPC_SECRET"`
SkipVerify bool `envconfig:"GITEA_RPC_SKIP_VERIFY"` SkipVerify bool `envconfig:"GITEA_RPC_SKIP_VERIFY"`
GRPC bool `envconfig:"GITEA_RPC_GRPC" default:"true"` GRPC bool `envconfig:"GITEA_RPC_GRPC" default:"true"`
GRPCWeb bool `envconfig:"GITEA_RPC_GRPC_WEB"` GRPCWeb bool `envconfig:"GITEA_RPC_GRPC_WEB"`
} }
Runner struct { Runner struct {
UUID string `ignored:"true"`
Name string `envconfig:"GITEA_RUNNER_NAME"` Name string `envconfig:"GITEA_RUNNER_NAME"`
Token string `envconfig:"GITEA_RUNNER_TOKEN" required:"true"` Token string `envconfig:"GITEA_RUNNER_TOKEN" required:"true"`
Capacity int `envconfig:"GITEA_RUNNER_CAPACITY" default:"1"` Capacity int `envconfig:"GITEA_RUNNER_CAPACITY" default:"1"`
@ -66,7 +66,7 @@ func FromEnviron() (Config, error) {
return cfg, err return cfg, err
} }
if runner.UUID != "" { if runner.UUID != "" {
cfg.Client.Secret = runner.UUID cfg.Runner.UUID = runner.UUID
} }
} }

View File

@ -2,17 +2,12 @@ package poller
import ( import (
"context" "context"
"encoding/json"
"errors" "errors"
"os"
"time" "time"
"gitea.com/gitea/act_runner/client" "gitea.com/gitea/act_runner/client"
"gitea.com/gitea/act_runner/config"
"gitea.com/gitea/act_runner/core"
runnerv1 "gitea.com/gitea/proto-go/runner/v1" runnerv1 "gitea.com/gitea/proto-go/runner/v1"
"github.com/appleboy/com/file"
"github.com/bufbuild/connect-go" "github.com/bufbuild/connect-go"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@ -27,10 +22,9 @@ var (
defaultLabels = []string{"self-hosted"} defaultLabels = []string{"self-hosted"}
) )
func New(cli client.Client, dispatch func(context.Context, *runnerv1.Task) error, filter *client.Filter) *Poller { func New(cli client.Client, dispatch func(context.Context, *runnerv1.Task) error) *Poller {
return &Poller{ return &Poller{
Client: cli, Client: cli,
Filter: filter,
Dispatch: dispatch, Dispatch: dispatch,
routineGroup: newRoutineGroup(), routineGroup: newRoutineGroup(),
} }
@ -45,41 +39,6 @@ type Poller struct {
errorRetryCounter int errorRetryCounter int
} }
func (p *Poller) Register(ctx context.Context, cfg config.Runner) error {
// check .runner config exist
if file.IsFile(cfg.File) {
return nil
}
// register new runner.
resp, err := p.Client.Register(ctx, connect.NewRequest(&runnerv1.RegisterRequest{
Name: cfg.Name,
Token: cfg.Token,
AgentLabels: append(defaultLabels, []string{p.Filter.OS, p.Filter.Arch}...),
CustomLabels: p.Filter.Labels,
}))
if err != nil {
log.WithError(err).Error("poller: cannot register new runner")
return err
}
data := &core.Runner{
ID: resp.Msg.Runner.Id,
UUID: resp.Msg.Runner.Uuid,
Name: resp.Msg.Runner.Name,
Token: resp.Msg.Runner.Token,
}
file, err := json.MarshalIndent(data, "", " ")
if err != nil {
log.WithError(err).Error("poller: cannot marshal the json input")
return err
}
// store runner config in .runner file
return os.WriteFile(cfg.File, file, 0o644)
}
func (p *Poller) Poll(ctx context.Context, n int) error { func (p *Poller) Poll(ctx context.Context, n int) error {
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
func(i int) { func(i int) {

59
register/register.go Normal file
View File

@ -0,0 +1,59 @@
package register
import (
"context"
"encoding/json"
"os"
"gitea.com/gitea/act_runner/client"
"gitea.com/gitea/act_runner/config"
"gitea.com/gitea/act_runner/core"
runnerv1 "gitea.com/gitea/proto-go/runner/v1"
"github.com/bufbuild/connect-go"
log "github.com/sirupsen/logrus"
)
var defaultLabels = []string{"self-hosted"}
func New(cli client.Client, filter *client.Filter) *Register {
return &Register{
Client: cli,
Filter: filter,
}
}
type Register struct {
Client client.Client
Filter *client.Filter
}
func (p *Register) Register(ctx context.Context, cfg config.Runner) (*core.Runner, error) {
// register new runner.
resp, err := p.Client.Register(ctx, connect.NewRequest(&runnerv1.RegisterRequest{
Name: cfg.Name,
Token: cfg.Token,
AgentLabels: append(defaultLabels, []string{p.Filter.OS, p.Filter.Arch}...),
CustomLabels: p.Filter.Labels,
}))
if err != nil {
log.WithError(err).Error("poller: cannot register new runner")
return nil, err
}
data := &core.Runner{
ID: resp.Msg.Runner.Id,
UUID: resp.Msg.Runner.Uuid,
Name: resp.Msg.Runner.Name,
Token: resp.Msg.Runner.Token,
}
file, err := json.MarshalIndent(data, "", " ")
if err != nil {
log.WithError(err).Error("poller: cannot marshal the json input")
return data, err
}
// store runner config in .runner file
return data, os.WriteFile(cfg.File, file, 0o644)
}