Skip to content
Snippets Groups Projects
Select Git revision
  • main default protected
  • create-k8s-init-objects-dynamically-with-spec-patch
  • ajwalker/fix-depth
  • avonbertoldi/clean-up-ubi-images
  • 16-0-stable
  • update-and-cleanup-git-lfs-install
  • vshushlin/emply-runner-registration-token
  • fneill-move-troubleshooting-to-new-page
  • renovate/golang-1.x
  • renovate/alpine-3.x
  • 31047-don-t-use-docker-links-for-user-defined-networks
  • vshushlin/issue-templates
  • 16-1-stable
  • 16-2-stable
  • fix-job-log-collapsible-sections
  • ajwalker/upgrade-fleeting-latest
  • add-check-interval-metric
  • sh-fix-fips-shell-executor
  • avonbertoldi/29944/revisit-alpine-image-creation-2
  • kballon-main-patch-23985
  • v16.0.3
  • v16.2.1
  • v16.1.1
  • v16.2.0
  • v16.1.0
  • v16.0.2
  • v15.11.1
  • v16.0.1
  • v16.0.0
  • v15.11.0
  • v15.10.1
  • v15.10.0
  • v15.9.1
  • v15.9.0
  • v15.8.3
  • v15.8.2
  • v15.8.1
  • v15.7.4
  • v15.5.2
  • v15.8.0
40 results

service.go

Forked from GitLab.org / gitlab-runner
9707 commits behind the upstream repository.
  • Lorenzo Villani's avatar
    bdd47556
    Add error handling to `ServiceLogHook.Fire()` · bdd47556
    Lorenzo Villani authored
    `entry.String()` returns both the string representation of the log entry
    and a possible error. Before this patch we were sending both to the log
    writer, which accepts a varargs `interface{}` ending up with spurious
    `<nil>` lines in syslog.
    
    With this patch we try to get to the string representation and perform
    an early return in case of errors, then pass only the string to the
    underlying `service.Logger`.
    
    Ref #2453
    bdd47556
    History
    Add error handling to `ServiceLogHook.Fire()`
    Lorenzo Villani authored
    `entry.String()` returns both the string representation of the log entry
    and a possible error. Before this patch we were sending both to the log
    writer, which accepts a varargs `interface{}` ending up with spurious
    `<nil>` lines in syslog.
    
    With this patch we try to get to the string representation and perform
    an early return in case of errors, then pass only the string to the
    underlying `service.Logger`.
    
    Ref #2453
service.go 5.75 KiB
package commands

import (
	"fmt"
	"os"
	"runtime"

	"github.com/Sirupsen/logrus"
	"github.com/ayufan/golang-kardianos-service"
	"github.com/urfave/cli"
	"gitlab.com/gitlab-org/gitlab-runner/common"
	"gitlab.com/gitlab-org/gitlab-runner/helpers"
	"gitlab.com/gitlab-org/gitlab-runner/helpers/service"
)

const (
	defaultServiceName = "gitlab-runner"
	defaultDisplayName = "GitLab Runner"
	defaultDescription = "GitLab Runner"
)

type ServiceLogHook struct {
	service.Logger
	Level logrus.Level
}

func (s *ServiceLogHook) Levels() []logrus.Level {
	return []logrus.Level{
		logrus.PanicLevel,
		logrus.FatalLevel,
		logrus.ErrorLevel,
		logrus.WarnLevel,
		logrus.InfoLevel,
	}
}

func (s *ServiceLogHook) Fire(entry *logrus.Entry) error {
	if entry.Level > s.Level {
		return nil
	}

	msg, err := entry.String()
	if err != nil {
		return err
	}

	switch entry.Level {
	case logrus.PanicLevel, logrus.FatalLevel, logrus.ErrorLevel:
		s.Error(msg)
	case logrus.WarnLevel:
		s.Warning(msg)
	case logrus.InfoLevel:
		s.Info(msg)
	}

	return nil
}

type NullService struct {
}

func (n *NullService) Start(s service.Service) error {
	return nil
}

func (n *NullService) Stop(s service.Service) error {
	return nil
}

func runServiceInstall(s service.Service, c *cli.Context) error {
	if user := c.String("user"); user == "" && os.Getuid() == 0 {
		logrus.Fatal("Please specify user that will run gitlab-runner service")
	}

	if configFile := c.String("config"); configFile != "" {
		// try to load existing config
		config := common.NewConfig()
		err := config.LoadConfig(configFile)
		if err != nil {
			return err
		}

		// save config for the first time
		if !config.Loaded {
			err = config.SaveConfig(configFile)
			if err != nil {
				return err
			}
		}
	}
	return service.Control(s, "install")
}

