/// <summary> /// Creates a new PlanetLab manager node event arguments instance. /// </summary> /// <param name="state">The manager state.</param> /// <param name="node">The PlanetLab node.</param> /// <param name="command">The PlanetLab command.</param> /// <param name="set">The PlanetLab command parameter set.</param> /// <param name="subcommand">The PlanetLab subcommand state.</param> public PlManagerSubcommandEventArgs(PlManagerState state, PlNode node, PlCommand command, int set, PlManagerSubcommandState subcommand) { this.State = state; this.Node = node; this.Command = command; this.Set = set; this.Subcommand = subcommand; }
/// <summary> /// Creates a new subcommand history from the specified subcommand state. /// </summary> /// <param name="state">The subcommand state.</param> public PlManagerHistorySubcommand(PlManagerSubcommandState state) { // Validate the argument. if (null == state) throw new ArgumentNullException("state"); // Set the properties. this.Command = state.Command; this.Exception = state.Exception != null ? state.Exception.Message : null; this.Timeout = state.Timeout; this.ExitStatus = state.ExitStatus; this.Result = state.Result; this.Error = state.Error; this.Duration = state.Duration; this.Retries = state.Retries; }
/// <summary> /// Runs a command on the specified PlanetLab node. /// </summary> /// <param name="state">The manager state.</param> /// <param name="node">The PlanetLab node state.</param> /// <param name="command">The PlanetLab command.</param> /// <param name="set">The command parameter set.</param> /// <param name="sshClient">The SSH client.</param> private void OnRunCommand(PlManagerState state, PlManagerNodeState node, PlCommand command, int set, SshClient sshClient) { // Raise the command started event. if (null != this.CommandStarted) this.CommandStarted(this, new PlManagerCommandEventArgs(state, node.Node, command, set)); try { // Compute the command text. string commandText = set >= 0 ? command.GetCommand(set) : command.Command; // The number of subcommands. int success = 0; int fail = 0; // Divide the command into subcommands. string[] subcommands = commandText.Split(PlManager.subcommandSeparators, StringSplitOptions.RemoveEmptyEntries); // For all subcommands. foreach (string subcommand in subcommands) { // If the operation has been paused, wait for resume. if (state.IsPaused) { state.WaitPause(); } // If the operation has been canceled, return. if (state.IsStopped) { // Raise the canceled event. if (null != this.CommandCanceled) this.CommandCanceled(this, new PlManagerCommandEventArgs(state, node.Node, command, set)); // Return. return; } // If the subcommand is empty, continue to the next subcommand. if (string.IsNullOrWhiteSpace(subcommand)) continue; // Create a new SSH command. using (SshCommand sshCommand = sshClient.CreateCommand(subcommand)) { try { // The command duration. TimeSpan duration; // The retry count. int retry = 0; do { // The start time. DateTime startTime = DateTime.Now; // Execute the command. sshCommand.Execute(); // Compute the command duration. duration = DateTime.Now - startTime; } while ((retry++ < state.Slice.CommandRetries) && (sshCommand.ExitStatus != 0)); // Create a new command state. PlManagerSubcommandState subcommandState = new PlManagerSubcommandState(node, sshCommand, duration, retry - 1); // Increment the number of successful subcommands. success++; // Add the subcommand. node.AddSubcommand(subcommandState); // Raise a subcommand success event. if (null != this.SubcommandSuccess) this.SubcommandSuccess(this, new PlManagerSubcommandEventArgs(state, node.Node, command, set, subcommandState)); } catch (Exception exception) { // Create a new subcommand state. PlManagerSubcommandState subcommandState = new PlManagerSubcommandState(node, sshCommand, exception); // Increment the number of failed subcommands. fail++; // Add the subcommand. node.AddSubcommand(subcommandState); // Raise a subcommand fail event. if (null != this.SubcommandFail) this.SubcommandFail(this, new PlManagerSubcommandEventArgs(state, node.Node, command, set, exception)); } } } // Raise a command completed event. if (null != this.CommandFinishedSuccess) this.CommandFinishedSuccess(this, new PlManagerCommandEventArgs(state, node.Node, command, set, success, fail)); } catch (Exception exception) { // Raise a command completed event. if (null != this.CommandFinishedFail) this.CommandFinishedFail(this, new PlManagerCommandEventArgs(state, node.Node, command, set, exception)); } }
/// <summary> /// Adds a subcommand result to the results list. /// </summary> /// <param name="subcommand">The subcommand.</param> private void OnAddResult(PlManagerSubcommandState subcommand) { // Create a new result item. ListViewItem item = new ListViewItem(new string[] { subcommand.Command, subcommand.ExitStatus.ToString(), subcommand.Duration.ToString() }); item.Tag = new PlManagerHistorySubcommand(subcommand); item.ImageKey = subcommand.Exception == null ? subcommand.ExitStatus == 0 ? "Success" : "Warning" : "Error"; // Add the result item. this.listViewResults.Items.Add(item); }
/// <summary> /// Sends the subcommand to the connected tools. /// </summary> /// <param name="subcommand">The subcommand.</param> private void OnSendResultTools(PlManagerSubcommandState subcommand) { // For all the connected tool methods. foreach (ToolMethodInfo info in this.controlMethods.Methods.Where(inf => inf.Trigger == ControlSliceRun.toolTriggerCommand)) { lock (this.toolSync) { try { // Call the tool method asynchronously. ToolMethodState asyncState = info.Method.BeginCall((IAsyncResult result) => { try { // End the call. if ((bool)info.Method.EndCall(result)) { // Log an event. this.controlLog.Add(this.config.Log.Add( LogEventLevel.Verbose, LogEventType.Success, ControlSliceRun.logSource.FormatWith(this.slice.Id), @"The result of the command {0} on PlanetLab node {1} was sent to method '{2}' of tool '{3}' and processed successfully.", new object[] { subcommand.Command, subcommand.Node.Node.Hostname, info.Method.Name, info.Method.Tool.Info.Name })); } else { // Log an event. this.controlLog.Add(this.config.Log.Add( LogEventLevel.Normal, LogEventType.Warning, ControlSliceRun.logSource.FormatWith(this.slice.Id), @"The result of the command {0} on PlanetLab node {1} was sent to method '{2}' of tool '{3}' but the processing failed.", new object[] { subcommand.Command, subcommand.Node.Node.Hostname, info.Method.Name, info.Method.Tool.Info.Name })); } } catch (Exception exception) { // Log an event. this.controlLog.Add(this.config.Log.Add( LogEventLevel.Important, LogEventType.Error, ControlSliceRun.logSource.FormatWith(this.slice.Id), @"The result of the command {0} on PlanetLab node {1} was sent to method '{2}' of tool '{3}' and failed. {4}", new object[] { subcommand.Command, subcommand.Node.Node.Hostname, info.Method.Name, info.Method.Tool.Info.Name, exception.Message }, exception)); } finally { lock (this.toolSync) { // Remove the method state from the list of tool method states. this.toolStates.Remove(result as ToolMethodState); // If the list of tool states is empty. if (this.toolStates.Count == 0) { // Set the wait handle. this.toolWait.Set(); } } } }, subcommand, this.sessionId, subcommand.Node.Node.Hostname, subcommand.Result); // If the list of tool states is empty. if (this.toolStates.Count == 0) { // Reset the wait handle. this.toolWait.Reset(); } // Add the state to the list of tool method states. this.toolStates.Add(asyncState); } catch (Exception exception) { // Log an event. this.controlLog.Add(this.config.Log.Add( LogEventLevel.Important, LogEventType.Error, ControlSliceRun.logSource.FormatWith(this.slice.Id), @"The result of the command {0} on PlanetLab node {1} was sent to method '{2}' of tool '{3}' and failed. {4}", new object[] { subcommand.Command, subcommand.Node.Node.Hostname, info.Method.Name, info.Method.Tool.Info.Name, exception.Message }, exception)); } } } }