private void Add(HandlerData data) { if (data != null) { _all.Add(data); } }
public async Task RunAsync() { // Validate args. Trace.Entering(); ArgUtil.NotNull(ExecutionContext, nameof(ExecutionContext)); ArgUtil.NotNull(ExecutionContext.Variables, nameof(ExecutionContext.Variables)); ArgUtil.NotNull(Task, nameof(Task)); var taskManager = HostContext.GetService <ITaskManager>(); var handlerFactory = HostContext.GetService <IHandlerFactory>(); // Set the task id and display name variable. ExecutionContext.Variables.Set(Constants.Variables.Task.DisplayName, DisplayName); ExecutionContext.Variables.Set(WellKnownDistributedTaskVariables.TaskInstanceId, Task.Id.ToString("D")); ExecutionContext.Variables.Set(WellKnownDistributedTaskVariables.TaskDisplayName, DisplayName); ExecutionContext.Variables.Set(WellKnownDistributedTaskVariables.TaskInstanceName, Task.Name); // Load the task definition and choose the handler. // TODO: Add a try catch here to give a better error message. Definition definition = taskManager.Load(Task); ArgUtil.NotNull(definition, nameof(definition)); // Print out task metadata PrintTaskMetaData(definition); ExecutionData currentExecution = null; switch (Stage) { case JobRunStage.PreJob: currentExecution = definition.Data?.PreJobExecution; break; case JobRunStage.Main: currentExecution = definition.Data?.Execution; break; case JobRunStage.PostJob: currentExecution = definition.Data?.PostJobExecution; break; } ; if ((currentExecution?.All.Any(x => x is PowerShell3HandlerData)).Value && (currentExecution?.All.Any(x => x is PowerShellHandlerData && x.Platforms != null && x.Platforms.Contains("windows", StringComparer.OrdinalIgnoreCase))).Value) { // When task contains both PS and PS3 implementations, we will always prefer PS3 over PS regardless of the platform pinning. Trace.Info("Ignore platform pinning for legacy PowerShell execution handler."); var legacyPShandler = currentExecution?.All.Where(x => x is PowerShellHandlerData).FirstOrDefault(); legacyPShandler.Platforms = null; } HandlerData handlerData = currentExecution?.All .OrderBy(x => !x.PreferredOnCurrentPlatform()) // Sort true to false. .ThenBy(x => x.Priority) .FirstOrDefault(); if (handlerData == null) { #if OS_WINDOWS throw new Exception(StringUtil.Loc("SupportedTaskHandlerNotFoundWindows", $"{Constants.Agent.Platform}({Constants.Agent.PlatformArchitecture})")); #else throw new Exception(StringUtil.Loc("SupportedTaskHandlerNotFoundLinux")); #endif } Variables runtimeVariables = ExecutionContext.Variables; IStepHost stepHost = HostContext.CreateService <IDefaultStepHost>(); // Setup container stephost and the right runtime variables for running job inside container. if (ExecutionContext.Container != null) { if (handlerData is AgentPluginHandlerData) { // plugin handler always runs on the Host, the rumtime variables needs to the variable works on the Host, ex: file path variable System.DefaultWorkingDirectory Dictionary <string, VariableValue> variableCopy = new Dictionary <string, VariableValue>(StringComparer.OrdinalIgnoreCase); foreach (var publicVar in ExecutionContext.Variables.Public) { variableCopy[publicVar.Key] = new VariableValue(ExecutionContext.Container.TranslateToHostPath(publicVar.Value)); } foreach (var secretVar in ExecutionContext.Variables.Private) { variableCopy[secretVar.Key] = new VariableValue(ExecutionContext.Container.TranslateToHostPath(secretVar.Value), true); } List <string> expansionWarnings; runtimeVariables = new Variables(HostContext, variableCopy, out expansionWarnings); expansionWarnings?.ForEach(x => ExecutionContext.Warning(x)); } else if (handlerData is NodeHandlerData || handlerData is Node10HandlerData || handlerData is PowerShell3HandlerData) { // Only the node, node10, and powershell3 handlers support running inside container. // Make sure required container is already created. ArgUtil.NotNullOrEmpty(ExecutionContext.Container.ContainerId, nameof(ExecutionContext.Container.ContainerId)); var containerStepHost = HostContext.CreateService <IContainerStepHost>(); containerStepHost.Container = ExecutionContext.Container; stepHost = containerStepHost; } else { throw new NotSupportedException(String.Format("Task '{0}' is using legacy execution handler '{1}' which is not supported in container execution flow.", definition.Data.FriendlyName, handlerData.GetType().ToString())); } } // Load the default input values from the definition. Trace.Verbose("Loading default inputs."); var inputs = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); foreach (var input in (definition.Data?.Inputs ?? new TaskInputDefinition[0])) { string key = input?.Name?.Trim() ?? string.Empty; if (!string.IsNullOrEmpty(key)) { inputs[key] = input.DefaultValue?.Trim() ?? string.Empty; } } // Merge the instance inputs. Trace.Verbose("Loading instance inputs."); foreach (var input in (Task.Inputs as IEnumerable <KeyValuePair <string, string> > ?? new KeyValuePair <string, string> [0])) { string key = input.Key?.Trim() ?? string.Empty; if (!string.IsNullOrEmpty(key)) { inputs[key] = input.Value?.Trim() ?? string.Empty; } } // Expand the inputs. Trace.Verbose("Expanding inputs."); runtimeVariables.ExpandValues(target: inputs); VarUtil.ExpandEnvironmentVariables(HostContext, target: inputs); // Translate the server file path inputs to local paths. foreach (var input in definition.Data?.Inputs ?? new TaskInputDefinition[0]) { if (string.Equals(input.InputType, TaskInputType.FilePath, StringComparison.OrdinalIgnoreCase)) { Trace.Verbose($"Translating file path input '{input.Name}': '{inputs[input.Name]}'"); inputs[input.Name] = stepHost.ResolvePathForStepHost(TranslateFilePathInput(inputs[input.Name] ?? string.Empty)); Trace.Verbose($"Translated file path input '{input.Name}': '{inputs[input.Name]}'"); } } // Load the task environment. Trace.Verbose("Loading task environment."); var environment = new Dictionary <string, string>(VarUtil.EnvironmentVariableKeyComparer); foreach (var env in (Task.Environment ?? new Dictionary <string, string>(0))) { string key = env.Key?.Trim() ?? string.Empty; if (!string.IsNullOrEmpty(key)) { environment[key] = env.Value?.Trim() ?? string.Empty; } } // Expand the inputs. Trace.Verbose("Expanding task environment."); runtimeVariables.ExpandValues(target: environment); VarUtil.ExpandEnvironmentVariables(HostContext, target: environment); // Expand the handler inputs. Trace.Verbose("Expanding handler inputs."); VarUtil.ExpandValues(HostContext, source: inputs, target: handlerData.Inputs); runtimeVariables.ExpandValues(target: handlerData.Inputs); // Get each endpoint ID referenced by the task. var endpointIds = new List <Guid>(); foreach (var input in definition.Data?.Inputs ?? new TaskInputDefinition[0]) { if ((input.InputType ?? string.Empty).StartsWith("connectedService:", StringComparison.OrdinalIgnoreCase)) { string inputKey = input?.Name?.Trim() ?? string.Empty; string inputValue; if (!string.IsNullOrEmpty(inputKey) && inputs.TryGetValue(inputKey, out inputValue) && !string.IsNullOrEmpty(inputValue)) { foreach (string rawId in inputValue.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) { Guid parsedId; if (Guid.TryParse(rawId.Trim(), out parsedId) && parsedId != Guid.Empty) { endpointIds.Add(parsedId); } } } } } if (endpointIds.Count > 0 && (runtimeVariables.GetBoolean(WellKnownDistributedTaskVariables.RestrictSecrets) ?? false) && (runtimeVariables.GetBoolean(Microsoft.TeamFoundation.Build.WebApi.BuildVariables.IsFork) ?? false)) { ExecutionContext.Result = TaskResult.Skipped; ExecutionContext.ResultCode = $"References service endpoint. PRs from repository forks are not allowed to access secrets in the pipeline. For more information see https://go.microsoft.com/fwlink/?linkid=862029 "; return; } // Get the endpoints referenced by the task. var endpoints = (ExecutionContext.Endpoints ?? new List <ServiceEndpoint>(0)) .Join(inner: endpointIds, outerKeySelector: (ServiceEndpoint endpoint) => endpoint.Id, innerKeySelector: (Guid endpointId) => endpointId, resultSelector: (ServiceEndpoint endpoint, Guid endpointId) => endpoint) .ToList(); // Add the system endpoint. foreach (ServiceEndpoint endpoint in (ExecutionContext.Endpoints ?? new List <ServiceEndpoint>(0))) { if (string.Equals(endpoint.Name, WellKnownServiceEndpointNames.SystemVssConnection, StringComparison.OrdinalIgnoreCase)) { endpoints.Add(endpoint); break; } } // Get each secure file ID referenced by the task. var secureFileIds = new List <Guid>(); foreach (var input in definition.Data?.Inputs ?? new TaskInputDefinition[0]) { if (string.Equals(input.InputType ?? string.Empty, "secureFile", StringComparison.OrdinalIgnoreCase)) { string inputKey = input?.Name?.Trim() ?? string.Empty; string inputValue; if (!string.IsNullOrEmpty(inputKey) && inputs.TryGetValue(inputKey, out inputValue) && !string.IsNullOrEmpty(inputValue)) { foreach (string rawId in inputValue.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) { Guid parsedId; if (Guid.TryParse(rawId.Trim(), out parsedId) && parsedId != Guid.Empty) { secureFileIds.Add(parsedId); } } } } } if (secureFileIds.Count > 0 && (runtimeVariables.GetBoolean(WellKnownDistributedTaskVariables.RestrictSecrets) ?? false) && (runtimeVariables.GetBoolean(Microsoft.TeamFoundation.Build.WebApi.BuildVariables.IsFork) ?? false)) { ExecutionContext.Result = TaskResult.Skipped; ExecutionContext.ResultCode = $"References secure file. PRs from repository forks are not allowed to access secrets in the pipeline. For more information see https://go.microsoft.com/fwlink/?linkid=862029"; return; } // Get the endpoints referenced by the task. var secureFiles = (ExecutionContext.SecureFiles ?? new List <SecureFile>(0)) .Join(inner: secureFileIds, outerKeySelector: (SecureFile secureFile) => secureFile.Id, innerKeySelector: (Guid secureFileId) => secureFileId, resultSelector: (SecureFile secureFile, Guid secureFileId) => secureFile) .ToList(); // Set output variables. foreach (var outputVar in definition.Data?.OutputVariables ?? new OutputVariable[0]) { if (outputVar != null && !string.IsNullOrEmpty(outputVar.Name)) { ExecutionContext.OutputVariables.Add(outputVar.Name); } } // Create the handler. IHandler handler = handlerFactory.Create( ExecutionContext, Task.Reference, stepHost, endpoints, secureFiles, handlerData, inputs, environment, runtimeVariables, taskDirectory: definition.Directory); // Run the task. await handler.RunAsync(); }
public async Task RunAsync() { // Validate args. Trace.Entering(); ArgUtil.NotNull(ExecutionContext, nameof(ExecutionContext)); ArgUtil.NotNull(ExecutionContext.Variables, nameof(ExecutionContext.Variables)); ArgUtil.NotNull(TaskInstance, nameof(TaskInstance)); var taskManager = HostContext.GetService <ITaskManager>(); var handlerFactory = HostContext.GetService <IHandlerFactory>(); // Set the task display name variable. ExecutionContext.Variables.Set(Constants.Variables.Task.DisplayName, DisplayName); // Load the task definition and choose the handler. // TODO: Add a try catch here to give a better error message. Definition definition = taskManager.Load(TaskInstance); ArgUtil.NotNull(definition, nameof(definition)); // Print out task metadata PrintTaskMetaData(definition); ExecutionData currentExecution = null; switch (Stage) { case JobRunStage.PreJob: currentExecution = definition.Data?.PreJobExecution; break; case JobRunStage.Main: currentExecution = definition.Data?.Execution; break; case JobRunStage.PostJob: currentExecution = definition.Data?.PostJobExecution; break; } ; if ((currentExecution?.All.Any(x => x is PowerShell3HandlerData)).Value && (currentExecution?.All.Any(x => x is PowerShellHandlerData && x.Platforms != null && x.Platforms.Contains("windows", StringComparer.OrdinalIgnoreCase))).Value) { // When task contains both PS and PS3 implementations, we will always prefer PS3 over PS regardless of the platform pinning. Trace.Info("Ignore platform pinning for legacy PowerShell execution handler."); var legacyPShandler = currentExecution?.All.Where(x => x is PowerShellHandlerData).FirstOrDefault(); legacyPShandler.Platforms = null; } HandlerData handlerData = currentExecution?.All .OrderBy(x => !x.PreferredOnCurrentPlatform()) // Sort true to false. .ThenBy(x => x.Priority) .FirstOrDefault(); if (handlerData == null) { throw new Exception(StringUtil.Loc("SupportedTaskHandlerNotFound")); } // Load the default input values from the definition. Trace.Verbose("Loading default inputs."); var inputs = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); foreach (var input in (definition.Data?.Inputs ?? new TaskInputDefinition[0])) { string key = input?.Name?.Trim() ?? string.Empty; if (!string.IsNullOrEmpty(key)) { inputs[key] = input.DefaultValue?.Trim() ?? string.Empty; } } // Merge the instance inputs. Trace.Verbose("Loading instance inputs."); foreach (var input in (TaskInstance.Inputs as IEnumerable <KeyValuePair <string, string> > ?? new KeyValuePair <string, string> [0])) { string key = input.Key?.Trim() ?? string.Empty; if (!string.IsNullOrEmpty(key)) { inputs[key] = input.Value?.Trim() ?? string.Empty; } } // Expand the inputs. Trace.Verbose("Expanding inputs."); ExecutionContext.Variables.ExpandValues(target: inputs); VarUtil.ExpandEnvironmentVariables(HostContext, target: inputs); // Translate the server file path inputs to local paths. foreach (var input in definition.Data?.Inputs ?? new TaskInputDefinition[0]) { if (string.Equals(input.InputType, TaskInputType.FilePath, StringComparison.OrdinalIgnoreCase)) { Trace.Verbose($"Translating file path input '{input.Name}': '{inputs[input.Name]}'"); inputs[input.Name] = TranslateFilePathInput(inputs[input.Name] ?? string.Empty); Trace.Verbose($"Translated file path input '{input.Name}': '{inputs[input.Name]}'"); } } // Expand the handler inputs. Trace.Verbose("Expanding handler inputs."); VarUtil.ExpandValues(HostContext, source: inputs, target: handlerData.Inputs); ExecutionContext.Variables.ExpandValues(target: handlerData.Inputs); // Get each endpoint ID referenced by the task. var endpointIds = new List <Guid>(); foreach (var input in definition.Data?.Inputs ?? new TaskInputDefinition[0]) { if ((input.InputType ?? string.Empty).StartsWith("connectedService:", StringComparison.OrdinalIgnoreCase)) { string inputKey = input?.Name?.Trim() ?? string.Empty; string inputValue; if (!string.IsNullOrEmpty(inputKey) && inputs.TryGetValue(inputKey, out inputValue) && !string.IsNullOrEmpty(inputValue)) { foreach (string rawId in inputValue.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) { Guid parsedId; if (Guid.TryParse(rawId.Trim(), out parsedId) && parsedId != Guid.Empty) { endpointIds.Add(parsedId); } } } } } // Get the endpoints referenced by the task. var endpoints = (ExecutionContext.Endpoints ?? new List <ServiceEndpoint>(0)) .Join(inner: endpointIds, outerKeySelector: (ServiceEndpoint endpoint) => endpoint.Id, innerKeySelector: (Guid endpointId) => endpointId, resultSelector: (ServiceEndpoint endpoint, Guid endpointId) => endpoint) .ToList(); // Add the system endpoint. foreach (ServiceEndpoint endpoint in (ExecutionContext.Endpoints ?? new List <ServiceEndpoint>(0))) { if (string.Equals(endpoint.Name, ServiceEndpoints.SystemVssConnection, StringComparison.OrdinalIgnoreCase)) { endpoints.Add(endpoint); break; } } // TODO: Add secure file only referenced by the task. // Set output variables. foreach (var outputVar in definition.Data?.OutputVariables ?? new OutputVariable[0]) { if (outputVar != null && !string.IsNullOrEmpty(outputVar.Name)) { ExecutionContext.OutputVariables.Add(outputVar.Name); } } // Create the handler. IHandler handler = handlerFactory.Create( ExecutionContext, endpoints, handlerData, inputs, taskDirectory: definition.Directory, filePathInputRootDirectory: TranslateFilePathInput(string.Empty)); // Run the task. await handler.RunAsync(); }
public async Task RunAsync() { // Validate args. Trace.Entering(); ArgUtil.NotNull(ExecutionContext, nameof(ExecutionContext)); ArgUtil.NotNull(ExecutionContext.Variables, nameof(ExecutionContext.Variables)); ArgUtil.NotNull(Task, nameof(Task)); var taskManager = HostContext.GetService <ITaskManager>(); var handlerFactory = HostContext.GetService <IHandlerFactory>(); // Set the task id and display name variable. using (var scope = ExecutionContext.Variables.CreateScope()) { scope.Set(Constants.Variables.Task.DisplayName, DisplayName); scope.Set(WellKnownDistributedTaskVariables.TaskInstanceId, Task.Id.ToString("D")); scope.Set(WellKnownDistributedTaskVariables.TaskDisplayName, DisplayName); scope.Set(WellKnownDistributedTaskVariables.TaskInstanceName, Task.Name); // Load the task definition and choose the handler. // TODO: Add a try catch here to give a better error message. Definition definition = taskManager.Load(Task); ArgUtil.NotNull(definition, nameof(definition)); // Verify Signatures and Re-Extract Tasks if neccessary await VerifyTask(taskManager, definition); // Print out task metadata PrintTaskMetaData(definition); ExecutionData currentExecution = null; switch (Stage) { case JobRunStage.PreJob: currentExecution = definition.Data?.PreJobExecution; break; case JobRunStage.Main: currentExecution = definition.Data?.Execution; break; case JobRunStage.PostJob: currentExecution = definition.Data?.PostJobExecution; break; } ; HandlerData handlerData = GetHandlerData(ExecutionContext, currentExecution, PlatformUtil.HostOS); if (handlerData == null) { if (PlatformUtil.RunningOnWindows) { throw new InvalidOperationException(StringUtil.Loc("SupportedTaskHandlerNotFoundWindows", $"{PlatformUtil.HostOS}({PlatformUtil.HostArchitecture})")); } throw new InvalidOperationException(StringUtil.Loc("SupportedTaskHandlerNotFoundLinux")); } Trace.Info($"Handler data is of type {handlerData}"); Variables runtimeVariables = ExecutionContext.Variables; IStepHost stepHost = HostContext.CreateService <IDefaultStepHost>(); var stepTarget = ExecutionContext.StepTarget(); // Setup container stephost and the right runtime variables for running job inside container. if (stepTarget is ContainerInfo containerTarget) { if (Stage == JobRunStage.PostJob && AgentKnobs.SkipPostExeceutionIfTargetContainerStopped.GetValue(ExecutionContext).AsBoolean()) { try { // Check that the target container is still running, if not Skip task execution IDockerCommandManager dockerManager = HostContext.GetService <IDockerCommandManager>(); bool isContainerRunning = await dockerManager.IsContainerRunning(ExecutionContext, containerTarget.ContainerId); if (!isContainerRunning) { ExecutionContext.Result = TaskResult.Skipped; ExecutionContext.ResultCode = $"Target container - {containerTarget.ContainerName} has been stopped, task post-execution will be skipped"; return; } } catch (Exception ex) { ExecutionContext.Write(WellKnownTags.Warning, $"Failed to check container state for task post-execution. Exception: {ex}"); } } if (handlerData is AgentPluginHandlerData) { // plugin handler always runs on the Host, the runtime variables needs to the variable works on the Host, ex: file path variable System.DefaultWorkingDirectory Dictionary <string, VariableValue> variableCopy = new Dictionary <string, VariableValue>(StringComparer.OrdinalIgnoreCase); foreach (var publicVar in ExecutionContext.Variables.Public) { variableCopy[publicVar.Key] = new VariableValue(stepTarget.TranslateToHostPath(publicVar.Value)); } foreach (var secretVar in ExecutionContext.Variables.Private) { variableCopy[secretVar.Key] = new VariableValue(stepTarget.TranslateToHostPath(secretVar.Value), true); } List <string> expansionWarnings; runtimeVariables = new Variables(HostContext, variableCopy, out expansionWarnings); expansionWarnings?.ForEach(x => ExecutionContext.Warning(x)); } else if (handlerData is BaseNodeHandlerData || handlerData is PowerShell3HandlerData) { // Only the node, node10, and powershell3 handlers support running inside container. // Make sure required container is already created. ArgUtil.NotNullOrEmpty(containerTarget.ContainerId, nameof(containerTarget.ContainerId)); var containerStepHost = HostContext.CreateService <IContainerStepHost>(); containerStepHost.Container = containerTarget; stepHost = containerStepHost; } else { throw new NotSupportedException(String.Format("Task '{0}' is using legacy execution handler '{1}' which is not supported in container execution flow.", definition.Data.FriendlyName, handlerData.GetType().ToString())); } } // Load the default input values from the definition. Trace.Verbose("Loading default inputs."); var inputs = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); foreach (var input in (definition.Data?.Inputs ?? new TaskInputDefinition[0])) { string key = input?.Name?.Trim() ?? string.Empty; if (!string.IsNullOrEmpty(key)) { if (AgentKnobs.DisableInputTrimming.GetValue(ExecutionContext).AsBoolean()) { inputs[key] = input.DefaultValue ?? string.Empty; } else { inputs[key] = input.DefaultValue?.Trim() ?? string.Empty; } } } // Merge the instance inputs. Trace.Verbose("Loading instance inputs."); foreach (var input in (Task.Inputs as IEnumerable <KeyValuePair <string, string> > ?? new KeyValuePair <string, string> [0])) { string key = input.Key?.Trim() ?? string.Empty; if (!string.IsNullOrEmpty(key)) { if (AgentKnobs.DisableInputTrimming.GetValue(ExecutionContext).AsBoolean()) { inputs[key] = input.Value ?? string.Empty; } else { inputs[key] = input.Value?.Trim() ?? string.Empty; } } } // Expand the inputs. Trace.Verbose("Expanding inputs."); runtimeVariables.ExpandValues(target: inputs); // We need to verify inputs of the tasks that were injected by decorators, to check if they contain secrets, // for security reasons execution of tasks in this case should be skipped. // Target task inputs could be injected into the decorator's tasks if the decorator has post-task-tasks or pre-task-tasks targets, // such tasks will have names that start with __system_pretargettask_ or __system_posttargettask_. var taskDecoratorManager = HostContext.GetService <ITaskDecoratorManager>(); if (taskDecoratorManager.IsInjectedTaskForTarget(Task.Name) && taskDecoratorManager.IsInjectedInputsContainsSecrets(inputs, out var inputsWithSecrets)) { var inputsForReport = taskDecoratorManager.GenerateTaskResultMessage(inputsWithSecrets); ExecutionContext.Result = TaskResult.Skipped; ExecutionContext.ResultCode = StringUtil.Loc("SecretsAreNotAllowedInInjectedTaskInputs", inputsForReport); return; } VarUtil.ExpandEnvironmentVariables(HostContext, target: inputs); // Translate the server file path inputs to local paths. foreach (var input in definition.Data?.Inputs ?? new TaskInputDefinition[0]) { if (string.Equals(input.InputType, TaskInputType.FilePath, StringComparison.OrdinalIgnoreCase)) { Trace.Verbose($"Translating file path input '{input.Name}': '{inputs[input.Name]}'"); inputs[input.Name] = stepHost.ResolvePathForStepHost(TranslateFilePathInput(inputs[input.Name] ?? string.Empty)); Trace.Verbose($"Translated file path input '{input.Name}': '{inputs[input.Name]}'"); } } // Load the task environment. Trace.Verbose("Loading task environment."); var environment = new Dictionary <string, string>(VarUtil.EnvironmentVariableKeyComparer); foreach (var env in (Task.Environment ?? new Dictionary <string, string>(0))) { string key = env.Key?.Trim() ?? string.Empty; if (!string.IsNullOrEmpty(key)) { environment[key] = env.Value?.Trim() ?? string.Empty; } } // Expand the inputs. Trace.Verbose("Expanding task environment."); runtimeVariables.ExpandValues(target: environment); VarUtil.ExpandEnvironmentVariables(HostContext, target: environment); // Expand the handler inputs. Trace.Verbose("Expanding handler inputs."); VarUtil.ExpandValues(HostContext, source: inputs, target: handlerData.Inputs); runtimeVariables.ExpandValues(target: handlerData.Inputs); // Get each endpoint ID referenced by the task. var endpointIds = new List <Guid>(); foreach (var input in definition.Data?.Inputs ?? new TaskInputDefinition[0]) { if ((input.InputType ?? string.Empty).StartsWith("connectedService:", StringComparison.OrdinalIgnoreCase)) { string inputKey = input?.Name?.Trim() ?? string.Empty; string inputValue; if (!string.IsNullOrEmpty(inputKey) && inputs.TryGetValue(inputKey, out inputValue) && !string.IsNullOrEmpty(inputValue)) { foreach (string rawId in inputValue.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) { Guid parsedId; if (Guid.TryParse(rawId.Trim(), out parsedId) && parsedId != Guid.Empty) { endpointIds.Add(parsedId); } } } } } if (endpointIds.Count > 0 && (runtimeVariables.GetBoolean(WellKnownDistributedTaskVariables.RestrictSecrets) ?? false) && (runtimeVariables.GetBoolean(Microsoft.TeamFoundation.Build.WebApi.BuildVariables.IsFork) ?? false)) { ExecutionContext.Result = TaskResult.Skipped; ExecutionContext.ResultCode = $"References service endpoint. PRs from repository forks are not allowed to access secrets in the pipeline. For more information see https://go.microsoft.com/fwlink/?linkid=862029 "; return; } // Get the endpoints referenced by the task. var endpoints = (ExecutionContext.Endpoints ?? new List <ServiceEndpoint>(0)) .Join(inner: endpointIds, outerKeySelector: (ServiceEndpoint endpoint) => endpoint.Id, innerKeySelector: (Guid endpointId) => endpointId, resultSelector: (ServiceEndpoint endpoint, Guid endpointId) => endpoint) .ToList(); // Add the system endpoint. foreach (ServiceEndpoint endpoint in (ExecutionContext.Endpoints ?? new List <ServiceEndpoint>(0))) { if (string.Equals(endpoint.Name, WellKnownServiceEndpointNames.SystemVssConnection, StringComparison.OrdinalIgnoreCase)) { endpoints.Add(endpoint); break; } } // Get each secure file ID referenced by the task. var secureFileIds = new List <Guid>(); foreach (var input in definition.Data?.Inputs ?? new TaskInputDefinition[0]) { if (string.Equals(input.InputType ?? string.Empty, "secureFile", StringComparison.OrdinalIgnoreCase)) { string inputKey = input?.Name?.Trim() ?? string.Empty; string inputValue; if (!string.IsNullOrEmpty(inputKey) && inputs.TryGetValue(inputKey, out inputValue) && !string.IsNullOrEmpty(inputValue)) { foreach (string rawId in inputValue.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) { Guid parsedId; if (Guid.TryParse(rawId.Trim(), out parsedId) && parsedId != Guid.Empty) { secureFileIds.Add(parsedId); } } } } } if (secureFileIds.Count > 0 && (runtimeVariables.GetBoolean(WellKnownDistributedTaskVariables.RestrictSecrets) ?? false) && (runtimeVariables.GetBoolean(Microsoft.TeamFoundation.Build.WebApi.BuildVariables.IsFork) ?? false)) { ExecutionContext.Result = TaskResult.Skipped; ExecutionContext.ResultCode = $"References secure file. PRs from repository forks are not allowed to access secrets in the pipeline. For more information see https://go.microsoft.com/fwlink/?linkid=862029"; return; } // Get the endpoints referenced by the task. var secureFiles = (ExecutionContext.SecureFiles ?? new List <SecureFile>(0)) .Join(inner: secureFileIds, outerKeySelector: (SecureFile secureFile) => secureFile.Id, innerKeySelector: (Guid secureFileId) => secureFileId, resultSelector: (SecureFile secureFile, Guid secureFileId) => secureFile) .ToList(); // Set output variables. foreach (var outputVar in definition.Data?.OutputVariables ?? new OutputVariable[0]) { if (outputVar != null && !string.IsNullOrEmpty(outputVar.Name)) { ExecutionContext.OutputVariables.Add(outputVar.Name); } } // translate inputs inputs = inputs.ToDictionary(kvp => kvp.Key, kvp => ExecutionContext.TranslatePathForStepTarget(kvp.Value)); // Create the handler. IHandler handler = handlerFactory.Create( ExecutionContext, Task.Reference, stepHost, endpoints, secureFiles, handlerData, inputs, environment, runtimeVariables, taskDirectory: definition.Directory); // Run the task. int retryCount = this.Task.RetryCountOnTaskFailure; if (retryCount > 0) { if (retryCount > RetryCountOnTaskFailureLimit) { ExecutionContext.Warning(StringUtil.Loc("RetryCountLimitExceeded", RetryCountOnTaskFailureLimit, retryCount)); retryCount = RetryCountOnTaskFailureLimit; } RetryHelper rh = new RetryHelper(ExecutionContext, retryCount); await rh.RetryStep(async() => await handler.RunAsync(), RetryHelper.ExponentialDelay); } else { await handler.RunAsync(); } } }
public async Task RunAsync() { // Validate args. Trace.Entering(); ArgUtil.NotNull(ExecutionContext, nameof(ExecutionContext)); ArgUtil.NotNull(ExecutionContext.Variables, nameof(ExecutionContext.Variables)); ArgUtil.NotNull(Task, nameof(Task)); var taskManager = HostContext.GetService <ITaskManager>(); var handlerFactory = HostContext.GetService <IHandlerFactory>(); // Set the task id and display name variable. using (var scope = ExecutionContext.Variables.CreateScope()) { scope.Set(Constants.Variables.Task.DisplayName, DisplayName); scope.Set(WellKnownDistributedTaskVariables.TaskInstanceId, Task.Id.ToString("D")); scope.Set(WellKnownDistributedTaskVariables.TaskDisplayName, DisplayName); scope.Set(WellKnownDistributedTaskVariables.TaskInstanceName, Task.Name); // Load the task definition and choose the handler. // TODO: Add a try catch here to give a better error message. Definition definition = taskManager.Load(Task); ArgUtil.NotNull(definition, nameof(definition)); // Verify task signatures if a fingerprint is configured for the Agent. var configurationStore = HostContext.GetService <IConfigurationStore>(); AgentSettings settings = configurationStore.GetSettings(); SignatureVerificationMode verificationMode = SignatureVerificationMode.None; if (settings.SignatureVerification != null) { verificationMode = settings.SignatureVerification.Mode; } if (verificationMode != SignatureVerificationMode.None) { ISignatureService signatureService = HostContext.CreateService <ISignatureService>(); Boolean verificationSuccessful = await signatureService.VerifyAsync(definition, ExecutionContext.CancellationToken); if (verificationSuccessful) { ExecutionContext.Output(StringUtil.Loc("TaskSignatureVerificationSucceeeded")); // Only extract if it's not the checkout task. if (!String.IsNullOrEmpty(definition.ZipPath)) { taskManager.Extract(ExecutionContext, Task); } } else { String message = StringUtil.Loc("TaskSignatureVerificationFailed"); if (verificationMode == SignatureVerificationMode.Error) { throw new InvalidOperationException(message); } else { ExecutionContext.Warning(message); } } } // Print out task metadata PrintTaskMetaData(definition); ExecutionData currentExecution = null; switch (Stage) { case JobRunStage.PreJob: currentExecution = definition.Data?.PreJobExecution; break; case JobRunStage.Main: currentExecution = definition.Data?.Execution; break; case JobRunStage.PostJob: currentExecution = definition.Data?.PostJobExecution; break; } ; HandlerData handlerData = GetHandlerData(ExecutionContext, currentExecution, PlatformUtil.HostOS); if (handlerData == null) { if (PlatformUtil.RunningOnWindows) { throw new InvalidOperationException(StringUtil.Loc("SupportedTaskHandlerNotFoundWindows", $"{PlatformUtil.HostOS}({PlatformUtil.HostArchitecture})")); } throw new InvalidOperationException(StringUtil.Loc("SupportedTaskHandlerNotFoundLinux")); } Trace.Info($"Handler data is of type {handlerData}"); Variables runtimeVariables = ExecutionContext.Variables; IStepHost stepHost = HostContext.CreateService <IDefaultStepHost>(); var stepTarget = ExecutionContext.StepTarget(); // Setup container stephost and the right runtime variables for running job inside container. if (stepTarget is ContainerInfo containerTarget) { if (handlerData is AgentPluginHandlerData) { // plugin handler always runs on the Host, the runtime variables needs to the variable works on the Host, ex: file path variable System.DefaultWorkingDirectory Dictionary <string, VariableValue> variableCopy = new Dictionary <string, VariableValue>(StringComparer.OrdinalIgnoreCase); foreach (var publicVar in ExecutionContext.Variables.Public) { variableCopy[publicVar.Key] = new VariableValue(stepTarget.TranslateToHostPath(publicVar.Value)); } foreach (var secretVar in ExecutionContext.Variables.Private) { variableCopy[secretVar.Key] = new VariableValue(stepTarget.TranslateToHostPath(secretVar.Value), true); } List <string> expansionWarnings; runtimeVariables = new Variables(HostContext, variableCopy, out expansionWarnings); expansionWarnings?.ForEach(x => ExecutionContext.Warning(x)); } else if (handlerData is NodeHandlerData || handlerData is Node10HandlerData || handlerData is PowerShell3HandlerData) { // Only the node, node10, and powershell3 handlers support running inside container. // Make sure required container is already created. ArgUtil.NotNullOrEmpty(containerTarget.ContainerId, nameof(containerTarget.ContainerId)); var containerStepHost = HostContext.CreateService <IContainerStepHost>(); containerStepHost.Container = containerTarget; stepHost = containerStepHost; } else { throw new NotSupportedException(String.Format("Task '{0}' is using legacy execution handler '{1}' which is not supported in container execution flow.", definition.Data.FriendlyName, handlerData.GetType().ToString())); } } // Load the default input values from the definition. Trace.Verbose("Loading default inputs."); var inputs = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); foreach (var input in (definition.Data?.Inputs ?? new TaskInputDefinition[0])) { string key = input?.Name?.Trim() ?? string.Empty; if (!string.IsNullOrEmpty(key)) { inputs[key] = input.DefaultValue?.Trim() ?? string.Empty; } } // Merge the instance inputs. Trace.Verbose("Loading instance inputs."); foreach (var input in (Task.Inputs as IEnumerable <KeyValuePair <string, string> > ?? new KeyValuePair <string, string> [0])) { string key = input.Key?.Trim() ?? string.Empty; if (!string.IsNullOrEmpty(key)) { inputs[key] = input.Value?.Trim() ?? string.Empty; } } // Expand the inputs. Trace.Verbose("Expanding inputs."); runtimeVariables.ExpandValues(target: inputs); VarUtil.ExpandEnvironmentVariables(HostContext, target: inputs); // Translate the server file path inputs to local paths. foreach (var input in definition.Data?.Inputs ?? new TaskInputDefinition[0]) { if (string.Equals(input.InputType, TaskInputType.FilePath, StringComparison.OrdinalIgnoreCase)) { Trace.Verbose($"Translating file path input '{input.Name}': '{inputs[input.Name]}'"); inputs[input.Name] = stepHost.ResolvePathForStepHost(TranslateFilePathInput(inputs[input.Name] ?? string.Empty)); Trace.Verbose($"Translated file path input '{input.Name}': '{inputs[input.Name]}'"); } } // Load the task environment. Trace.Verbose("Loading task environment."); var environment = new Dictionary <string, string>(VarUtil.EnvironmentVariableKeyComparer); foreach (var env in (Task.Environment ?? new Dictionary <string, string>(0))) { string key = env.Key?.Trim() ?? string.Empty; if (!string.IsNullOrEmpty(key)) { environment[key] = env.Value?.Trim() ?? string.Empty; } } // Expand the inputs. Trace.Verbose("Expanding task environment."); runtimeVariables.ExpandValues(target: environment); VarUtil.ExpandEnvironmentVariables(HostContext, target: environment); // Expand the handler inputs. Trace.Verbose("Expanding handler inputs."); VarUtil.ExpandValues(HostContext, source: inputs, target: handlerData.Inputs); runtimeVariables.ExpandValues(target: handlerData.Inputs); // Get each endpoint ID referenced by the task. var endpointIds = new List <Guid>(); foreach (var input in definition.Data?.Inputs ?? new TaskInputDefinition[0]) { if ((input.InputType ?? string.Empty).StartsWith("connectedService:", StringComparison.OrdinalIgnoreCase)) { string inputKey = input?.Name?.Trim() ?? string.Empty; string inputValue; if (!string.IsNullOrEmpty(inputKey) && inputs.TryGetValue(inputKey, out inputValue) && !string.IsNullOrEmpty(inputValue)) { foreach (string rawId in inputValue.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) { Guid parsedId; if (Guid.TryParse(rawId.Trim(), out parsedId) && parsedId != Guid.Empty) { endpointIds.Add(parsedId); } } } } } if (endpointIds.Count > 0 && (runtimeVariables.GetBoolean(WellKnownDistributedTaskVariables.RestrictSecrets) ?? false) && (runtimeVariables.GetBoolean(Microsoft.TeamFoundation.Build.WebApi.BuildVariables.IsFork) ?? false)) { ExecutionContext.Result = TaskResult.Skipped; ExecutionContext.ResultCode = $"References service endpoint. PRs from repository forks are not allowed to access secrets in the pipeline. For more information see https://go.microsoft.com/fwlink/?linkid=862029 "; return; } // Get the endpoints referenced by the task. var endpoints = (ExecutionContext.Endpoints ?? new List <ServiceEndpoint>(0)) .Join(inner: endpointIds, outerKeySelector: (ServiceEndpoint endpoint) => endpoint.Id, innerKeySelector: (Guid endpointId) => endpointId, resultSelector: (ServiceEndpoint endpoint, Guid endpointId) => endpoint) .ToList(); // Add the system endpoint. foreach (ServiceEndpoint endpoint in (ExecutionContext.Endpoints ?? new List <ServiceEndpoint>(0))) { if (string.Equals(endpoint.Name, WellKnownServiceEndpointNames.SystemVssConnection, StringComparison.OrdinalIgnoreCase)) { endpoints.Add(endpoint); break; } } // Get each secure file ID referenced by the task. var secureFileIds = new List <Guid>(); foreach (var input in definition.Data?.Inputs ?? new TaskInputDefinition[0]) { if (string.Equals(input.InputType ?? string.Empty, "secureFile", StringComparison.OrdinalIgnoreCase)) { string inputKey = input?.Name?.Trim() ?? string.Empty; string inputValue; if (!string.IsNullOrEmpty(inputKey) && inputs.TryGetValue(inputKey, out inputValue) && !string.IsNullOrEmpty(inputValue)) { foreach (string rawId in inputValue.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) { Guid parsedId; if (Guid.TryParse(rawId.Trim(), out parsedId) && parsedId != Guid.Empty) { secureFileIds.Add(parsedId); } } } } } if (secureFileIds.Count > 0 && (runtimeVariables.GetBoolean(WellKnownDistributedTaskVariables.RestrictSecrets) ?? false) && (runtimeVariables.GetBoolean(Microsoft.TeamFoundation.Build.WebApi.BuildVariables.IsFork) ?? false)) { ExecutionContext.Result = TaskResult.Skipped; ExecutionContext.ResultCode = $"References secure file. PRs from repository forks are not allowed to access secrets in the pipeline. For more information see https://go.microsoft.com/fwlink/?linkid=862029"; return; } // Get the endpoints referenced by the task. var secureFiles = (ExecutionContext.SecureFiles ?? new List <SecureFile>(0)) .Join(inner: secureFileIds, outerKeySelector: (SecureFile secureFile) => secureFile.Id, innerKeySelector: (Guid secureFileId) => secureFileId, resultSelector: (SecureFile secureFile, Guid secureFileId) => secureFile) .ToList(); // Set output variables. foreach (var outputVar in definition.Data?.OutputVariables ?? new OutputVariable[0]) { if (outputVar != null && !string.IsNullOrEmpty(outputVar.Name)) { ExecutionContext.OutputVariables.Add(outputVar.Name); } } // translate inputs inputs = inputs.ToDictionary(kvp => kvp.Key, kvp => ExecutionContext.TranslatePathForStepTarget(kvp.Value)); // Create the handler. IHandler handler = handlerFactory.Create( ExecutionContext, Task.Reference, stepHost, endpoints, secureFiles, handlerData, inputs, environment, runtimeVariables, taskDirectory: definition.Directory); // Run the task. await handler.RunAsync(); } }
public async Task RunAsync() { // Validate args. Trace.Entering(); ArgUtil.NotNull(ExecutionContext, nameof(ExecutionContext)); ArgUtil.NotNull(ExecutionContext.Variables, nameof(ExecutionContext.Variables)); ArgUtil.NotNull(TaskInstance, nameof(TaskInstance)); var taskManager = HostContext.GetService <ITaskManager>(); var handlerFactory = HostContext.GetService <IHandlerFactory>(); // Set the task display name variable. ExecutionContext.Variables.Set(Constants.Variables.Task.DisplayName, DisplayName); // Load the task definition and choose the handler. // TODO: Add a try catch here to give a better error message. Definition definition = taskManager.Load(TaskInstance); ArgUtil.NotNull(definition, nameof(definition)); // Print out task metadata PrintTaskMetaData(definition); if ((definition.Data?.Execution?.All.Any(x => x is PowerShell3HandlerData)).Value && (definition.Data?.Execution?.All.Any(x => x is PowerShellHandlerData && x.Platforms != null && x.Platforms.Contains("windows", StringComparer.OrdinalIgnoreCase))).Value) { // When task contains both PS and PS3 implementations, we will always prefer PS3 over PS regardless of the platform pinning. Trace.Info("Ignore platform pinning for legacy PowerShell execution handler."); var legacyPShandler = definition.Data?.Execution?.All.Where(x => x is PowerShellHandlerData).FirstOrDefault(); legacyPShandler.Platforms = null; } HandlerData handlerData = definition.Data?.Execution?.All .OrderBy(x => !x.PreferredOnCurrentPlatform()) // Sort true to false. .ThenBy(x => x.Priority) .FirstOrDefault(); if (handlerData == null) { string[] supportedHandlers; #if OS_WINDOWS supportedHandlers = new string[] { "Node", "PowerShell3", "PowerShell", "AzurePowerShell", "PowerShellExe", "Process" }; #else supportedHandlers = new string[] { "Node" }; #endif throw new Exception(StringUtil.Loc("SupportedTaskHandlerNotFound", string.Join(", ", supportedHandlers))); } // Load the default input values from the definition. Trace.Verbose("Loading default inputs."); var inputs = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); foreach (var input in (definition.Data?.Inputs ?? new TaskInputDefinition[0])) { string key = input?.Name?.Trim() ?? string.Empty; if (!string.IsNullOrEmpty(key)) { inputs[key] = input.DefaultValue?.Trim() ?? string.Empty; } } // Merge the instance inputs. Trace.Verbose("Loading instance inputs."); foreach (var input in (TaskInstance.Inputs as IEnumerable <KeyValuePair <string, string> > ?? new KeyValuePair <string, string> [0])) { string key = input.Key?.Trim() ?? string.Empty; if (!string.IsNullOrEmpty(key)) { inputs[key] = input.Value?.Trim() ?? string.Empty; } } // Expand the inputs. Trace.Verbose("Expanding inputs."); ExecutionContext.Variables.ExpandValues(target: inputs); VarUtil.ExpandEnvironmentVariables(HostContext, target: inputs); // Translate the server file path inputs to local paths. foreach (var input in definition.Data?.Inputs ?? new TaskInputDefinition[0]) { if (string.Equals(input.InputType, TaskInputType.FilePath, StringComparison.OrdinalIgnoreCase)) { Trace.Verbose($"Translating file path input '{input.Name}': '{inputs[input.Name]}'"); inputs[input.Name] = TranslateFilePathInput(inputs[input.Name] ?? string.Empty); Trace.Verbose($"Translated file path input '{input.Name}': '{inputs[input.Name]}'"); } } // Expand the handler inputs. Trace.Verbose("Expanding handler inputs."); VarUtil.ExpandValues(HostContext, source: inputs, target: handlerData.Inputs); ExecutionContext.Variables.ExpandValues(target: handlerData.Inputs); // Create the handler. IHandler handler = handlerFactory.Create( ExecutionContext, handlerData, inputs, taskDirectory: definition.Directory, filePathInputRootDirectory: TranslateFilePathInput(string.Empty)); // Run the task. await handler.RunAsync(); }
public async Task RunAsync() { // Validate args. Trace.Entering(); ArgUtil.NotNull(ExecutionContext, nameof(ExecutionContext)); ArgUtil.NotNull(ExecutionContext.Variables, nameof(ExecutionContext.Variables)); ArgUtil.NotNull(TaskInstance, nameof(TaskInstance)); var taskManager = HostContext.GetService <ITaskManager>(); var handlerFactory = HostContext.GetService <IHandlerFactory>(); // Set the task display name variable. ExecutionContext.Variables.Set(Constants.Variables.Task.DisplayName, DisplayName); // Load the task definition and choose the handler. // TODO: Add a try catch here to give a better error message. Definition definition = taskManager.Load(TaskInstance); ArgUtil.NotNull(definition, nameof(definition)); HandlerData handlerData = definition.Data?.Execution?.All .OrderBy(x => !x.PreferredOnCurrentPlatform()) // Sort true to false. .ThenBy(x => x.Priority) .FirstOrDefault(); if (handlerData == null) { throw new Exception(StringUtil.Loc("SupportedTaskHandlerNotFound")); } // Load the default input values from the definition. Trace.Verbose("Loading default inputs."); var inputs = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); foreach (var input in (definition.Data?.Inputs ?? new TaskInputDefinition[0])) { string key = input?.Name?.Trim() ?? string.Empty; if (!string.IsNullOrEmpty(key)) { inputs[key] = input.DefaultValue?.Trim() ?? string.Empty; } } // Merge the instance inputs. Trace.Verbose("Loading instance inputs."); foreach (var input in (TaskInstance.Inputs as IEnumerable <KeyValuePair <string, string> > ?? new KeyValuePair <string, string> [0])) { string key = input.Key?.Trim() ?? string.Empty; if (!string.IsNullOrEmpty(key)) { inputs[key] = input.Value?.Trim() ?? string.Empty; } } // Expand the inputs. Trace.Verbose("Expanding inputs."); ExecutionContext.Variables.ExpandValues(target: inputs); VarUtil.ExpandEnvironmentVariables(HostContext, target: inputs); // Translate the server file path inputs to local paths. foreach (var input in definition.Data?.Inputs ?? new TaskInputDefinition[0]) { if (string.Equals(input.InputType, TaskInputType.FilePath, StringComparison.OrdinalIgnoreCase)) { Trace.Verbose($"Translating file path input '{input.Name}': '{inputs[input.Name]}'"); inputs[input.Name] = TranslateFilePathInput(inputs[input.Name] ?? string.Empty); Trace.Verbose($"Translated file path input '{input.Name}': '{inputs[input.Name]}'"); } } // Expand the handler inputs. Trace.Verbose("Expanding handler inputs."); VarUtil.ExpandValues(HostContext, source: inputs, target: handlerData.Inputs); // Create the handler. IHandler handler = handlerFactory.Create( ExecutionContext, handlerData, inputs, taskDirectory: definition.Directory, filePathInputRootDirectory: TranslateFilePathInput(string.Empty)); // Run the task. await handler.RunAsync(); }
public IHandler Create( IExecutionContext executionContext, HandlerData data, Dictionary<string, string> inputs, string taskDirectory, string filePathInputRootDirectory) { // Validate args. Trace.Entering(); ArgUtil.NotNull(executionContext, nameof(executionContext)); ArgUtil.NotNull(data, nameof(data)); ArgUtil.NotNull(inputs, nameof(inputs)); ArgUtil.NotNull(taskDirectory, nameof(taskDirectory)); // Create the handler. IHandler handler; if (data is NodeHandlerData) { // Node. handler = HostContext.CreateService<INodeHandler>(); (handler as INodeHandler).Data = data as NodeHandlerData; } else if (data is PowerShell3HandlerData) { // PowerShell3. handler = HostContext.CreateService<IPowerShell3Handler>(); (handler as IPowerShell3Handler).Data = data as PowerShell3HandlerData; } else if (data is PowerShellExeHandlerData) { // PowerShellExe. handler = HostContext.CreateService<IPowerShellExeHandler>(); (handler as IPowerShellExeHandler).Data = data as PowerShellExeHandlerData; } else if (data is ProcessHandlerData) { // Process. handler = HostContext.CreateService<IProcessHandler>(); (handler as IProcessHandler).Data = data as ProcessHandlerData; } else if (data is PowerShellHandlerData) { // PowerShell. handler = HostContext.CreateService<IPowerShellHandler>(); (handler as IPowerShellHandler).Data = data as PowerShellHandlerData; } else if (data is AzurePowerShellHandlerData) { // AzurePowerShell. handler = HostContext.CreateService<IAzurePowerShellHandler>(); (handler as IAzurePowerShellHandler).Data = data as AzurePowerShellHandlerData; } else { // This should never happen. throw new NotSupportedException(); } handler.ExecutionContext = executionContext; handler.FilePathInputRootDirectory = filePathInputRootDirectory; handler.Inputs = inputs; handler.TaskDirectory = taskDirectory; return handler; }
public async Task RunAsync() { // Validate args. Trace.Entering(); ArgUtil.NotNull(ExecutionContext, nameof(ExecutionContext)); ArgUtil.NotNull(ExecutionContext.Variables, nameof(ExecutionContext.Variables)); ArgUtil.NotNull(TaskInstance, nameof(TaskInstance)); var taskManager = HostContext.GetService <ITaskManager>(); var handlerFactory = HostContext.GetService <IHandlerFactory>(); // Load the task definition and choose the handler. // TODO: Add a try catch here to give a better error message. Definition definition = taskManager.Load(TaskInstance); ArgUtil.NotNull(definition, nameof(definition)); HandlerData handlerData = definition.Data?.Execution?.All .OrderBy(x => !x.PreferredOnCurrentPlatform()) // Sort true to false. .ThenBy(x => x.Priority) .FirstOrDefault(); if (handlerData == null) { // TODO: BETTER ERROR AND LOC throw new Exception("Supported handler not found."); } // Load the default input values from the definition. Trace.Verbose("Loading default inputs."); var inputs = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); foreach (var input in (definition.Data?.Inputs ?? new TaskInputDefinition[0])) { string key = input?.Name?.Trim() ?? string.Empty; if (!string.IsNullOrEmpty(key)) { inputs[key] = input.DefaultValue?.Trim() ?? string.Empty; } } // Merge the instance inputs. Trace.Verbose("Loading instance inputs."); foreach (var input in (TaskInstance.Inputs as IEnumerable <KeyValuePair <string, string> > ?? new KeyValuePair <string, string> [0])) { string key = input.Key?.Trim() ?? string.Empty; if (!string.IsNullOrEmpty(key)) { inputs[key] = input.Value?.Trim() ?? string.Empty; } } // Expand the inputs. Trace.Verbose("Expanding inputs."); ExecutionContext.Variables.ExpandValues(target: inputs); // Delegate to the JobExtension to fixup the file path inputs. foreach (var input in definition.Data?.Inputs ?? new TaskInputDefinition[0]) { if (String.Equals(input.InputType, TaskInputType.FilePath, StringComparison.OrdinalIgnoreCase)) { Trace.Verbose($"Expanding filepath type input {input.Name}: {inputs[input.Name] ?? string.Empty}."); inputs[input.Name] = ExpandFilePathInput(inputs[input.Name] ?? string.Empty); Trace.Verbose($"Expanded filepath type input {input.Name}: {inputs[input.Name] ?? string.Empty}."); } } // Create the handler. IHandler handler = handlerFactory.Create( ExecutionContext, handlerData, inputs, taskDirectory: definition.Directory); // Run the task. await handler.RunAsync(); }