func runServiceStatus(displayName string, s service.Service, c *cli.Context) error {
	err := s.Status()
	if err == nil {
		fmt.Println(displayName+":", "Service is running!")
	} else {
		fmt.Fprintln(os.Stderr, displayName+":", err)
		os.Exit(1)
	}
	return nil
}

func getServiceArguments(c *cli.Context) (arguments []string) {
	if wd := c.String("working-directory"); wd != "" {
		arguments = append(arguments, "--working-directory", wd)
	}

	if config := c.String("config"); config != "" {
		arguments = append(arguments, "--config", config)
	}

	if sn := c.String("service"); sn != "" {
		arguments = append(arguments, "--service", sn)
	}

	arguments = append(arguments, "--syslog")
	return
}

func createServiceConfig(c *cli.Context) (svcConfig *service.Config) {
	svcConfig = &service.Config{
		Name:        c.String("service"),
		DisplayName: c.String("service"),
		Description: defaultDescription,
		Arguments:   []string{"run"},
	}
	svcConfig.Arguments = append(svcConfig.Arguments, getServiceArguments(c)...)

	switch runtime.GOOS {
	case "linux":
		if os.Getuid() != 0 {
			logrus.Fatal("Please run the commands as root")
		}
		if user := c.String("user"); user != "" {
			svcConfig.Arguments = append(svcConfig.Arguments, "--user", user)
		}

	case "darwin":
		svcConfig.Option = service.KeyValue{
			"KeepAlive":   true,
			"RunAtLoad":   true,
			"UserService": os.Getuid() != 0,
		}

		if user := c.String("user"); user != "" {
			if os.Getuid() == 0 {
				svcConfig.Arguments = append(svcConfig.Arguments, "--user", user)
			} else {
				logrus.Fatalln("The --user is not supported for non-root users")
			}
		}

	case "windows":
		svcConfig.Option = service.KeyValue{
			"Password": c.String("password"),
		}
		svcConfig.UserName = c.String("user")
	}
	return
}

func RunServiceControl(c *cli.Context) {
	svcConfig := createServiceConfig(c)

	s, err := service_helpers.New(&NullService{}, svcConfig)
	if err != nil {
		logrus.Fatal(err)
	}

	switch c.Command.Name {
	case "install":
		err = runServiceInstall(s, c)
	case "status":
		err = runServiceStatus(svcConfig.DisplayName, s, c)
	default:
		err = service.Control(s, c.Command.Name)
	}

	if err != nil {
		logrus.Fatal(err)
	}
}

func init() {
	flags := []cli.Flag{
		cli.StringFlag{
			Name:  "service, n",
			Value: defaultServiceName,
			Usage: "Specify service name to use",
		},
	}

	installFlags := flags
	installFlags = append(installFlags, cli.StringFlag{
		Name:  "working-directory, d",
		Value: helpers.GetCurrentWorkingDirectory(),
		Usage: "Specify custom root directory where all data are stored",
	})
	installFlags = append(installFlags, cli.StringFlag{
		Name:  "config, c",
		Value: getDefaultConfigFile(),
		Usage: "Specify custom config file",
	})

	if runtime.GOOS == "windows" {
		installFlags = append(installFlags, cli.StringFlag{
			Name:  "user, u",
			Value: "",
			Usage: "Specify user-name to secure the runner",
		})
		installFlags = append(installFlags, cli.StringFlag{
			Name:  "password, p",
			Value: "",
			Usage: "Specify user password to install service (required)",
		})
	} else if os.Getuid() == 0 {
		installFlags = append(installFlags, cli.StringFlag{
			Name:  "user, u",
			Value: "",
			Usage: "Specify user-name to secure the runner",
		})
	}

	common.RegisterCommand(cli.Command{
		Name:   "install",
		Usage:  "install service",
		Action: RunServiceControl,
		Flags:  installFlags,
	})
	common.RegisterCommand(cli.Command{
		Name:   "uninstall",
		Usage:  "uninstall service",
		Action: RunServiceControl,
		Flags:  flags,
	})
	common.RegisterCommand(cli.Command{
		Name:   "start",
		Usage:  "start service",
		Action: RunServiceControl,
		Flags:  flags,
	})
	common.RegisterCommand(cli.Command{
		Name:   "stop",
		Usage:  "stop service",
		Action: RunServiceControl,
		Flags:  flags,
	})
	common.RegisterCommand(cli.Command{
		Name:   "restart",
		Usage:  "restart service",
		Action: RunServiceControl,
		Flags:  flags,
	})
	common.RegisterCommand(cli.Command{
		Name:   "status",
		Usage:  "get status of a service",
		Action: RunServiceControl,
		Flags:  flags,
	})
}