Beispiel #1
0
		private Int32 StartJobExecution()
		{
			Int32 ErrorCode = Constants.INVALID;
			try
			{
				string JobsFolder = Path.Combine( AgentApplication.Options.CacheFolder, "Jobs" );
				string JobSpecificFolder = Path.Combine( JobsFolder, "Job-" + JobGuid.ToString() );

				// Assert that the folders we need are there
				Debug.Assert( Directory.Exists( JobsFolder ) &&
							  Directory.Exists( JobSpecificFolder ) );

				// Copy all required files into the Job directory
				foreach( KeyValuePair<string, string> Pair in Specification.DependenciesOriginalNames )
				{
					string SrcFile = Path.Combine( AgentApplication.Options.CacheFolder, Pair.Key );
					string DestFile = Path.Combine( JobSpecificFolder, Pair.Value );

					// Before the file is copied into the job directory, security check
					bool bIsAuthorized = true;
					bool bNeedToCheckFile = ( Path.GetExtension( SrcFile ) == ".exe" ) ||
											( Path.GetExtension( SrcFile ) == ".dll" );

					// Microsoft redistributable binaries won't be signed by Epic, so allow them to slide
					if( Path.GetFileName( SrcFile ).StartsWith( "msvc", StringComparison.InvariantCultureIgnoreCase ) )
					{
						bNeedToCheckFile = false;
					}

					if( ( bNeedToCheckFile ) &&
						( Manager.Certificate != null ) )
					{
						// If the Agent is signed, then everything else must be signed as well.
						// Start off pessimistic
						bIsAuthorized = false;

						X509Certificate NextCertificate = null;
						try
						{
							NextCertificate = X509Certificate.CreateFromSignedFile( SrcFile );
						}
						catch( Exception )
						{
							// Any exception means that either the file isn't signed or has an invalid certificate
						}
						if( NextCertificate != null )
						{
							if( NextCertificate.Equals( Manager.Certificate ) )
							{
								bIsAuthorized = true;
							}
						}
					}
					if( bIsAuthorized )
					{
						File.Copy( SrcFile, DestFile, true );
					}
					else
					{
						Manager.Log( EVerbosityLevel.Informative, ELogColour.Red, "[Job] Failed to use file \"" + Pair.Key + "\" because of a security violation" );
					}
				}

				// Used to indicate the Job was started successfully
				bool JobStartedSuccessfully = false;

				// First determine if we're even supposed to start the executable
				EJobTaskFlags JobFlags = Specification.JobFlags;
				if( ( JobFlags & EJobTaskFlags.FLAG_MANUAL_START ) != 0 )
				{
					// User has asked to start the executable on their own (useful
					// for debugging). At connection time, we'll try to match the
					// full executable path name to establish the parent
					// connection. Simply update the state of the Job.
					JobStartedSuccessfully = true;
				}
				else
				{
					string OriginalExecutableName;
					if( Specification.DependenciesOriginalNames.TryGetValue( Specification.ExecutableName, out OriginalExecutableName ) )
					{
						string FullExecutableName = Path.Combine( JobSpecificFolder, OriginalExecutableName );

						Process TaskProcess = new Process();
						TaskProcess.StartInfo.FileName = FullExecutableName;
						TaskProcess.StartInfo.Arguments = Specification.Parameters;
						TaskProcess.StartInfo.WorkingDirectory = JobSpecificFolder;
						TaskProcess.StartInfo.CreateNoWindow = true;

						// Other properties worth looking into setting
						//   TaskProcess.StartInfo.RedirectStandardInput

						// Set up the redirect for output
						TaskProcess.StartInfo.UseShellExecute = false;
						TaskProcess.StartInfo.RedirectStandardOutput = true;
						TaskProcess.StartInfo.RedirectStandardError = true;
						TaskProcess.OutputDataReceived += new DataReceivedEventHandler( OutputReceivedDataEventHandler );
						TaskProcess.ErrorDataReceived += new DataReceivedEventHandler( ErrorReceivedDataEventHandler );

						// If not already set, set the number of allowed cores to use,
						// which should be respected by swarm-aware applications
						if( OwnerIsInstigator )
						{
							// Use local settings, if it's not already set
							if( !TaskProcess.StartInfo.EnvironmentVariables.ContainsKey( "Swarm_MaxCores" ) )
							{
								TaskProcess.StartInfo.EnvironmentVariables.Add( "Swarm_MaxCores", AgentApplication.DeveloperOptions.LocalJobsDefaultProcessorCount.ToString() );
							}
						}
						else
						{
							// Use remote settings
							TaskProcess.StartInfo.EnvironmentVariables.Add( "Swarm_MaxCores", AgentApplication.DeveloperOptions.RemoteJobsDefaultProcessorCount.ToString() );
						}

						// Set up our exited callback
						TaskProcess.Exited += new EventHandler( ExitedProcessEventHandler );
						TaskProcess.EnableRaisingEvents = true;

						ProcessObject = TaskProcess;
						if( TaskProcess.Start() )
						{
							if( OwnerIsInstigator )
							{
								if( AgentApplication.Options.AvoidLocalExecution )
								{
									// If we're avoiding local execution, make it as non-invasive as possible
									TaskProcess.PriorityClass = ProcessPriorityClass.Idle;
								}
								else
								{
									// Use local settings
									TaskProcess.PriorityClass = ( ProcessPriorityClass )AgentApplication.DeveloperOptions.LocalJobsDefaultProcessPriority;
								}
							}
							else
							{
								// Use remote settings
								TaskProcess.PriorityClass = ( ProcessPriorityClass )AgentApplication.DeveloperOptions.RemoteJobsDefaultProcessPriority;
							}
							TaskProcess.BeginOutputReadLine();
							TaskProcess.BeginErrorReadLine();

							Manager.Log( EVerbosityLevel.Informative, ELogColour.Green, "[Job] Launched Job " + Specification.ExecutableName );
							Manager.Log( EVerbosityLevel.Informative, ELogColour.Green, "[Job]     PID is " + ProcessObject.Id.ToString() );
							Manager.Log( EVerbosityLevel.Informative, ELogColour.Green, "[Job]     GUID is \"" + JobGuid.ToString() + "\"" );

							// Success
							JobStartedSuccessfully = true;
						}
					}
					else
					{
						//@TODO: Error handling...
					}
				}

				// If the job was started successfully, however that may be, update
				// the state of the job
				if( JobStartedSuccessfully )
				{
					CurrentState = JobState.AGENT_JOB_RUNNING;
					StartTime = DateTime.UtcNow;
					ErrorCode = Constants.SUCCESS;
				}
				
				// Send a message indicating the Job has started, if this is the original owner
				if( ( OwnerIsInstigator ) &&
					( CurrentState == JobState.AGENT_JOB_RUNNING ) )
				{
					AgentJobState JobStartedMessage = new AgentJobState( JobGuid, EJobTaskState.STATE_RUNNING );
					Manager.SendMessageInternal( Owner, JobStartedMessage );

					// Also, if enabled, request that the agent window be brought
					// to the front, but only for the Instigator
					if (AgentApplication.Options.BringToFront && ((JobFlags & EJobTaskFlags.FLAG_MINIMIZED) == 0))
					{
						AgentApplication.ShowWindow = true;
					}
				}
			}
			catch( Exception Ex )
			{
				// Be sure to null out the process object if anything went wrong (usually starting the process)
				ProcessObject = null;

				Manager.Log( EVerbosityLevel.Critical, ELogColour.Red, "[StartJobExecution] Exception was: " + Ex.ToString() );
				ErrorCode = Constants.ERROR_EXCEPTION;
			}

			return ( ErrorCode );
		}
