예제 #1
0
        /// <summary>
        /// Runs the commands on the PlanetLab node at the specified index.
        /// </summary>
        /// <param name="state">The state.</param>
        /// <param name="index">The node state index.</param>
        private void OnRunNode(PlManagerState state, int index)
        {
            lock (state.Sync)
            {
                // If the operation has been canceled, return.
                if (state.IsStopped) return;

                // Get the node state.
                PlManagerNodeState nodeState = state.GetNode(index);

                // Execute the secure shell connection on the thread pool.
                ThreadPool.QueueUserWorkItem((object threadState) =>
                    {
                        // Raise a node started event.
                        if (null != this.NodeStarted) this.NodeStarted(this, new PlManagerNodeEventArgs(state, nodeState.Node));

                        try
                        {
                            // Create the private key connection information.
                            ConnectionInfo connectionInfo;
                            // Create a memory stream with the key data.
                            using (MemoryStream memoryStream = new MemoryStream(state.Slice.Key))
                            {
                                // Create the private key file.
                                using (PrivateKeyFile keyFile = new PrivateKeyFile(memoryStream))
                                {
                                    // Create a key connection info.
                                    connectionInfo = new PrivateKeyConnectionInfo(nodeState.Node.Hostname, state.Slice.Name, keyFile);
                                }
                            }

                            // Open an SSH client to the PlanetLab node.
                            using (SshClient sshClient = new SshClient(connectionInfo))
                            {
                                // Connect the client.
                                sshClient.Connect();

                                // For all the slice commands.
                                foreach (PlCommand command in state.Slice.Commands)
                                {
                                    // If the command has parameters.
                                    if (command.HasParameters)
                                    {
                                        // Format the command with all parameter sets.
                                        for (int indexSet = 0; indexSet < command.SetsCount; indexSet++)
                                        {
                                            // If the operation has been paused, wait for resume.
                                            if (state.IsPaused)
                                            {
                                                state.WaitPause();
                                            }

                                            // If the operation has been canceled, return.
                                            if (state.IsStopped)
                                            {
                                                // Remove the node from the running list.
                                                state.UpdateNodeRunningToSkipped(index);
                                                // Cancel all nodes in the pending list.
                                                state.CancelPendingNodes();
                                                // Raise the canceled event.
                                                if (null != this.NodeCanceled) this.NodeCanceled(this, new PlManagerNodeEventArgs(state, nodeState.Node));
                                                // Return.
                                                return;
                                            }

                                            // Run the command with the current parameters set.
                                            this.OnRunCommand(state, nodeState, command, indexSet, sshClient);
                                        }
                                    }
                                    else
                                    {
                                        // Run the command without parameters.
                                        this.OnRunCommand(state, nodeState, command, -1, sshClient);
                                    }
                                }

                                // Disconnect the client.
                                sshClient.Disconnect();
                            }

                            // Remove the node from the running list.
                            state.UpdateNodeRunningToCompleted(index);

                            // Raise the success event.
                            if (null != this.NodeFinishedSuccess) this.NodeFinishedSuccess(this, new PlManagerNodeEventArgs(state, nodeState.Node));
                        }
                        catch (Exception exception)
                        {
                            // Remove the node from the running list.
                            state.UpdateNodeRunningToSkipped(index);

                            // Raise the fail event.
                            if (null != this.NodeFinishedFail) this.NodeFinishedFail(this, new PlManagerNodeEventArgs(state, nodeState.Node, exception));
                        }
                        finally
                        {
                            lock (state.Sync)
                            {
                                // If the operation has not been canceled.
                                if (!state.IsStopped)
                                {

                                    // If the list of pending nodes and running nodes is empty, stop.
                                    if ((0 == state.PendingCount) && (0 == state.RunningCount))
                                    {
                                        this.Stop(state);
                                    }

                                    // Get a cached copy of all the pending PlanetLab nodes.
                                    int[] pendingCache = state.PendingNodes.ToArray();

                                    // Find the next pending node to execute commands.
                                    foreach (int newIndex in pendingCache)
                                    {
                                        // Get the node state corresponding to the pending node.
                                        PlManagerNodeState newNode = state.GetNode(newIndex);

                                        // If the slice configuration only allows one node per site.
                                        if (state.Slice.OnlyRunOneNodePerSite)
                                        {
                                            // If the node site is completed.
                                            if (state.IsSiteCompleted(newNode.Node.SiteId.Value))
                                            {
                                                // Change the node from the pending to the skipped state.
                                                state.UpdateNodePendingToSkipped(newIndex);
                                                // Raise an event indicating that the node has been skipped.
                                                if (null != this.NodeSkipped) this.NodeSkipped(this, new PlManagerNodeEventArgs(state, newNode.Node));
                                                // Skip the loop to the next node.
                                                continue;
                                            }
                                            // If the node site is running.
                                            if (state.IsSiteRunning(newNode.Node.SiteId.Value))
                                            {
                                                // Postpone the node for later, and skip the loop to the next node.
                                                continue;
                                            }
                                        }

                                        // Change the node from the pending to the running state.
                                        state.UpdateNodePendingToRunning(newIndex);

                                        // Execute the commands on specified node.
                                        this.OnRunNode(state, newIndex);

                                        // Exit the loop.
                                        break;
                                    }
                                }
                            }
                        }
                    });
            }
        }
예제 #2
0
        /// <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));
            }
        }