commands/wrapper.go (84 lines of code) (raw):
package commands
import (
"context"
"errors"
"fmt"
"net"
"net/url"
"os"
"os/signal"
"syscall"
"time"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
"gitlab.com/gitlab-org/gitlab-runner/common"
"gitlab.com/gitlab-org/gitlab-runner/helpers/runner_wrapper"
"gitlab.com/gitlab-org/gitlab-runner/helpers/runner_wrapper/api/server"
)
const (
defaultWrapperGRPCListen = "tcp://localhost:7777"
)
var (
errFailedToParseGRPCAddress = errors.New("failed to parse grpc-listen address")
errUnsupportedGRPCAddressScheme = errors.New("unsupported grpc-listen address scheme")
)
type logHook struct{}
func (h *logHook) Levels() []logrus.Level {
return logrus.AllLevels
}
func (h *logHook) Fire(e *logrus.Entry) error {
e.Message = "[WRAPPER] " + e.Message
return nil
}
type RunnerWrapperCommand struct {
GRPCListen string `long:"grpc-listen"`
ProcessTerminationTimeout time.Duration `long:"process-termination-timeout"`
}
func (c *RunnerWrapperCommand) Execute(cctx *cli.Context) {
logrus.AddHook(new(logHook))
log := logrus.WithField("wrapper", true)
grpcLog := log.WithField("grpc-listen-addr", c.GRPCListen)
path, err := os.Executable()
if err != nil {
log.WithError(err).Fatal("Failed to get executable path")
}
l, err := c.createListener()
if err != nil {
grpcLog.WithError(err).Fatal("Failed to create listener")
}
ctx, cancelFn := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT)
defer cancelFn()
w := runner_wrapper.New(log, path, cctx.Args())
w.SetTerminationTimeout(c.ProcessTerminationTimeout)
srv := server.New(grpcLog, w)
go srv.Listen(l)
err = w.Run(ctx)
if err != nil {
log.WithError(err).Fatal("Failed while executing wrapped command")
}
srv.Stop()
log.Info("All wrapper tasks finished. See you!")
}
func (c *RunnerWrapperCommand) createListener() (net.Listener, error) {
uri, err := url.ParseRequestURI(c.GRPCListen)
if err != nil {
return nil, fmt.Errorf("%w: %v", errFailedToParseGRPCAddress, err)
}
switch uri.Scheme {
case "unix":
return net.Listen("unix", uri.Path)
case "tcp":
return net.Listen("tcp", uri.Host)
default:
return nil, fmt.Errorf("%w: %s", errUnsupportedGRPCAddressScheme, uri.Scheme)
}
}
func init() {
common.RegisterCommand2(
"wrapper", "start multi runner service wrapped with gRPC manager server",
&RunnerWrapperCommand{
GRPCListen: defaultWrapperGRPCListen,
ProcessTerminationTimeout: runner_wrapper.DefaultTerminationTimeout,
},
)
}