Skip to content

Commit

Permalink
RavenDB-21858 Cannot download the dump file generated by /admin/debug…
Browse files Browse the repository at this point in the history
…/dump endpoint
  • Loading branch information
arekpalinski committed Jan 10, 2024
1 parent c709374 commit ccd1d2e
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 5 deletions.
3 changes: 3 additions & 0 deletions src/Raven.Server/Web/System/AdminDumpHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ private static void Execute(string args, int processId, string output)

var sb = new StringBuilder($"{args} --pid {processId} --output {CommandLineArgumentEscaper.EscapeSingleArg(output)}");

if (PlatformDetails.RunningOnPosix)
sb.Append($" --output-owner {Environment.UserName}"); // make sure we'll be able to download the output file and delete it once HTTP request completes

var startup = new ProcessStartInfo
{
Arguments = sb.ToString(),
Expand Down
14 changes: 12 additions & 2 deletions tools/Raven.Debug/CommandLineApp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ public static int Run(string[] args)
var pidOption = cmd.Option("--pid", "Process ID to which the tool will attach to", CommandOptionType.SingleValue);
var outputOption = cmd.Option("--output", "Output file path", CommandOptionType.SingleValue);
var typeOption = cmd.Option("--type", "Type of dump (Heap or Mini). ", CommandOptionType.SingleValue);
var outputOwnerOption = cmd.Option("--output-owner", "The owner of the output file (applicable only to Posix based OS)", CommandOptionType.SingleValue);

cmd.OnExecuteAsync(async (_) =>
{
Expand All @@ -151,10 +152,14 @@ public static int Run(string[] args)
if (outputOption.HasValue())
output = outputOption.Value();

string outputOwner = null;
if (outputOwnerOption.HasValue())
outputOwner = outputOwnerOption.Value();

try
{
var dumper = new Dumper();
await dumper.Collect(cmd, pid, output, diag: false, type).ConfigureAwait(false);
await dumper.Collect(cmd, pid, output, outputOwner, diag: false, type).ConfigureAwait(false);
return 0;
}
catch (Exception e)
Expand All @@ -173,6 +178,7 @@ public static int Run(string[] args)
var outputOption = cmd.Option("--output", "Output file path", CommandOptionType.SingleValue);
var timeoutOption = cmd.Option("--timeout", "Give up on collecting the gcdump if it takes longer than this many seconds. The default value is. Default 30", CommandOptionType.SingleValue);
var verboseOption = cmd.Option("--verbose", "Output the log while collecting the gcdump.", CommandOptionType.NoValue);
var outputOwnerOption = cmd.Option("--output-owner", "The owner of the output file (applicable only to Posix based OS)", CommandOptionType.SingleValue);

cmd.OnExecuteAsync(async token =>
{
Expand All @@ -186,6 +192,10 @@ public static int Run(string[] args)
if (outputOption.HasValue())
output = outputOption.Value();

string outputOwner = null;
if (outputOwnerOption.HasValue())
outputOwner = outputOwnerOption.Value();

int timeout = 30;
if (timeoutOption.HasValue() && int.TryParse(timeoutOption.Value(), out timeout) == false)
return cmd.ExitWithError($"Could not parse --timeout with value '{timeoutOption.Value()}' to number.");
Expand All @@ -194,7 +204,7 @@ public static int Run(string[] args)

try
{
await GCHeapDumper.Collect(token, cmd, pid, output, timeout, verbose).ConfigureAwait(false);
await GCHeapDumper.Collect(token, cmd, pid, output, outputOwner, timeout, verbose).ConfigureAwait(false);
return 0;
}
catch (Exception e)
Expand Down
5 changes: 4 additions & 1 deletion tools/Raven.Debug/Dump/Dumper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public Dumper()
{
}

public async Task<int> Collect(CommandLineApplication cmd, int processId, string output, bool diag, DumpTypeOption type)
public async Task<int> Collect(CommandLineApplication cmd, int processId, string output, string outputOwner, bool diag, DumpTypeOption type)
{
if (processId == 0)
{
Expand Down Expand Up @@ -66,6 +66,9 @@ public async Task<int> Collect(CommandLineApplication cmd, int processId, string

// Send the command to the runtime to initiate the core dump
client.WriteDump(dumpType, output, diag);

if (string.IsNullOrEmpty(outputOwner) == false)
PosixFileExtensions.ChangeFileOwner(output, outputOwner);
}
else
{
Expand Down
12 changes: 10 additions & 2 deletions tools/Raven.Debug/GCDump/GCHeapDumper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using McMaster.Extensions.CommandLineUtils;
using Raven.Debug.Utils;
using Sparrow;
using Sparrow.Platform;

namespace Microsoft.Diagnostics.Tools.GCDump
{
Expand All @@ -24,7 +25,7 @@ internal static class GCHeapDumper
/// <param name="processId">The process to collect the gcdump from.</param>
/// <param name="output">The output path for the collected gcdump.</param>
/// <returns></returns>
public static async Task<int> Collect(CancellationToken ct, CommandLineApplication cmd, int processId, string output, int timeout, bool verbose)
public static async Task<int> Collect(CancellationToken ct, CommandLineApplication cmd, int processId, string output, string outputOwner, int timeout, bool verbose)
{
try
{
Expand Down Expand Up @@ -63,6 +64,13 @@ public static async Task<int> Collect(CancellationToken ct, CommandLineApplicati
return false;
memoryGraph.AllowReading();
GCHeapDump.WriteMemoryGraph(memoryGraph, outputFileInfo.FullName, "dotnet-gcdump");

if (string.IsNullOrEmpty(outputOwner) == false && PlatformDetails.RunningOnPosix)
{
cmd.Out.WriteLine($"Changing owner of '{outputFileInfo.FullName}' to '{outputOwner}'");
PosixFileExtensions.ChangeFileOwner(outputFileInfo.FullName, outputOwner);
}

return true;
});

Expand All @@ -81,7 +89,7 @@ public static async Task<int> Collect(CancellationToken ct, CommandLineApplicati
}
else
{
cmd.Out.WriteLine($"\tFailed to collect gcdump. Try running with '-v' for more information.");
cmd.Out.WriteLine($"\tFailed to collect gcdump. Try running with '--verbose' for more information.");
return -1;
}
}
Expand Down
40 changes: 40 additions & 0 deletions tools/Raven.Debug/Utils/PosixFileExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;
using System.Diagnostics;
using Sparrow.Platform;

namespace Raven.Debug.Utils;

public static class PosixFileExtensions
{
public static void ChangeFileOwner(string fileName, string owner)
{
if (PlatformDetails.RunningOnPosix == false)
throw new InvalidOperationException("This method is supposed to be called only on Posix systems");

var startup = new ProcessStartInfo
{
FileName = "chown",
Arguments = $"{owner}:{owner} {fileName}",
UseShellExecute = false,
RedirectStandardOutput = false,
RedirectStandardError = true
};

var process = new Process
{
StartInfo = startup,
EnableRaisingEvents = true
};

process.Start();
process.WaitForExit();


if (process.ExitCode == 0)
return;

var error = process.StandardError.ReadToEnd();

throw new InvalidOperationException($"Error changing file owner: {error}");
}
}

0 comments on commit ccd1d2e

Please sign in to comment.