/// <summary> /// Ensures that the <see cref="TestDistroName"/> does not exist from a past test run. /// </summary> public static void RemoveTestDistro() { if (Wsl2Proxy.Exists(TestDistroName)) { Wsl2Proxy.Unregister(TestDistroName); } }
public async Task PathMapping() { // Verify that file system path mapping works in both directions. var imagePath = await TestHelper.GetTestImageAsync(); using (var tempFolder = new TempFolder()) { try { Wsl2Proxy.Import(TestHelper.TestDistroName, imagePath, tempFolder.Path); var distro = new Wsl2Proxy(TestHelper.TestDistroName, user: KubeConst.SysAdminUser); // Linux --> Windows Assert.Equal($@"\\wsl$\{distro.Name}\", distro.ToWindowsPath("/")); Assert.Equal($@"\\wsl$\{distro.Name}\bin\bash", distro.ToWindowsPath("/bin/bash")); // Windows --> Linux Assert.Equal("/mnt/c/", distro.ToLinuxPath(@"C:\")); Assert.Equal("/mnt/c/Program Files/test.exe", distro.ToLinuxPath(@"c:\Program Files\test.exe")); } finally { TestHelper.RemoveTestDistro(); } } }
public async Task Execute_WithPathSpaces() { // Verify that we can execute SUDO and non-SUDO commands from a temporary // folder that includes spaces. This happens when the user's Windows username // include spaces. var imagePath = await TestHelper.GetTestImageAsync(); using (var folderWithSpaces = new TempFolder(folder: Path.Combine(Path.GetTempPath(), $"test {Guid.NewGuid().ToString("d")}"))) { using (var tempFolder = new TempFolder()) { try { Wsl2Proxy.Import(TestHelper.TestDistroName, imagePath, tempFolder.Path); var distro = new Wsl2Proxy(TestHelper.TestDistroName, user: KubeConst.SysAdminUser); distro.TempFolder = folderWithSpaces.Path; Assert.Contains("Hello World!", distro.Execute("echo", "Hello World!").OutputText); Assert.Contains("Hello World!", distro.SudoExecute("echo", "Hello World!").OutputText); } finally { TestHelper.RemoveTestDistro(); } } } }
public async Task UploadFile() { // Verify that we can upload a text file to the distribution // and set its owner and permissions. var imagePath = await TestHelper.GetTestImageAsync(); using (var tempFolder = new TempFolder()) { try { Wsl2Proxy.Import(TestHelper.TestDistroName, imagePath, tempFolder.Path); var distro = new Wsl2Proxy(TestHelper.TestDistroName, user: KubeConst.SysAdminUser); var text = @"Line 1 Line 2 Line 3 Line 4 "; // Write a file using the defaults to convert CRLF-->LF with // no special permissions. distro.UploadFile($"/home/{KubeConst.SysAdminUser}/test1.txt", text, toLinuxText: true); Assert.Equal("Line 1\nLine 2\nLine 3\nLine 4\n", File.ReadAllText(distro.ToWindowsPath($"/home/{KubeConst.SysAdminUser}/test1.txt"))); var response = distro.SudoExecute("ls", "-l", $"/home/{KubeConst.SysAdminUser}/test1.txt"); response.EnsureSuccess(); Assert.StartsWith("-rw-r--r-- ", response.OutputText); // Write another file using the leaving the line endings as CRLF // and some permissions. Also verify that the file is owned by // the default distro user. distro.UploadFile($"/home/{KubeConst.SysAdminUser}/test2.txt", text, permissions: "666", toLinuxText: false); Assert.Equal("Line 1\r\nLine 2\r\nLine 3\r\nLine 4\r\n", File.ReadAllText(distro.ToWindowsPath($"/home/{KubeConst.SysAdminUser}/test2.txt"))); response = distro.SudoExecute("ls", "-l", $"/home/{KubeConst.SysAdminUser}/test2.txt"); response.EnsureSuccess(); Assert.StartsWith("-rw-rw-rw- ", response.OutputText); Assert.Contains($"{KubeConst.SysAdminUser} {KubeConst.SysAdminUser}", response.OutputText); } finally { TestHelper.RemoveTestDistro(); } } }
public async Task ImportExport() { // Verify that we can import and export distributions. var imagePath = await TestHelper.GetTestImageAsync(); using (var tempFolder = new TempFolder()) { try { //--------------------------------------------------------- // Import the distribution and verify that we can execute a command. Wsl2Proxy.Import(TestHelper.TestDistroName, imagePath, tempFolder.Path); Assert.True(Wsl2Proxy.Exists(TestHelper.TestDistroName)); var distro = new Wsl2Proxy(TestHelper.TestDistroName); Assert.Equal(TestHelper.TestDistroName, distro.Name); Assert.Contains("Hello World!", distro.Execute("echo", "Hello World!").OutputText); //--------------------------------------------------------- // Terminate the distribution and verify that we can export it. var exportPath = Path.Combine(tempFolder.Path, "export.tar"); Wsl2Proxy.Terminate(TestHelper.TestDistroName); Wsl2Proxy.Export(TestHelper.TestDistroName, exportPath); //--------------------------------------------------------- // Remove the test distribution and verify that we can regenerate // it from the image we just exported. TestHelper.RemoveTestDistro(); Wsl2Proxy.Import(TestHelper.TestDistroName, exportPath, tempFolder.Path); Assert.True(Wsl2Proxy.Exists(TestHelper.TestDistroName)); distro = new Wsl2Proxy(TestHelper.TestDistroName, user: KubeConst.SysAdminUser); Assert.Contains("Hello World!", distro.Execute("echo", "Hello World!").OutputText); } finally { TestHelper.RemoveTestDistro(); } } }
public async Task StartAs_Sysadmin() { // Verify that we can start a distro as [sysadmin] without configuring // or starting systemd. var imagePath = await TestHelper.GetTestImageAsync(); using (var tempFolder = new TempFolder()) { try { Wsl2Proxy.Import(TestHelper.TestDistroName, imagePath, tempFolder.Path); // Start as the [sysadmin] user. var distro = new Wsl2Proxy(TestHelper.TestDistroName, user: KubeConst.SysAdminUser); Assert.Equal(KubeConst.SysAdminUser, distro.User); // Expecting to be running under MSFT's [init] process 1. var response = distro.Execute("ps", "-e"); Assert.Equal(0, response.ExitCode); Assert.Contains("init", response.OutputText); // Expecting to be logged in as [root] response = distro.Execute("echo", "$LOGNAME"); Assert.Equal(0, response.ExitCode); Assert.Equal(KubeConst.SysAdminUser, response.OutputText.Trim()); } finally { TestHelper.RemoveTestDistro(); } } }
public async Task NoSudoPassword() { // Verify that the distribution doesn't prompt for a SUDO password. var imagePath = await TestHelper.GetTestImageAsync(); using (var tempFolder = new TempFolder()) { try { Wsl2Proxy.Import(TestHelper.TestDistroName, imagePath, tempFolder.Path); Assert.True(Wsl2Proxy.Exists(TestHelper.TestDistroName)); var distro = new Wsl2Proxy(TestHelper.TestDistroName, user: KubeConst.SysAdminUser); Assert.Contains("Hello World!", distro.SudoExecute("echo", "Hello World!").OutputText); } finally { TestHelper.RemoveTestDistro(); } } }
public async Task Execute() { // Verify that we can execute SUDO and non-SUDO commands. var imagePath = await TestHelper.GetTestImageAsync(); using (var tempFolder = new TempFolder()) { try { Wsl2Proxy.Import(TestHelper.TestDistroName, imagePath, tempFolder.Path); var distro = new Wsl2Proxy(TestHelper.TestDistroName, user: KubeConst.SysAdminUser); Assert.Contains("Hello World!", distro.Execute("echo", "Hello World!").OutputText); Assert.Contains("Hello World!", distro.SudoExecute("echo", "Hello World!").OutputText); } finally { TestHelper.RemoveTestDistro(); } } }
/// <inheritdoc/> public override async Task RunAsync(CommandLine commandLine) { if (commandLine.HasHelpOption || commandLine.Arguments.Length == 0) { Console.WriteLine(usage); Program.Exit(0); } var sourceFolder = commandLine.Arguments.ElementAtOrDefault(0); var outputPath = commandLine.Arguments.ElementAtOrDefault(1); var sbGccArgs = new StringBuilder(); if (string.IsNullOrEmpty(sourceFolder) || string.IsNullOrEmpty(outputPath)) { Console.WriteLine(usage); Program.Exit(1); } foreach (var arg in commandLine.Arguments.Skip(2)) { sbGccArgs.AppendWithSeparator(arg); } // We're going to build this within the distro at [/tmp/wsl-util/GUID] by // recursively copying the contents of SOURCE-FOLDER to this directory, // running GCC to build the thing, passing [*.c] to include all of the C // source files and generating the binary as [output.bin] with the folder. // // We're also going to clear the [/tmp/wsl-util] folder first to ensure that we don't // accumulate any old build files over time and we'll also ensure that // [gcc] is installed. var defaultDistro = Wsl2Proxy.GetDefault(); if (string.IsNullOrEmpty(defaultDistro)) { Console.Error.WriteLine("*** ERROR: There is no default WSL2 distro."); Program.Exit(1); } var distro = new Wsl2Proxy(defaultDistro); if (!distro.IsDebian) { Console.Error.WriteLine($"*** ERROR: Your default WSL2 distro [{distro.Name}] is running: {distro.OSRelease["ID"]}/{distro.OSRelease["ID_LIKE"]}"); Console.Error.WriteLine($" The CRI-O build requires an Debian/Ubuntu based distribution."); Program.Exit(1); } var linuxUtilFolder = LinuxPath.Combine("/", "tmp", "wsl-util"); var linuxBuildFolder = LinuxPath.Combine(linuxUtilFolder, Guid.NewGuid().ToString("d")); var linuxOutputPath = LinuxPath.Combine(linuxBuildFolder, "output.bin"); var windowsUtilFolder = distro.ToWindowsPath(linuxUtilFolder); var windowsBuildFolder = distro.ToWindowsPath(linuxBuildFolder); try { // Delete the [/tmp/wsl-util] folder on Linux and the copy the // source from the Windows side into a fresh distro folder. NeonHelper.DeleteFolder(windowsUtilFolder); NeonHelper.CopyFolder(sourceFolder, windowsBuildFolder); // Install [safe-apt-get] if it's not already present. We're using this // because it's possible that projects build in parallel and it's possible // that multiple GCC commands could also be running in parallel. var linuxSafeAptGetPath = "/usr/bin/safe-apt-get"; var windowsSafeAptGetPath = distro.ToWindowsPath(linuxSafeAptGetPath); if (!File.Exists(windowsSafeAptGetPath)) { var resources = Assembly.GetExecutingAssembly().GetResourceFileSystem("WslUtil.Resources"); var toolScript = resources.GetFile("/safe-apt-get.sh").ReadAllText(); // Note that we need to escape all "$" characters in the script // so the upload script won't attempt to replace any variables // (with blanks). toolScript = toolScript.Replace("$", "\\$"); var uploadScript = $@" cat <<EOF > {linuxSafeAptGetPath} {toolScript} EOF chmod 754 {linuxSafeAptGetPath} "; distro.SudoExecuteScript(uploadScript).EnsureSuccess(); } // Perform the build. var buildScript = $@" set -euo pipefail safe-apt-get install -yq gcc cd {linuxBuildFolder} gcc *.c -o {linuxOutputPath} {sbGccArgs} "; distro.SudoExecuteScript(buildScript).EnsureSuccess(); // Copy the build output to the Windows output path. Directory.CreateDirectory(Path.GetDirectoryName(outputPath)); NeonHelper.DeleteFile(outputPath); File.Copy(distro.ToWindowsPath(linuxOutputPath), outputPath); } finally { // Remove the temporary distro folder. NeonHelper.DeleteFolder(windowsBuildFolder); } await Task.CompletedTask; }