Refactor environment variables to configuration and registration (#90)
Close #21. Refactor environment variables to configuration file (config.yaml) and registration file (.runner). The old environment variables are still supported, but warning logs will be printed. Like: ```text $ GITEA_DEBUG=true ./act_runner -c config.yaml daemon INFO[0000] Starting runner daemon WARN[0000] env GITEA_DEBUG has been ignored because config file is used $ GITEA_DEBUG=true ./act_runner daemon INFO[0000] Starting runner daemon WARN[0000] env GITEA_DEBUG will be deprecated, please use config file instead ``` Reviewed-on: https://gitea.com/gitea/act_runner/pulls/90 Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
This commit is contained in:
parent
8eea12dd78
commit
7e7096e60b
20 changed files with 393 additions and 280 deletions
29
cmd/cmd.go
29
cmd/cmd.go
|
@ -5,23 +5,18 @@ package cmd
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"gitea.com/gitea/act_runner/config"
|
||||
)
|
||||
|
||||
// the version of act_runner
|
||||
var version = "develop"
|
||||
|
||||
type globalArgs struct {
|
||||
EnvFile string
|
||||
}
|
||||
|
||||
func Execute(ctx context.Context) {
|
||||
// task := runtime.NewTask("gitea", 0, nil, nil)
|
||||
|
||||
var gArgs globalArgs
|
||||
|
||||
// ./act_runner
|
||||
rootCmd := &cobra.Command{
|
||||
Use: "act_runner [event name to run]\nIf no event name passed, will default to \"on: push\"",
|
||||
|
@ -30,7 +25,8 @@ func Execute(ctx context.Context) {
|
|||
Version: version,
|
||||
SilenceUsage: true,
|
||||
}
|
||||
rootCmd.PersistentFlags().StringVarP(&gArgs.EnvFile, "env-file", "", ".env", "Read in a file of environment variables.")
|
||||
configFile := ""
|
||||
rootCmd.PersistentFlags().StringVarP(&configFile, "config", "c", "", "Config file path")
|
||||
|
||||
// ./act_runner register
|
||||
var regArgs registerArgs
|
||||
|
@ -38,11 +34,10 @@ func Execute(ctx context.Context) {
|
|||
Use: "register",
|
||||
Short: "Register a runner to the server",
|
||||
Args: cobra.MaximumNArgs(0),
|
||||
RunE: runRegister(ctx, ®Args, gArgs.EnvFile), // must use a pointer to regArgs
|
||||
RunE: runRegister(ctx, ®Args, &configFile), // must use a pointer to regArgs
|
||||
}
|
||||
registerCmd.Flags().BoolVar(®Args.NoInteractive, "no-interactive", false, "Disable interactive mode")
|
||||
registerCmd.Flags().StringVar(®Args.InstanceAddr, "instance", "", "Gitea instance address")
|
||||
registerCmd.Flags().BoolVar(®Args.Insecure, "insecure", false, "If check server's certificate if it's https protocol")
|
||||
registerCmd.Flags().StringVar(®Args.Token, "token", "", "Runner token")
|
||||
registerCmd.Flags().StringVar(®Args.RunnerName, "name", "", "Runner name")
|
||||
registerCmd.Flags().StringVar(®Args.Labels, "labels", "", "Runner tags, comma separated")
|
||||
|
@ -53,13 +48,23 @@ func Execute(ctx context.Context) {
|
|||
Use: "daemon",
|
||||
Short: "Run as a runner daemon",
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
RunE: runDaemon(ctx, gArgs.EnvFile),
|
||||
RunE: runDaemon(ctx, &configFile),
|
||||
}
|
||||
rootCmd.AddCommand(daemonCmd)
|
||||
|
||||
// ./act_runner exec
|
||||
rootCmd.AddCommand(loadExecCmd(ctx))
|
||||
|
||||
// ./act_runner config
|
||||
rootCmd.AddCommand(&cobra.Command{
|
||||
Use: "generate-config",
|
||||
Short: "Generate an example config file",
|
||||
Args: cobra.MaximumNArgs(0),
|
||||
Run: func(_ *cobra.Command, _ []string) {
|
||||
fmt.Printf("%s", config.Example)
|
||||
},
|
||||
})
|
||||
|
||||
// hide completion command
|
||||
rootCmd.CompletionOptions.HiddenDefaultCmd = true
|
||||
|
||||
|
|
|
@ -5,9 +5,9 @@ package cmd
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/mattn/go-isatty"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
|
@ -21,22 +21,28 @@ import (
|
|||
"gitea.com/gitea/act_runner/runtime"
|
||||
)
|
||||
|
||||
func runDaemon(ctx context.Context, envFile string) func(cmd *cobra.Command, args []string) error {
|
||||
func runDaemon(ctx context.Context, configFile *string) func(cmd *cobra.Command, args []string) error {
|
||||
return func(cmd *cobra.Command, args []string) error {
|
||||
log.Infoln("Starting runner daemon")
|
||||
|
||||
_ = godotenv.Load(envFile)
|
||||
cfg, err := config.FromEnviron()
|
||||
cfg, err := config.LoadDefault(*configFile)
|
||||
if err != nil {
|
||||
log.WithError(err).
|
||||
Fatalln("invalid configuration")
|
||||
return fmt.Errorf("invalid configuration: %w", err)
|
||||
}
|
||||
|
||||
initLogging(cfg)
|
||||
|
||||
reg, err := config.LoadRegistration(cfg.Runner.File)
|
||||
if os.IsNotExist(err) {
|
||||
log.Error("registration file not found, please register the runner first")
|
||||
return err
|
||||
} else if err != nil {
|
||||
return fmt.Errorf("failed to load registration file: %w", err)
|
||||
}
|
||||
|
||||
// require docker if a runner label uses a docker backend
|
||||
needsDocker := false
|
||||
for _, l := range cfg.Runner.Labels {
|
||||
for _, l := range reg.Labels {
|
||||
_, schema, _, _ := runtime.ParseLabel(l)
|
||||
if schema == "docker" {
|
||||
needsDocker = true
|
||||
|
@ -55,40 +61,40 @@ func runDaemon(ctx context.Context, envFile string) func(cmd *cobra.Command, arg
|
|||
var g errgroup.Group
|
||||
|
||||
cli := client.New(
|
||||
cfg.Client.Address,
|
||||
cfg.Client.Insecure,
|
||||
cfg.Runner.UUID,
|
||||
cfg.Runner.Token,
|
||||
reg.Address,
|
||||
cfg.Runner.Insecure,
|
||||
reg.UUID,
|
||||
reg.Token,
|
||||
version,
|
||||
)
|
||||
|
||||
runner := &runtime.Runner{
|
||||
Client: cli,
|
||||
Machine: cfg.Runner.Name,
|
||||
ForgeInstance: cfg.Client.Address,
|
||||
Environ: cfg.Runner.Environ,
|
||||
Labels: cfg.Runner.Labels,
|
||||
Machine: reg.Name,
|
||||
ForgeInstance: reg.Address,
|
||||
Environ: cfg.Runner.Envs,
|
||||
Labels: reg.Labels,
|
||||
Version: version,
|
||||
}
|
||||
|
||||
if handler, err := artifactcache.NewHandler(); err != nil {
|
||||
log.Errorf("cannot init cache server, it will be disabled: %v", err)
|
||||
} else {
|
||||
log.Infof("cache handler listens on: %v", handler.ExternalURL())
|
||||
runner.CacheHandler = handler
|
||||
if *cfg.Cache.Enabled {
|
||||
if handler, err := artifactcache.NewHandler(cfg.Cache.Dir, cfg.Cache.Host, cfg.Cache.Port); err != nil {
|
||||
log.Errorf("cannot init cache server, it will be disabled: %v", err)
|
||||
} else {
|
||||
log.Infof("cache handler listens on: %v", handler.ExternalURL())
|
||||
runner.CacheHandler = handler
|
||||
}
|
||||
}
|
||||
|
||||
poller := poller.New(
|
||||
cli,
|
||||
runner.Run,
|
||||
cfg.Runner.Capacity,
|
||||
cfg,
|
||||
)
|
||||
|
||||
g.Go(func() error {
|
||||
l := log.WithField("capacity", cfg.Runner.Capacity).
|
||||
WithField("endpoint", cfg.Client.Address).
|
||||
WithField("os", cfg.Platform.OS).
|
||||
WithField("arch", cfg.Platform.Arch)
|
||||
WithField("endpoint", reg.Address)
|
||||
l.Infoln("polling the remote server")
|
||||
|
||||
if err := poller.Poll(ctx); err != nil {
|
||||
|
@ -108,17 +114,22 @@ func runDaemon(ctx context.Context, envFile string) func(cmd *cobra.Command, arg
|
|||
}
|
||||
|
||||
// initLogging setup the global logrus logger.
|
||||
func initLogging(cfg config.Config) {
|
||||
func initLogging(cfg *config.Config) {
|
||||
isTerm := isatty.IsTerminal(os.Stdout.Fd())
|
||||
log.SetFormatter(&log.TextFormatter{
|
||||
DisableColors: !isTerm,
|
||||
FullTimestamp: true,
|
||||
})
|
||||
|
||||
if cfg.Debug {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
}
|
||||
if cfg.Trace {
|
||||
log.SetLevel(log.TraceLevel)
|
||||
if l := cfg.Log.Level; l != "" {
|
||||
level, err := log.ParseLevel(l)
|
||||
if err != nil {
|
||||
log.WithError(err).
|
||||
Errorf("invalid log level: %q", l)
|
||||
}
|
||||
if log.GetLevel() != level {
|
||||
log.Infof("log level changed to %v", level)
|
||||
log.SetLevel(level)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -348,7 +348,7 @@ func runExec(ctx context.Context, execArgs *executeArgs) func(cmd *cobra.Command
|
|||
}
|
||||
|
||||
// init a cache server
|
||||
handler, err := artifactcache.NewHandler()
|
||||
handler, err := artifactcache.NewHandler("", "", 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -14,20 +14,19 @@ import (
|
|||
"time"
|
||||
|
||||
pingv1 "code.gitea.io/actions-proto-go/ping/v1"
|
||||
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
|
||||
"github.com/bufbuild/connect-go"
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/mattn/go-isatty"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"gitea.com/gitea/act_runner/client"
|
||||
"gitea.com/gitea/act_runner/config"
|
||||
"gitea.com/gitea/act_runner/register"
|
||||
"gitea.com/gitea/act_runner/runtime"
|
||||
)
|
||||
|
||||
// runRegister registers a runner to the server
|
||||
func runRegister(ctx context.Context, regArgs *registerArgs, envFile string) func(*cobra.Command, []string) error {
|
||||
func runRegister(ctx context.Context, regArgs *registerArgs, configFile *string) func(*cobra.Command, []string) error {
|
||||
return func(cmd *cobra.Command, args []string) error {
|
||||
log.SetReportCaller(false)
|
||||
isTerm := isatty.IsTerminal(os.Stdout.Fd())
|
||||
|
@ -47,14 +46,13 @@ func runRegister(ctx context.Context, regArgs *registerArgs, envFile string) fun
|
|||
}
|
||||
|
||||
if regArgs.NoInteractive {
|
||||
if err := registerNoInteractive(envFile, regArgs); err != nil {
|
||||
if err := registerNoInteractive(*configFile, regArgs); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
go func() {
|
||||
if err := registerInteractive(envFile); err != nil {
|
||||
// log.Errorln(err)
|
||||
os.Exit(2)
|
||||
if err := registerInteractive(*configFile); err != nil {
|
||||
log.Fatal(err)
|
||||
return
|
||||
}
|
||||
os.Exit(0)
|
||||
|
@ -73,7 +71,6 @@ func runRegister(ctx context.Context, regArgs *registerArgs, envFile string) fun
|
|||
type registerArgs struct {
|
||||
NoInteractive bool
|
||||
InstanceAddr string
|
||||
Insecure bool
|
||||
Token string
|
||||
RunnerName string
|
||||
Labels string
|
||||
|
@ -101,7 +98,6 @@ var defaultLabels = []string{
|
|||
|
||||
type registerInputs struct {
|
||||
InstanceAddr string
|
||||
Insecure bool
|
||||
Token string
|
||||
RunnerName string
|
||||
CustomLabels []string
|
||||
|
@ -173,16 +169,17 @@ func (r *registerInputs) assignToNext(stage registerStage, value string) registe
|
|||
return StageUnknown
|
||||
}
|
||||
|
||||
func registerInteractive(envFile string) error {
|
||||
func registerInteractive(configFile string) error {
|
||||
var (
|
||||
reader = bufio.NewReader(os.Stdin)
|
||||
stage = StageInputInstance
|
||||
inputs = new(registerInputs)
|
||||
)
|
||||
|
||||
// check if overwrite local config
|
||||
_ = godotenv.Load(envFile)
|
||||
cfg, _ := config.FromEnviron()
|
||||
cfg, err := config.LoadDefault(configFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load config: %v", err)
|
||||
}
|
||||
if f, err := os.Stat(cfg.Runner.File); err == nil && !f.IsDir() {
|
||||
stage = StageOverwriteLocalConfig
|
||||
}
|
||||
|
@ -198,7 +195,7 @@ func registerInteractive(envFile string) error {
|
|||
|
||||
if stage == StageWaitingForRegistration {
|
||||
log.Infof("Registering runner, name=%s, instance=%s, labels=%v.", inputs.RunnerName, inputs.InstanceAddr, inputs.CustomLabels)
|
||||
if err := doRegister(&cfg, inputs); err != nil {
|
||||
if err := doRegister(cfg, inputs); err != nil {
|
||||
log.Errorf("Failed to register runner: %v", err)
|
||||
} else {
|
||||
log.Infof("Runner registered successfully.")
|
||||
|
@ -235,12 +232,13 @@ func printStageHelp(stage registerStage) {
|
|||
}
|
||||
}
|
||||
|
||||
func registerNoInteractive(envFile string, regArgs *registerArgs) error {
|
||||
_ = godotenv.Load(envFile)
|
||||
cfg, _ := config.FromEnviron()
|
||||
func registerNoInteractive(configFile string, regArgs *registerArgs) error {
|
||||
cfg, err := config.LoadDefault(configFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
inputs := ®isterInputs{
|
||||
InstanceAddr: regArgs.InstanceAddr,
|
||||
Insecure: regArgs.Insecure,
|
||||
Token: regArgs.Token,
|
||||
RunnerName: regArgs.RunnerName,
|
||||
CustomLabels: defaultLabels,
|
||||
|
@ -257,7 +255,7 @@ func registerNoInteractive(envFile string, regArgs *registerArgs) error {
|
|||
log.WithError(err).Errorf("Invalid input, please re-run act command.")
|
||||
return nil
|
||||
}
|
||||
if err := doRegister(&cfg, inputs); err != nil {
|
||||
if err := doRegister(cfg, inputs); err != nil {
|
||||
log.Errorf("Failed to register runner: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
@ -271,7 +269,7 @@ func doRegister(cfg *config.Config, inputs *registerInputs) error {
|
|||
// initial http client
|
||||
cli := client.New(
|
||||
inputs.InstanceAddr,
|
||||
inputs.Insecure,
|
||||
cfg.Runner.Insecure,
|
||||
"",
|
||||
"",
|
||||
version,
|
||||
|
@ -300,9 +298,36 @@ func doRegister(cfg *config.Config, inputs *registerInputs) error {
|
|||
}
|
||||
}
|
||||
|
||||
cfg.Runner.Name = inputs.RunnerName
|
||||
cfg.Runner.Token = inputs.Token
|
||||
cfg.Runner.Labels = inputs.CustomLabels
|
||||
_, err := register.New(cli).Register(ctx, cfg.Runner)
|
||||
return err
|
||||
reg := &config.Registration{
|
||||
Name: inputs.RunnerName,
|
||||
Token: inputs.Token,
|
||||
Address: inputs.InstanceAddr,
|
||||
Labels: inputs.CustomLabels,
|
||||
}
|
||||
|
||||
labels := make([]string, len(reg.Labels))
|
||||
for i, v := range reg.Labels {
|
||||
l, _, _, _ := runtime.ParseLabel(v)
|
||||
labels[i] = l
|
||||
}
|
||||
// register new runner.
|
||||
resp, err := cli.Register(ctx, connect.NewRequest(&runnerv1.RegisterRequest{
|
||||
Name: reg.Name,
|
||||
Token: reg.Token,
|
||||
AgentLabels: labels,
|
||||
}))
|
||||
if err != nil {
|
||||
log.WithError(err).Error("poller: cannot register new runner")
|
||||
return err
|
||||
}
|
||||
|
||||
reg.ID = resp.Msg.Runner.Id
|
||||
reg.UUID = resp.Msg.Runner.Uuid
|
||||
reg.Name = resp.Msg.Runner.Name
|
||||
reg.Token = resp.Msg.Runner.Token
|
||||
|
||||
if err := config.SaveRegistration(cfg.Runner.File, reg); err != nil {
|
||||
return fmt.Errorf("failed to save runner config: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue