diff --git a/src/VirtualClient/VirtualClient.Actions.UnitTests/ScriptExecutor/PowershellExecutorTests.cs b/src/VirtualClient/VirtualClient.Actions.UnitTests/ScriptExecutor/PowershellExecutorTests.cs index 107e72b188..a91405cb53 100644 --- a/src/VirtualClient/VirtualClient.Actions.UnitTests/ScriptExecutor/PowershellExecutorTests.cs +++ b/src/VirtualClient/VirtualClient.Actions.UnitTests/ScriptExecutor/PowershellExecutorTests.cs @@ -139,12 +139,14 @@ public void SetupTest(PlatformID platform = PlatformID.Win32NT) } [Test] - [TestCase(PlatformID.Win32NT, @"\win-x64", @"genericScript.ps1")] + [TestCase(PlatformID.Win32NT, @"\win-x64", @"genericScript.ps1", true)] + [TestCase(PlatformID.Win32NT, @"\win-x64", @"genericScript.ps1", false)] [Platform(Exclude = "Unix,Linux,MacOsX")] - public async Task PowershellExecutorExecutesTheCorrectWorkloadCommands(PlatformID platform, string platformSpecificPath, string command) + public async Task PowershellExecutorExecutesTheCorrectWorkloadCommands(PlatformID platform, string platformSpecificPath, string command, bool runElevated) { this.SetupTest(platform); - this.fixture.Parameters["ScriptPath"] = command; + this.fixture.Parameters[nameof(PowershellExecutor.RunElevated)] = runElevated; + this.fixture.Parameters[nameof(PowershellExecutor.ScriptPath)] = command; string fullCommand = $"{this.mockPackage.Path}{platformSpecificPath}\\{command} parameter1 parameter2"; diff --git a/src/VirtualClient/VirtualClient.Actions.UnitTests/ScriptExecutor/PythonExecutorTests.cs b/src/VirtualClient/VirtualClient.Actions.UnitTests/ScriptExecutor/PythonExecutorTests.cs index 3094d0dc8c..763939f7e4 100644 --- a/src/VirtualClient/VirtualClient.Actions.UnitTests/ScriptExecutor/PythonExecutorTests.cs +++ b/src/VirtualClient/VirtualClient.Actions.UnitTests/ScriptExecutor/PythonExecutorTests.cs @@ -139,22 +139,27 @@ public void SetupTest(PlatformID platform) } [Test] - [TestCase(PlatformID.Win32NT, @"\win-x64\", @"genericScript.py", true, "python3")] - [TestCase(PlatformID.Unix, @"/linux-x64/", @"genericScript.py", true, "python3")] - [TestCase(PlatformID.Win32NT, @"\win-x64\", @"genericScript.py", false, "python")] - [TestCase(PlatformID.Unix, @"/linux-x64/", @"genericScript.py", false, "python")] - public async Task PythonExecutorExecutesTheCorrectWorkloadCommands(PlatformID platform, string platformSpecificPath, string command, bool usePython3, string pythonVersion) + [TestCase(PlatformID.Win32NT, @"\win-x64\", @"genericScript.py", true, "python3", true)] + [TestCase(PlatformID.Win32NT, @"\win-x64\", @"genericScript.py", true, "python3", false)] + [TestCase(PlatformID.Unix, @"/linux-x64/", @"genericScript.py", true, "python3", true)] + [TestCase(PlatformID.Unix, @"/linux-x64/", @"genericScript.py", true, "python3", false)] + [TestCase(PlatformID.Win32NT, @"\win-x64\", @"genericScript.py", false, "python", true)] + [TestCase(PlatformID.Win32NT, @"\win-x64\", @"genericScript.py", false, "python", false)] + [TestCase(PlatformID.Unix, @"/linux-x64/", @"genericScript.py", false, "python", true)] + [TestCase(PlatformID.Unix, @"/linux-x64/", @"genericScript.py", false, "python", false)] + public async Task PythonExecutorExecutesTheCorrectWorkloadCommands(PlatformID platform, string platformSpecificPath, string command, bool usePython3, string pythonVersion, bool runElevated) { this.SetupTest(platform); - this.mockFixture.Parameters["ScriptPath"] = command; - this.mockFixture.Parameters["UsePython3"] = usePython3; + this.mockFixture.Parameters[nameof(PythonExecutor.RunElevated)] = runElevated; + this.mockFixture.Parameters[nameof(PythonExecutor.ScriptPath)] = command; + this.mockFixture.Parameters[nameof(PythonExecutor.UsePython3)] = usePython3; string fullCommand = $"{this.mockPackage.Path}{platformSpecificPath}{command} parameter1 parameter2"; using (TestPythonExecutor executor = new TestPythonExecutor(this.mockFixture)) { bool commandExecuted = false; - string expectedCommand = $"{pythonVersion} {fullCommand}"; + string expectedCommand = $"{(PlatformID.Unix.Equals(platform) && runElevated ? "sudo" : string.Empty)} {pythonVersion} {fullCommand}".Trim(); this.mockFixture.ProcessManager.OnCreateProcess = (exe, arguments, workingDirectory) => { if (expectedCommand == $"{exe} {arguments}") diff --git a/src/VirtualClient/VirtualClient.Actions.UnitTests/ScriptExecutor/ScriptExecutorTests.cs b/src/VirtualClient/VirtualClient.Actions.UnitTests/ScriptExecutor/ScriptExecutorTests.cs index d3ecda69f4..d47ffa30c1 100644 --- a/src/VirtualClient/VirtualClient.Actions.UnitTests/ScriptExecutor/ScriptExecutorTests.cs +++ b/src/VirtualClient/VirtualClient.Actions.UnitTests/ScriptExecutor/ScriptExecutorTests.cs @@ -176,17 +176,21 @@ public void ScriptExecutorThrowsOnInitializationWhenNoFileExistsAtExecutablePath } [Test] - [TestCase(@"genericScript.bat", true)] - [TestCase(@"..\..\..\subfolder1\genericScript.bat", true)] - [TestCase(@"..\..\..\subfolder1\genericScript.bat", false)] + [TestCase(@"genericScript.bat", true, true)] + [TestCase(@"genericScript.bat", true, false)] + [TestCase(@"..\..\..\subfolder1\genericScript.bat", true, true)] + [TestCase(@"..\..\..\subfolder1\genericScript.bat", true, false)] + [TestCase(@"..\..\..\subfolder1\genericScript.bat", false, true)] + [TestCase(@"..\..\..\subfolder1\genericScript.bat", false, false)] [Platform(Exclude = "Unix,Linux,MacOsX")] - public async Task ScriptExecutorExecutesTheCorrectWorkloadCommandsInWindows(string command, bool packageAvailable) + public async Task ScriptExecutorExecutesTheCorrectWorkloadCommandsInWindows(string command, bool packageAvailable, bool runElevated) { this.SetupTest(PlatformID.Win32NT); - this.mockFixture.Parameters["ScriptPath"] = command; + this.mockFixture.Parameters[nameof(ScriptExecutor.RunElevated)] = runElevated; + this.mockFixture.Parameters[nameof(ScriptExecutor.ScriptPath)] = command; string platformSpecificPath = packageAvailable ? Path.Combine("win-x64") : string.Empty; - this.mockFixture.Parameters["PackageName"] = packageAvailable ? "workloadPackage" : string.Empty; + this.mockFixture.Parameters[nameof(ScriptExecutor.PackageName)] = packageAvailable ? "workloadPackage" : string.Empty; string workingDir = packageAvailable ? this.mockPackage.Path : this.mockFixture.PlatformSpecifics.CurrentDirectory; using (TestScriptExecutor executor = new TestScriptExecutor(this.mockFixture)) @@ -225,16 +229,20 @@ await executor.ExecuteAsync(CancellationToken.None) } [Test] - [TestCase(@"genericScript.sh", true)] - [TestCase(@"../../../subfolder1/genericScript.sh", true)] - [TestCase(@"../../../subfolder1/genericScript.sh", false)] - public async Task ScriptExecutorExecutesTheCorrectWorkloadCommandsInUnix(string command, bool packageAvailable) + [TestCase(@"genericScript.sh", true, true)] + [TestCase(@"genericScript.sh", true, false)] + [TestCase(@"../../../subfolder1/genericScript.sh", true, true)] + [TestCase(@"../../../subfolder1/genericScript.sh", true, false)] + [TestCase(@"../../../subfolder1/genericScript.sh", false, true)] + [TestCase(@"../../../subfolder1/genericScript.sh", false, false)] + public async Task ScriptExecutorExecutesTheCorrectWorkloadCommandsInUnix(string command, bool packageAvailable, bool runElevated) { this.SetupTest(PlatformID.Unix); - this.mockFixture.Parameters["ScriptPath"] = command; + this.mockFixture.Parameters[nameof(ScriptExecutor.RunElevated)] = runElevated; + this.mockFixture.Parameters[nameof(ScriptExecutor.ScriptPath)] = command; string platformSpecificPath = packageAvailable ? Path.Combine("linux-x64") : string.Empty; - this.mockFixture.Parameters["PackageName"] = packageAvailable ? "workloadPackage" : string.Empty; + this.mockFixture.Parameters[nameof(ScriptExecutor.PackageName)] = packageAvailable ? "workloadPackage" : string.Empty; string workingDir = packageAvailable ? this.mockPackage.Path : this.mockFixture.PlatformSpecifics.CurrentDirectory; using (TestScriptExecutor executor = new TestScriptExecutor(this.mockFixture)) @@ -249,7 +257,7 @@ public async Task ScriptExecutorExecutesTheCorrectWorkloadCommandsInUnix(string unixStylePath = unixStylePath.Substring(unixStylePath.IndexOf(':') + 1); // Remove drive letter } - string expectedCommand = $"{unixStylePath} parameter1 parameter2"; + string expectedCommand = $"{(runElevated ? "sudo" : string.Empty)} {unixStylePath} parameter1 parameter2".Trim(); this.mockFixture.ProcessManager.OnCreateProcess = (exe, arguments, workingDirectory) => { diff --git a/src/VirtualClient/VirtualClient.Actions/ScriptExecutor/PowershellExecutor.cs b/src/VirtualClient/VirtualClient.Actions/ScriptExecutor/PowershellExecutor.cs index 88b76ce882..bada79d781 100644 --- a/src/VirtualClient/VirtualClient.Actions/ScriptExecutor/PowershellExecutor.cs +++ b/src/VirtualClient/VirtualClient.Actions/ScriptExecutor/PowershellExecutor.cs @@ -41,7 +41,7 @@ protected override async Task ExecuteAsync(EventContext telemetryContext, Cancel .AddContext(nameof(command), command) .AddContext(nameof(commandArguments), commandArguments); - using (IProcessProxy process = await this.ExecuteCommandAsync(command, commandArguments, this.ExecutableDirectory, telemetryContext, cancellationToken, false)) + using (IProcessProxy process = await this.ExecuteCommandAsync(command, commandArguments, this.ExecutableDirectory, telemetryContext, cancellationToken, this.RunElevated)) { if (!cancellationToken.IsCancellationRequested) { diff --git a/src/VirtualClient/VirtualClient.Actions/ScriptExecutor/PythonExecutor.cs b/src/VirtualClient/VirtualClient.Actions/ScriptExecutor/PythonExecutor.cs index e3c98a7e91..a4a2d1f82e 100644 --- a/src/VirtualClient/VirtualClient.Actions/ScriptExecutor/PythonExecutor.cs +++ b/src/VirtualClient/VirtualClient.Actions/ScriptExecutor/PythonExecutor.cs @@ -60,7 +60,7 @@ protected override async Task ExecuteAsync(EventContext telemetryContext, Cancel .AddContext(nameof(command), command) .AddContext(nameof(commandArguments), commandArguments); - using (IProcessProxy process = await this.ExecuteCommandAsync(command, commandArguments, this.ExecutableDirectory, telemetryContext, cancellationToken, false)) + using (IProcessProxy process = await this.ExecuteCommandAsync(command, commandArguments, this.ExecutableDirectory, telemetryContext, cancellationToken, this.RunElevated)) { if (!cancellationToken.IsCancellationRequested) { diff --git a/src/VirtualClient/VirtualClient.Actions/ScriptExecutor/ScriptExecutor.cs b/src/VirtualClient/VirtualClient.Actions/ScriptExecutor/ScriptExecutor.cs index 72865fc019..e28a23138e 100644 --- a/src/VirtualClient/VirtualClient.Actions/ScriptExecutor/ScriptExecutor.cs +++ b/src/VirtualClient/VirtualClient.Actions/ScriptExecutor/ScriptExecutor.cs @@ -89,6 +89,23 @@ public string ToolName } } + /// + /// True if VC should create elevated process + /// to execute the script. Default = false. + /// + public bool RunElevated + { + get + { + return this.Parameters.GetValue(nameof(this.RunElevated), false); + } + + set + { + this.Parameters[nameof(this.RunElevated)] = value; + } + } + /// /// The full path to the script executable. /// @@ -153,7 +170,7 @@ protected override async Task ExecuteAsync(EventContext telemetryContext, Cancel .AddContext(nameof(command), command) .AddContext(nameof(commandArguments), commandArguments); - using (IProcessProxy process = await this.ExecuteCommandAsync(command, commandArguments, this.ExecutableDirectory, telemetryContext, cancellationToken, false)) + using (IProcessProxy process = await this.ExecuteCommandAsync(command, commandArguments, this.ExecutableDirectory, telemetryContext, cancellationToken, this.RunElevated)) { if (!cancellationToken.IsCancellationRequested) { diff --git a/src/VirtualClient/VirtualClient.Main/profiles/EXAMPLE-EXECUTE-SCRIPT.json b/src/VirtualClient/VirtualClient.Main/profiles/EXAMPLE-EXECUTE-SCRIPT.json index 41f8317752..90cbea20fc 100644 --- a/src/VirtualClient/VirtualClient.Main/profiles/EXAMPLE-EXECUTE-SCRIPT.json +++ b/src/VirtualClient/VirtualClient.Main/profiles/EXAMPLE-EXECUTE-SCRIPT.json @@ -8,11 +8,12 @@ "Parameters": { "CommandLine": "", "ScriptPath": "relativePath\\script.sh", - "LogPaths": "relativePath1\\file1;relativePath2\\subFolder1;*.txt", - "ToolName": "", - "PackageName": "exampleWorkload", - "WorkloadPackage": "exampleworkload.1.1.0.zip", - "FailFast": false + "LogPaths": "relativePath1\\file1;relativePath2\\subFolder1;*.txt", + "ToolName": "", + "PackageName": "exampleWorkload", + "WorkloadPackage": "exampleworkload.1.1.0.zip", + "FailFast": false, + "RunElevated": false }, "Actions": [ { @@ -24,7 +25,8 @@ "LogPaths": "$.Parameters.LogPaths", "ToolName": "$.Parameters.ToolName", "PackageName": "$.Parameters.PackageName", - "FailFast": "$.Parameters.FailFast", + "FailFast": "$.Parameters.FailFast", + "RunElevated": "$.Parameters.RunElevated", "Tags": "Test,VC,Script" } }