azure-sdk-for-net icon indicating copy to clipboard operation
azure-sdk-for-net copied to clipboard

[BUG] ArgumentException 'stream must be seekable' when calling ReplaceContentRunbookDraftAsync.

Open davecader opened this issue 2 years ago • 5 comments

Library name and version

Azure.ResourceManager.Automation 1.0.0

Describe the bug

We are consistently observing an ArgumentException 'stream must be seekable' when calling ReplaceContentRunbookDraftAsync to upload a runbook to Azure Automation. The runbook content was converted to a buffer of UTF encoded bytes and which was then used to create a MemoryStream. We have confirmed that the stream that is being bassed to ReplaceContentRunbookDraftAsync is indeed seekable.

Expected behavior

The runbook content should be uploaded to Azure Automation without error.

Actual behavior

Fails with ArgumentException 'stream must be seekable'.

Reproduction Steps

public async Task UploadRunbookContent(ResourceIdentifier runbookIdentifier, string content) { var options = new InteractiveBrowserCredentialOptions { TenantId = "<Your Tenant ID>" ClientId = "<Your Cliend ID>" RedirectUri = new Uri("<Your Redirect URI>") };

var credential = new InteractiveBrowserCredential(options);
var armClient = new ArmClient(credential);	
AutomationRunbookResource resource = armClient.GetAutomationRunbookResource(runbookIdentifier);

using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(content)))
{
    await resource.ReplaceContentRunbookDraftAsync(WaitUntil.Completed, stream);
}

}

Environment

No response

davecader avatar Jan 03 '23 11:01 davecader

Here is the stack trace:

StackTrace " at Azure.Core.RequestContent.StreamContent..ctor(Stream stream)\r\n at Azure.ResourceManager.Automation.RunbookDraftRestOperations.CreateReplaceContentRequest(String subscriptionId, String resourceGroupName, String automationAccountName, String runbookName, Stream runbookContent)\r\n at Azure.ResourceManager.Automation.AutomationRunbookResource.<ReplaceContentRunbookDraftAsync>d__28.MoveNext()\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter1.GetResult()\r\n at Kelverion.RunbookStudio.Cloud.Client.AutomationRunbookCollectionClient.<DoUpdateAsync>d__9.MoveNext() in C:\\Users\\DavidCader\\source\\repos\\app-automation-console\\Src\\Kelverion.RunbookStudio.Cloud\\Client\\AutomationRunbookCollectionClient.cs:line 134\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.ConfiguredTaskAwaitable1.ConfiguredTaskAwaiter.GetResult()\r\n at Kelverion.RunbookStudio.Cloud.Client.AutomationCollectionClientBase`1.<UpdateAsync>d__13.MoveNext() in C:\Users\DavidCader\source\repos\app-automation-console\Src\Kelverion.RunbookStudio.Cloud\Client\AutomationCollectionClientBase.cs:line 121" string

davecader avatar Jan 03 '23 12:01 davecader

I thought the problem might have been due to disposing the stream explicitly. However, when I updated the code so that the stream was not disposed the same exception was still observed. This is a major blocking issue for us.

davecader avatar Jan 03 '23 12:01 davecader

Thank you for your feedback. Tagging and routing to the team member best able to assist. Please expect delayed responses due to the US holidays.

jsquire avatar Jan 03 '23 13:01 jsquire

It looks like the stream is being disposed, but our code is not explicitly doing so. Investigating further, but now struggling with an Azure.Identity authentication failure.

davecader avatar Jan 05 '23 15:01 davecader

Thanks for reaching out to us, will try to reproduce this issue.

Yao725 avatar Jan 10 '23 08:01 Yao725

I've noticed this bug as well when working on a prototype runBook for my team, which is effectively blocked without a fix for this - both on async and non-async variants of the ReplaceContentRunbookDraft method. It definitely is the case that the stream is being disposed - based on my debugging it appears that it's between the initial call to _runbookDraftRestClient.ReplaceContentAsync and the subsequent call to AutomationArmOperation in Azure.ResourceManager.Automation.AutomationRunbookResource..ReplaceContentRunbookDraft that the dispose occurs, but I'm not 100% sure if that's accurate or just how things appear to be.

ArtificialErmine avatar Jan 13 '23 18:01 ArtificialErmine

This issue is reproduced and confirmed, opened #33907 to fix it.

Yao725 avatar Feb 06 '23 06:02 Yao725

Close this issue as the fix is merged, we will release a new version for automation soon.

Yao725 avatar Feb 08 '23 07:02 Yao725

Have released a new version with the fix of this problem: https://www.nuget.org/packages/Azure.ResourceManager.Automation/1.0.1

Yao725 avatar Feb 16 '23 02:02 Yao725

Confirmed this works only if you define a memory stream directly. It does still have to be seekable. In other words, you cannot generate the stream elsewhere, so the false positive is partly fixed and has a working method. It would still be good to be able to generate a stream from a string with a return or just a string instead of a stream. Is it possible to also do this while we are at it?

using MemoryStream stream = new();
            using StreamWriter writer = new(stream);
            writer.Write(code);
            writer.Flush();
            stream.Seek(0, SeekOrigin.Begin);
            _ = await runbook.ReplaceContentRunbookDraftAsync(WaitUntil.Completed, stream);
            //_ = await runbook.ReplaceContentRunbookDraftAsync(WaitUntil.Completed, Globals.GenerateStreamFromString(code));

AASPLLC avatar Feb 16 '23 17:02 AASPLLC

It's correct that the stream that is being passed to ReplaceContentRunbookDraft has to be seekable. Here what I fixed is that we shouldn't get the exception stream must be seekable with a seekable stream. And back to the question about changing the type of this parameter to string, our SDK is based on the API spec, so please open an issue here to let the service team know this need.

Yao725 avatar Feb 17 '23 05:02 Yao725