Beispiel #2
0
		private void SendJobCompletedMessage( AgentInfoMessage AdditionalInfoMessage )
		{
			// Only send a message back if we're the Instigator - remote workers don't have
			// enough information to make this determination
			Debug.Assert( OwnerIsInstigator );

			AgentJobState UpdatedStateMessage = null;
			if( CurrentSuccessState == JobSuccessState.AGENT_JOB_SUCCESS )
			{
				Manager.Log( EVerbosityLevel.Informative, ELogColour.Green, "[Job] " + AdditionalInfoMessage.TextMessage );
				UpdatedStateMessage = new AgentJobState( JobGuid, EJobTaskState.STATE_COMPLETE_SUCCESS );
			}
			else if( CurrentSuccessState == JobSuccessState.AGENT_JOB_FAILURE )
			{
				Manager.Log( EVerbosityLevel.Informative, ELogColour.Red, "[Job] " + AdditionalInfoMessage.TextMessage );
				UpdatedStateMessage = new AgentJobState( JobGuid, EJobTaskState.STATE_COMPLETE_FAILURE );
			}

			// Only if we have an actual update should we send one
			if( UpdatedStateMessage != null )
			{
				// Set the running time
				TimeSpan JobRunningTime = DateTime.UtcNow - StartTime;
				UpdatedStateMessage.JobRunningTime = JobRunningTime.TotalSeconds;

				// Set the exit code, if there is one
				UpdatedStateMessage.JobExitCode = ProcessObjectExitCode;

				// Send the actual message and the additional state message
				if( AdditionalInfoMessage != null )
				{
					Manager.SendMessageInternal( Owner, AdditionalInfoMessage );
				}
				Manager.SendMessageInternal( Owner, UpdatedStateMessage );
			}
		}