예제 #1
0
파일: agent.go 프로젝트: tychoish/evergreen
// New creates a new agent to run a given task.
func New(apiServerURL, taskId, taskSecret, logFile, cert, pidFilePath string) (*Agent, error) {
	sh := &SignalHandler{}
	sh.makeChannels()

	// set up communicator with API server
	httpCommunicator, err := comm.NewHTTPCommunicator(apiServerURL, taskId, taskSecret, cert, sh.communicatorChan)
	if err != nil {
		return nil, err
	}

	// set up logger to API server
	apiLogger := comm.NewAPILogger(httpCommunicator)
	idleTimeoutWatcher := comm.NewTimeoutWatcher(sh.stopBackgroundChan)
	idleTimeoutWatcher.SetDuration(DefaultIdleTimeout)

	// set up timeout logger, local and API logger streams
	streamLogger, err := comm.NewStreamLogger(idleTimeoutWatcher, apiLogger, logFile)
	if err != nil {
		return nil, err
	}
	httpCommunicator.Logger = streamLogger.Execution

	// set up the heartbeat ticker
	hbTicker := comm.NewHeartbeatTicker(sh.stopBackgroundChan)
	hbTicker.MaxFailedHeartbeats = 10
	hbTicker.SignalChan = sh.heartbeatChan
	hbTicker.TaskCommunicator = httpCommunicator
	hbTicker.Logger = httpCommunicator.Logger
	hbTicker.Interval = DefaultHeartbeatInterval

	// set up the system stats collector
	statsCollector := NewSimpleStatsCollector(
		streamLogger.System,
		DefaultStatsInterval,
		sh.stopBackgroundChan,
		"df -h",
		"${ps|ps}",
	)

	agt := &Agent{
		signalHandler:      sh,
		logger:             streamLogger,
		TaskCommunicator:   httpCommunicator,
		heartbeater:        hbTicker,
		statsCollector:     statsCollector,
		idleTimeoutWatcher: idleTimeoutWatcher,
		APILogger:          apiLogger,
		Registry:           plugin.NewSimpleRegistry(),
		KillChan:           make(chan bool),
		endChan:            make(chan *apimodels.TaskEndDetail, 1),
		pidFilePath:        pidFilePath,
	}

	return agt, nil
}
예제 #2
0
파일: agent.go 프로젝트: tychoish/evergreen
// RunTask manages the process of running a task. It returns a response
// indicating the end result of the task.
func (agt *Agent) RunTask() (*apimodels.TaskEndResponse, error) {
	agt.CheckIn(InitialSetupCommand, InitialSetupTimeout)

	agt.logger.LogLocal(slogger.INFO, "Local logger initialized.")
	agt.logger.LogTask(slogger.INFO, "Task logger initialized (agent revision: %v)", evergreen.BuildRevision)
	agt.logger.LogExecution(slogger.INFO, "Execution logger initialized.")
	agt.logger.LogSystem(slogger.INFO, "System logger initialized.")

	httpAgentComm, ok := agt.TaskCommunicator.(*comm.HTTPCommunicator)
	if ok && len(httpAgentComm.HttpsCert) == 0 {
		agt.logger.LogTask(slogger.WARN, "Running agent without a https certificate.")
	}

	taskConfig, err := agt.GetTaskConfig()
	if err != nil {
		agt.logger.LogExecution(slogger.ERROR, "Error fetching task configuration: %v", err)
		return nil, err
	}

	agt.logger.LogTask(slogger.INFO,
		"Starting task %v, execution %v.", taskConfig.Task.Id, taskConfig.Task.Execution)

	pt := taskConfig.Project.FindProjectTask(taskConfig.Task.DisplayName)
	if pt.ExecTimeoutSecs == 0 {
		// if unspecified in the project task and the project, use the default value
		if taskConfig.Project.ExecTimeoutSecs != 0 {
			pt.ExecTimeoutSecs = taskConfig.Project.ExecTimeoutSecs
		} else {
			pt.ExecTimeoutSecs = DefaultExecTimeoutSecs
		}
	}
	execTimeout := time.Duration(pt.ExecTimeoutSecs) * time.Second
	// Set master task timeout, only if included in the taskConfig
	if execTimeout != 0 {
		agt.maxExecTimeoutWatcher = comm.NewTimeoutWatcher(
			agt.signalHandler.stopBackgroundChan)
		agt.maxExecTimeoutWatcher.SetDuration(execTimeout)
	}

	agt.logger.LogExecution(slogger.INFO, "Fetching expansions for project %v...", taskConfig.Task.Project)
	expVars, err := agt.FetchExpansionVars()
	if err != nil {
		agt.logger.LogExecution(slogger.ERROR, "error fetching project expansion variables: %v", err)
		return nil, err
	}
	taskConfig.Expansions.Update(*expVars)
	agt.taskConfig = taskConfig

	// start the heartbeater, timeout watcher, system stats collector, and signal listener
	agt.StartBackgroundActions(agt.signalHandler)

	err = agt.createTaskDirectory(taskConfig)
	if err != nil {
		agt.signalHandler.directoryChan <- comm.DirectoryFailure
		return nil, err
	}
	taskConfig.Expansions.Put("workdir", taskConfig.WorkDir)

	// register plugins needed for execution
	if err = registerPlugins(agt.Registry, plugin.CommandPlugins, agt.logger); err != nil {
		agt.logger.LogExecution(slogger.ERROR, "error initializing agent plugins: %v", err)
		return agt.finishAndAwaitCleanup(evergreen.TaskFailed)
	}

	// notify API server that the task has been started.
	agt.logger.LogExecution(slogger.INFO, "Reporting task started.")
	if err = agt.Start(strconv.Itoa(os.Getpid())); err != nil {
		agt.logger.LogExecution(slogger.ERROR, "error marking task started: %v", err)
		return agt.finishAndAwaitCleanup(evergreen.TaskFailed)
	}

	if agt.taskConfig.Project.Pre != nil {
		agt.logger.LogExecution(slogger.INFO, "Running pre-task commands.")
		err = agt.RunCommands(agt.taskConfig.Project.Pre.List(), false, agt.callbackTimeoutSignal())
		if err != nil {
			agt.logger.LogExecution(slogger.ERROR, "Running pre-task script failed: %v", err)
		}
		agt.logger.LogExecution(slogger.INFO, "Finished running pre-task commands.")
	}

	return agt.RunTaskCommands()
}