Ejemplo n.º 1
0
// Run will execute the command in workingDir, by applying the expansions to
// the script and then invoking it with sh -c, and logging all of the command's
// stdout/stderr using the Logger.
// It will block until the command either finishes, or is aborted prematurely
// via the kill channel.
func (ac *AgentCommand) Run(workingDir string) error {
	ac.LogTask(slogger.INFO, "Running script task for command \n%v in directory %v", ac.ScriptLine, workingDir)

	logWriterInfo := &evergreen.LoggingWriter{ac.Task, slogger.INFO}
	logWriterErr := &evergreen.LoggingWriter{ac.Task, slogger.ERROR}

	ignoreErrors := false
	if strings.HasPrefix(ac.ScriptLine, "-") {
		ac.ScriptLine = ac.ScriptLine[1:]
		ignoreErrors = true
	}

	outBufferWriter := util.NewLineBufferingWriter(logWriterInfo)
	errorBufferWriter := util.NewLineBufferingWriter(logWriterErr)
	defer outBufferWriter.Flush()
	defer errorBufferWriter.Flush()

	cmd := &command.LocalCommand{
		CmdString:        ac.ScriptLine,
		WorkingDirectory: workingDir,
		Stdout:           outBufferWriter,
		Stderr:           errorBufferWriter,
		Environment:      os.Environ(),
	}
	err := cmd.PrepToRun(ac.Expansions)
	if err != nil {
		ac.LogTask(slogger.ERROR, "Failed to prepare command: %v", err)
	}

	ac.LogTask(slogger.INFO, "Running command (expanded): %v", cmd.CmdString)

	doneStatus := make(chan error)
	go func() {
		err := cmd.Run()
		doneStatus <- err
	}()

	select {
	case err = <-doneStatus:
		if ignoreErrors {
			return nil
		} else {
			return err
		}
	case _ = <-ac.KillChan:
		// try and kill the process
		ac.LogExecution(slogger.INFO, "Got kill signal, stopping process: %v", cmd.Cmd.Process.Pid)
		if err := cmd.Stop(); err != nil {
			ac.LogExecution(slogger.ERROR, "Error occurred stopping process: %v", err)
		}
		return InterruptedCmdError
	}

	return err
}
Ejemplo n.º 2
0
// Execute starts the shell with its given parameters.
func (self *ShellExecCommand) Execute(pluginLogger plugin.Logger,
	pluginCom plugin.PluginCommunicator,
	conf *model.TaskConfig,
	stop chan bool) error {
	pluginLogger.LogExecution(slogger.DEBUG, "Preparing script...")

	logWriterInfo := pluginLogger.GetTaskLogWriter(slogger.INFO)
	logWriterErr := pluginLogger.GetTaskLogWriter(slogger.ERROR)

	outBufferWriter := util.NewLineBufferingWriter(logWriterInfo)
	errorBufferWriter := util.NewLineBufferingWriter(logWriterErr)
	defer outBufferWriter.Flush()
	defer errorBufferWriter.Flush()

	localCmd := &command.LocalCommand{
		CmdString:  self.Script,
		Stdout:     outBufferWriter,
		Stderr:     errorBufferWriter,
		ScriptMode: true,
	}

	if self.WorkingDir != "" {
		localCmd.WorkingDirectory = filepath.Join(conf.WorkDir, self.WorkingDir)
	} else {
		localCmd.WorkingDirectory = conf.WorkDir
	}

	err := localCmd.PrepToRun(conf.Expansions)
	if err != nil {
		return fmt.Errorf("Failed to apply expansions: %v", err)
	}
	if self.Silent {
		pluginLogger.LogExecution(slogger.INFO, "Executing script (source hidden)...")
	} else {
		pluginLogger.LogExecution(slogger.INFO, "Executing script: %v", localCmd.CmdString)
	}

	doneStatus := make(chan error)
	go func() {
		var err error
		env := os.Environ()
		env = append(env, fmt.Sprintf("EVR_TASK_ID=%v", conf.Task.Id))
		env = append(env, fmt.Sprintf("EVR_AGENT_PID=%v", os.Getpid()))
		localCmd.Environment = env
		err = localCmd.Start()
		if err == nil {
			pluginLogger.LogSystem(slogger.DEBUG, "spawned shell process with pid %v", localCmd.Cmd.Process.Pid)

			// Call the platform's process-tracking function. On some OSes this will be a noop,
			// on others this may need to do some additional work to track the process so that
			// it can be cleaned up later.
			if trackedTask != "" && trackedTask == conf.Task.Id {
				trackProcess(conf.Task.Id, localCmd.Cmd.Process.Pid, pluginLogger)
			}

			if !self.Background {
				err = localCmd.Cmd.Wait()
			}

		} else {
			pluginLogger.LogSystem(slogger.DEBUG, "error spawning shell process: %v", err)
		}
		doneStatus <- err
	}()

	defer pluginLogger.Flush()
	select {
	case err = <-doneStatus:
		if err != nil {
			if self.ContinueOnError {
				pluginLogger.LogExecution(slogger.INFO, "(ignoring) Script finished with error: %v", err)
				return nil
			} else {
				pluginLogger.LogExecution(slogger.INFO, "Script finished with error: %v", err)
				return err
			}
		} else {
			pluginLogger.LogExecution(slogger.INFO, "Script execution complete.")
		}
	case <-stop:
		pluginLogger.LogExecution(slogger.INFO, "Got kill signal")

		// need to check command has started
		if localCmd.Cmd != nil {
			pluginLogger.LogExecution(slogger.INFO, "Stopping process: %v", localCmd.Cmd.Process.Pid)

			// try and stop the process
			if err := localCmd.Stop(); err != nil {
				pluginLogger.LogExecution(slogger.ERROR, "Error occurred stopping process: %v", err)
			}
		}

		return fmt.Errorf("Shell command interrupted.")
	}

	return nil
}