act_runner/cmd/register.go

151 lines
3.4 KiB
Go

package cmd
import (
"bufio"
"context"
"os"
"os/signal"
"runtime"
"strings"
"github.com/mattn/go-isatty"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
// runRegister registers a runner to the server
func runRegister(ctx context.Context, regArgs *registerArgs) func(*cobra.Command, []string) error {
return func(cmd *cobra.Command, args []string) error {
log.SetReportCaller(false)
isTerm := isatty.IsTerminal(os.Stdout.Fd())
log.SetFormatter(&log.TextFormatter{
DisableColors: !isTerm,
DisableTimestamp: true,
})
log.Infof("Registering runner, arch=%s, os=%s, version=%s.",
runtime.GOARCH, runtime.GOOS, version)
// runner always needs root permission
if os.Getuid() != 0 {
// TODO: use a better way to check root permission
log.Warnf("Runner in user-mode.")
}
go func() {
if err := registerInteractive(); err != nil {
// log.Errorln(err)
os.Exit(2)
return
}
os.Exit(0)
}()
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
<-c
return nil
}
}
// registerArgs represents the arguments for register command
type registerArgs struct {
NoInteractive bool
InstanceAddr string
Token string
}
type registerStage int8
const (
StageUnknown registerStage = -1
StageInputInstance registerStage = iota + 1
StageInputToken
StageInputRunnerName
StageInputCustomLabels
StageWaitingForRegistration
)
type registerInputs struct {
InstanceAddr string
Token string
RunnerName string
CustomLabels []string
}
func (r *registerInputs) assignToNext(stage registerStage, value string) registerStage {
// must set instance address and token.
// if empty, keep current stage.
if stage == StageInputInstance || stage == StageInputToken {
if value == "" {
return stage
}
}
// set hostname for runner name if empty
if stage == StageInputRunnerName && value == "" {
value, _ = os.Hostname()
}
switch stage {
case StageInputInstance:
r.InstanceAddr = value
return StageInputToken
case StageInputToken:
r.Token = value
return StageInputRunnerName
case StageInputRunnerName:
r.RunnerName = value
return StageInputCustomLabels
case StageInputCustomLabels:
r.CustomLabels = strings.Split(value, ",")
return StageWaitingForRegistration
}
return StageUnknown
}
func registerInteractive() error {
var (
reader = bufio.NewReader(os.Stdin)
stage = StageInputInstance
inputs = new(registerInputs)
)
for {
printStageHelp(stage)
cmdString, err := reader.ReadString('\n')
if err != nil {
return err
}
stage = inputs.assignToNext(stage, strings.TrimSpace(cmdString))
if stage == StageWaitingForRegistration {
log.Infof("Registering runner, name=%s, instance=%s, labels=%v.", inputs.RunnerName, inputs.InstanceAddr, inputs.CustomLabels)
return nil
}
if stage <= StageUnknown {
log.Errorf("Invalid input, please re-run act command.")
return nil
}
}
}
func printStageHelp(stage registerStage) {
switch stage {
case StageInputInstance:
log.Infoln("Enter the Gitea instance URL (for example, https://gitea.com/):")
case StageInputToken:
log.Infoln("Enter the runner token:")
case StageInputRunnerName:
hostname, _ := os.Hostname()
log.Infof("Enter the runner name (if set empty, use hostname:%s ):\n", hostname)
case StageInputCustomLabels:
log.Infoln("Enter the runner custom labels (comma-separated, for example, label1,label2):")
case StageWaitingForRegistration:
log.Infoln("Waiting for registration...")
}
}