Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 41 additions & 26 deletions OpenTap.Plugins.Ssh/SshCommandStep.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
using System.Collections.Generic;
using System.Linq;
using System.ComponentModel;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Renci.SshNet;

namespace OpenTap.Plugins.Ssh
Expand All @@ -36,7 +39,7 @@ public IEnumerable<SshResource> sshSessions
.Concat(DutSettings.Current.OfType<SshResource>()));
}
}

private SshResource BackingResource;

[Display("Connection", "Use SSH session defined by this Instrument, DUT or Parent step.")]
Expand Down Expand Up @@ -67,20 +70,22 @@ public class SshCommandStep : SshStepBase
#region Settings
public string Command { get; set; } = "pwd";

[Display("Add To Log", Group: "Response", Collapsed: true, Order:0)]
[Display("Add To Log", Group: "Response", Collapsed: true, Order: 0)]
public bool AddToLog { get; set; } = true;
[Display("Output Response", "Sets if the output of the ssh command should be saved as an output.", Group: "Response", Collapsed: true, Order:0)]

[Display("Output Response", "Sets if the output of the ssh command should be saved as an output.", Group: "Response", Collapsed: true, Order: 0)]
public bool OutputResponse { get; set; }

[Output]
[Browsable(true)]
[EnabledIf(nameof(OutputResponse), HideIfDisabled = true)]
[Display("Response", Description:"The standard output (stdout) of the executed program.", Group: "Response", Collapsed: true, Order:1)]
[Display("Response", Description: "The standard output (stdout) of the executed program.", Group: "Response", Collapsed: true, Order: 1)]
public string Response { get; private set; }


[Output]
[Browsable(true)]
[Display("Exit Code", Description:"The exit code of the command.", Group: "Response", Collapsed: true, Order:1)]
[Display("Exit Code", Description: "The exit code of the command.", Group: "Response", Collapsed: true, Order: 1)]
public int ExitCode { get; private set; }

[Display("Enabled", Group: "Timeout")]
Expand All @@ -90,7 +95,7 @@ public class SshCommandStep : SshStepBase
[EnabledIf(nameof(TimeoutEnabled), HideIfDisabled = true)]
public double Timeout { get; set; } = 5.0;

[Display("Check Exit Code", Description: "Sets the test step verdict based on the exit code. Exit code 0 will cause the step to pass, all other exit codes will cause it to fail.", Group: "Response", Collapsed: true, Order:0)]
[Display("Check Exit Code", Description: "Sets the test step verdict based on the exit code. Exit code 0 will cause the step to pass, all other exit codes will cause it to fail.", Group: "Response", Collapsed: true, Order: 0)]
public bool CheckExitCode { get; set; }
#endregion

Expand All @@ -104,28 +109,13 @@ public override void Run()
SshCommand command = SshResource.SshClient.CreateCommand(Command);
if (TimeoutEnabled)
command.CommandTimeout = TimeSpan.FromSeconds(Timeout);
command.Execute();

ExitCode = command.ExitStatus;
if (OutputResponse)
{
Response = command.Result.TrimEnd('\n');
}
if(command.ExitStatus == 0)
{
if (AddToLog)
{
foreach (var line in command.Result.Trim().Split('\n'))
{
Log.Info(line);
}
}
}
if (AddToLog)
ExecuteAsync(command).GetAwaiter().GetResult();
else
{
if (AddToLog)
Log.Warning(command.Error);
}
command.Execute();

ExitCode = command.ExitStatus;
if (CheckExitCode)
{
if (ExitCode == 0)
Expand All @@ -138,5 +128,30 @@ public override void Run()
}
}
}

private async Task ExecuteAsync(SshCommand command)
{
var result = command.BeginExecute();
var outputReader = new StreamReader(command.OutputStream, Encoding.UTF8);
var errorReader = new StreamReader(command.ExtendedOutputStream, Encoding.UTF8);

var outputTask = ReadStreamAsync(outputReader, line => Log.Info(line), result);
var errorTask = ReadStreamAsync(errorReader, line => Log.Warning(line), result);

await Task.WhenAll(outputTask, errorTask);

command.EndExecute(result);
}

private async Task ReadStreamAsync(StreamReader reader, Action<string> logAction, IAsyncResult result)
{
var buffer = new char[1024];
var line = await reader.ReadLineAsync();
while (!result.IsCompleted || line != null)
{
logAction(line);
line = await reader.ReadLineAsync();
}
}
}
}