//note: this doesn't implement SaveExitDataAs( action ); private ExecuteResult SpawnExternal(ActionItem a, Dictionary <string, string> dynamicData, object parentExitData, bool dryRun) { ExecuteResult result = new ExecuteResult(); List <string> args = new List <string>(); Plan container = new Plan(); a.InstanceId = ActionInstanceIdCounter++; container.Name = $"{Name}:{a.Name}"; container.Actions.Add(a.Clone()); container.StartInfo = StartInfo; string planYaml = CryptoHelpers.Encode(container.ToYaml()); args.Add($"/plan:{planYaml}"); args.Add($"/dryRun:{dryRun}"); args.Add($"/taskModel:single"); foreach (string key in dynamicData.Keys) { args.Add($"/{key}:{dynamicData[key]}"); } args.Add($"/data:{parentExitData}"); string arguments = string.Join(" ", args); Process p = new Process(); p.StartInfo.Arguments = arguments; p.StartInfo.FileName = "synapse.cli.exe"; p.StartInfo.RedirectStandardInput = true; p.StartInfo.RedirectStandardOutput = true; p.StartInfo.RedirectStandardError = true; p.StartInfo.UseShellExecute = false; p.StartInfo.CreateNoWindow = true; p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; p.EnableRaisingEvents = true; //if( a.HasRunAs ) //{ // p.StartInfo.Domain = a.RunAs.Domain; // p.StartInfo.UserName = a.RunAs.UserName; // SecureString pw = new SecureString(); // foreach( char c in a.RunAs.Password ) // pw.AppendChar( c ); // p.StartInfo.Password = pw; //} p.OutputDataReceived += p_OutputDataReceived; p.Start(); result.PId = p.Id; #if sqlite a.UpdateInstanceStatus(StatusType.None, "SpawnExternal", 0, p.Id); #endif #region read this // best practice information on accessing stdout/stderr from mdsn article: // https://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.redirectstandardoutput%28v=vs.110%29.aspx // Do not wait for the child process to exit before reading to the end of its redirected stream. // Do not perform a synchronous read to the end of both redirected streams. // string output = p.StandardOutput.ReadToEnd(); // string error = p.StandardError.ReadToEnd(); // p.WaitForExit(); // Use asynchronous read operations on at least one of the streams. #endregion p.BeginOutputReadLine(); p.BeginErrorReadLine(); p.WaitForExit(); result.BranchStatus = result.Status = (StatusType)p.ExitCode; return(result); }
void ProcessRecursive(IActionContainer parentContext, SecurityContext parentSecurityContext, ActionItem actionGroup, List <ActionItem> actions, ExecuteResult parentResult, Dictionary <string, string> dynamicData, bool dryRun, Func <SecurityContext, ActionItem, Dictionary <string, string>, object, bool, ExecuteResult> executeHandlerMethod) { if (WantsStopOrPause()) { return; } parentContext.EnsureInitialized(); //queryStatus provides the inbound value to ExecuteCase evaluation; it's the ExecuteCase comparison value. //queryStatus is carried downward through successive subtree executions. StatusType queryStatus = parentResult.Status; #region actionGroup if (actionGroup != null && (((actionGroup.ExecuteCase & parentResult.Status) == actionGroup.ExecuteCase) || (actionGroup.ExecuteCase == StatusType.Any))) { actionGroup.EnsureInitialized(); #region actionGroup-forEach if ((actionGroup.HasParameters && actionGroup.Parameters.HasForEach) || (actionGroup.Handler.HasConfig && actionGroup.Handler.Config.HasForEach)) { List <ActionItem> resolvedParmsActionGroup = new List <ActionItem>(); ResolveConfigAndParameters(actionGroup, dynamicData, ref resolvedParmsActionGroup, parentResult.ExitData); foreach (ActionItem ai in resolvedParmsActionGroup) { ai.Parameters.ForEach = null; } actionGroup.InstanceId = ActionInstanceIdCounter++; ActionItem agclone = actionGroup.Clone(); agclone.Result = new ExecuteResult(); parentContext.ActionGroup = agclone; Parallel.ForEach(resolvedParmsActionGroup, a => // foreach( ActionItem a in resolvedParmsActionGroup ) { #if sqlite a.CreateInstance(parentContext, InstanceId); #endif a.InstanceId = ActionInstanceIdCounter++; ActionItem clone = a.Clone(); agclone.Actions.Add(clone); ExecuteResult r = executeHandlerMethod(parentSecurityContext, a, dynamicData, parentResult.ExitData, dryRun); parentContext.ActionGroup.Result.SetBranchStatusChecked(r); parentContext.Result.SetBranchStatusChecked(r); clone.Handler.Type = actionGroup.Handler.Type; clone.Handler.StartInfo = actionGroup.Handler.StartInfo; clone.Result = r; if (r.Status > queryStatus) { queryStatus = r.Status; } if (a.HasActions) { ProcessRecursive(clone, a.RunAs, a.ActionGroup, a.Actions, r, dynamicData, dryRun, executeHandlerMethod); parentContext.ActionGroup.Result.SetBranchStatusChecked(clone.Result); parentContext.Result.SetBranchStatusChecked(clone.Result); if (clone.Result.Status > queryStatus) { queryStatus = clone.Result.Status; } } }); } #endregion #region actionGroup-single else { #if sqlite actionGroup.CreateInstance(parentContext, InstanceId); #endif ResolveConfigAndParameters(actionGroup, dynamicData, parentResult.ExitData); actionGroup.InstanceId = ActionInstanceIdCounter++; ActionItem clone = actionGroup.Clone(); parentContext.ActionGroup = clone; ExecuteResult r = executeHandlerMethod(parentSecurityContext, actionGroup, dynamicData, parentResult.ExitData, dryRun); parentContext.Result.SetBranchStatusChecked(r); clone.Handler.Type = actionGroup.Handler.Type; clone.Handler.StartInfo = actionGroup.Handler.StartInfo; clone.Result = r; if (r.Status > queryStatus) { queryStatus = r.Status; } if (actionGroup.HasActions) { ProcessRecursive(clone, actionGroup.RunAs, null, actionGroup.Actions, r, dynamicData, dryRun, executeHandlerMethod); parentContext.Result.SetBranchStatusChecked(clone.Result); if (clone.Result.Status > queryStatus) { queryStatus = clone.Result.Status; } } } #endregion } #endregion #region actions IEnumerable <ActionItem> actionList = actions.Where(a => (((a.ExecuteCase & queryStatus) == a.ExecuteCase) || (a.ExecuteCase == StatusType.Any))); List <ActionItem> resolvedParmsActions = new List <ActionItem>(); Parallel.ForEach(actionList, a => // foreach( ActionItem a in actionList ) ResolveConfigAndParameters(a, dynamicData, ref resolvedParmsActions, parentResult.ExitData) ); Parallel.ForEach(resolvedParmsActions, a => // foreach( ActionItem a in resolvedParmsActions ) { #if sqlite a.CreateInstance(parentContext, InstanceId); #endif a.InstanceId = ActionInstanceIdCounter++; ActionItem clone = a.Clone(); parentContext.Actions.Add(clone); ExecuteResult r = a.Result; if (r?.Status != StatusType.Failed) { r = executeHandlerMethod(parentSecurityContext, a, dynamicData, parentResult.ExitData, dryRun); } parentContext.Result.SetBranchStatusChecked(r); clone.Handler.Type = a.Handler.Type; clone.Handler.StartInfo = a.Handler.StartInfo; clone.Result = r; if (a.HasActions) { ProcessRecursive(clone, a.RunAs, a.ActionGroup, a.Actions, r, dynamicData, dryRun, executeHandlerMethod); parentContext.Result.SetBranchStatusChecked(clone.Result); } }); #endregion }