示例#1
0
// Run starts the caretakerd execution, every service and required resource.
// This is a blocking method.
func (instance *Execution) Run() (values.ExitCode, error) {
	autoStartableServices := instance.executable.Services().GetAllAutoStartable()
	// Start all non-master services first to start the master properly.
	for _, target := range autoStartableServices {
		if target.Config().Type != service.Master {
			instance.startAndLogProblemsIfNeeded(target)
		}
	}
	// Now start the master.
	masterStarted := false
	for _, target := range autoStartableServices {
		if target.Config().Type == service.Master {
			err := instance.Start(target)
			if err != nil {
				(*instance).masterError = err
			}
			masterStarted = true
		}
	}
	if !masterStarted {
		(*instance).masterError = errors.New("No master was started. There are no master configured?")
	}
	if (*instance).masterError != nil {
		instance.stopOthers()
	}
	instance.wg.Wait()
	exitCode := values.ExitCode(-1)
	if (*instance).masterExitCode != nil {
		exitCode = *(*instance).masterExitCode
	}
	return exitCode, (*instance).masterError
}
示例#2
0
func (instance *Execution) runCommand(cmd *exec.Cmd) (values.ExitCode, error) {
	var waitStatus syscall.WaitStatus
	if err := cmd.Run(); err != nil {
		if exitError, ok := err.(*exec.ExitError); ok {
			waitStatus = exitError.Sys().(syscall.WaitStatus)
			exitSignal := waitStatus.Signal()
			if exitSignal > 0 {
				return values.ExitCode(int(exitSignal) + 128), nil
			}
			return values.ExitCode(waitStatus.ExitStatus()), nil
		}
		return values.ExitCode(0), UnrecoverableError{error: err}
	}
	waitStatus = cmd.ProcessState.Sys().(syscall.WaitStatus)
	return values.ExitCode(waitStatus.ExitStatus()), nil
}
示例#3
0
// Run runs this execution.
// This method is a blocking method and could only be executed at this instance once.
func (instance *Execution) Run() (values.ExitCode, error) {
	err := instance.handleBeforeRun()
	if err != nil {
		return values.ExitCode(1), err
	}
	exitCode, err := instance.preExecution()
	if err != nil || exitCode != 0 {
		return exitCode, err
	}
	instance.logger.Log(logger.Debug, "Start service '%s' with command: %s", instance.Name(), instance.commandLineOf(instance.cmd))
	exitCode, lastState, err := instance.runBare()
	if lastState == Killed {
		err = StoppedOrKilledError{error: errors.New("Process was killed.")}
		instance.logger.Log(logger.Debug, "Service '%s' ended after kill: %d", instance.Name(), exitCode)
	} else if lastState == Stopped {
		err = StoppedOrKilledError{error: errors.New("Process was stopped.")}
		instance.logger.Log(logger.Debug, "Service '%s' ended successful after stop: %d", instance.Name(), exitCode)
	} else if err != nil {
		instance.logger.Log(logger.Fatal, err)
	} else if instance.service.config.SuccessExitCodes.Contains(exitCode) {
		instance.logger.Log(logger.Debug, "Service '%s' ended successful: %d", instance.Name(), exitCode)
	} else {
		instance.logger.Log(logger.Error, "Service '%s' ended with unexpected code: %d", instance.Name(), exitCode)
		err = errors.New("Unexpected error code %d generated by service '%s'", exitCode, instance.Name())
	}
	instance.postExecution()
	return exitCode, err
}
示例#4
0
func (instance *Execution) runBare() (values.ExitCode, Status, error) {
	if instance.doTrySetRunningState() {
		defer instance.doSetDownState()
		exitCode, err := instance.runCommand((*instance).cmd)
		// This little sleep is required because there is no guarantee anymore that every lock is
		// respected if the routines are interrupted.
		time.Sleep(5 * time.Millisecond)
		return exitCode, instance.getSyncedCurrentStatus(), err
	}
	return values.ExitCode(0), instance.getSyncedCurrentStatus(), UnrecoverableError{error: errors.New("Cannot run service. Already in status: %v", instance.status)}
}
示例#5
0
func (instance *Config) init() {
	(*instance).Logger = logger.NewConfig()
	(*instance).Command = []values.String{}
	(*instance).PreCommands = [][]values.String{}
	(*instance).PostCommands = [][]values.String{}
	(*instance).Type = AutoStart
	(*instance).CronExpression = NewCronExpression()
	(*instance).StartDelayInSeconds = values.NonNegativeInteger(0)
	(*instance).RestartDelayInSeconds = values.NonNegativeInteger(5)
	(*instance).SuccessExitCodes = values.ExitCodes{values.ExitCode(0)}
	(*instance).StopSignal = defaultStopSignal()
	(*instance).StopSignalTarget = values.ProcessGroup
	(*instance).StopCommand = []values.String{}
	(*instance).StopWaitInSeconds = values.NonNegativeInteger(30)
	(*instance).User = values.String("")
	(*instance).Environment = Environments{}
	(*instance).Directory = values.String("")
	(*instance).AutoRestart = values.OnFailures
	(*instance).InheritEnvironment = values.Boolean(true)
	(*instance).Access = access.NewNoneConfig()
}
示例#6
0
func (instance *Execution) preExecution() (values.ExitCode, error) {
	preCommands := instance.service.config.PreCommands
	for _, preCommand := range preCommands {
		command, handleErrors := instance.extractCommandProperties(preCommand)
		if len(command) > 0 {
			cmd := instance.generateCmd(command)
			instance.logger.Log(logger.Debug, "Execute pre command: %s", instance.commandLineOf(cmd))
			exitCode, err := instance.runCommand(cmd)
			if handleErrors {
				if err != nil {
					instance.logger.LogProblem(err, logger.Error, "Pre command failed.")
					return exitCode, err
				} else if exitCode != 0 {
					instance.logger.Log(logger.Error, "Pre command failed. Exit with unexpected exit code: %d", exitCode)
					return exitCode, err
				}
			}
		}
	}
	return values.ExitCode(0), nil
}