I am trying to use the POST api/admin/v1/workflows/ API to send a workflow to our company gallery. I am creating the request in Python (for a custom tool) so I can implement this capability into an Alteryx workflow. When I run the Python code I get a 500 response with an UnknownException. The gallery log gives me a stack trace that looks like this:
2019-05-17 14:00:33.684786,ERROR,197,ErrorHandler,HandleError,,,,,,,,,,Exception caught by ErrorHandler and marshalled to client,"Ionic.Zip.BadReadException: ZipEntry::ReadHeader(): Bad signature (0x6D783F3C) at position 0x00000000-> at Ionic.Zip.ZipEntry.ReadHeader(ZipEntry ze, Encoding defaultEncoding)-> at Ionic.Zip.ZipEntry.ReadEntry(ZipContainer zc, Boolean first)-> at Ionic.Zip.ZipFile.ReadIntoInstance_Orig(ZipFile zf)-> at Ionic.Zip.ZipFile.ReadIntoInstance(ZipFile zf)-> at Ionic.Zip.ZipFile.Read(String fileName, TextWriter statusMessageWriter, Encoding encoding, EventHandler`1 readProgress)-> at DotNetZipCompression.CompressionEngine.GetArchiveComment(String archiveFile)-> at Alteryx.Cloud.Engine.AppEngine.GetWorkflowsFromPackage(String packageFile)-> at Alteryx.Cloud.Models.Presenters.AdminApiPresenter.PublishApp(AppFileInfo fileInfo, ExecutionModeType runMode, Int32 validationPriority, String requestId)-> at Alteryx.Cloud.Models.Presenters.AdminApiPresenter.<PublishAppAsync>d__24.MoveNext()->--- End of stack trace from previous location where exception was thrown ----> at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()-> at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)-> at Alteryx.Cloud.Server.Services.Api.AdminApiServiceV1.<PublishYxzp>d__10.MoveNext()->--- End of stack trace from previous location where exception was thrown ----> at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()-> at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)-> at System.ServiceModel.Dispatcher.TaskMethodInvoker.<InvokeAsync>d__16.MoveNext()->--- End of stack trace from previous location where exception was thrown ----> at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()-> at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)-> at System.ServiceModel.Dispatcher.TaskMethodInvoker.InvokeEnd(Object instance, Object[]& outputs, IAsyncResult result)-> at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeEnd(MessageRpc& rpc)-> at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage7(MessageRpc& rpc)-> at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)"
The python HTTP request is being made to the following URL:
http://my_gallery_address/api/admin/v1/workflows/?oauth_timestamp=1558456741&oauth_signature_method=HMAC-SHA1&oauth_consumer_key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&oauth_version=1.0&oauth_nonce=000000&oauth_signature=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
The headers in the request look like this:
{'User-Agent': 'python-requests/2.21.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Length': '2807', 'Content-Type': 'multipart/form-data; boundary=d1062b6b42d7777ea9f33c8329d169f9'}
The body of the request looks like this:
--d1062b6b42d7777ea9f33c8329d169f9\r\nContent-Disposition: form-data; name="file"; filename="Test.yxmd"\r\n\r\n<?xml version="1.0"?>\r\n<AlteryxDocument yxmdVer="2019.1">\r\n <Nodes>\r\n <Node ToolID="1">\r\n <GuiSettings Plugin="AlteryxBasePluginsGui.TextInput.TextInput">\r\n <Position x="186" y="162" />\r\n </GuiSettings>\r\n <Properties>\r\n <Configuration>\r\n <NumRows value="1" />\r\n <Fields>\r\n <Field name="Field1" />\r\n </Fields>\r\n <Data>\r\n <r>\r\n <c>A</c>\r\n </r>\r\n </Data>\r\n </Configuration>\r\n <Annotation DisplayMode="0">\r\n <Name />\r\n <DefaultAnnotationText />\r\n <Left value="False" />\r\n </Annotation>\r\n </Properties>\r\n <EngineSettings EngineDll="AlteryxBasePluginsEngine.dll" EngineDllEntryPoint="AlteryxTextInput" />\r\n </Node>\r\n </Nodes>\r\n <Connections />\r\n <Properties>\r\n <Memory default="True" />\r\n <GlobalRecordLimit value="0" />\r\n <TempFiles default="True" />\r\n <Annotation on="True" includeToolName="False" />\r\n <ConvErrorLimit value="10" />\r\n <ConvErrorLimit_Stop value="False" />\r\n <CancelOnError value="False" />\r\n <DisableBrowse value="False" />\r\n <EnablePerformanceProfiling value="False" />\r\n <DisableAllOutput value="False" />\r\n <ShowAllMacroMessages value="False" />\r\n <ShowConnectionStatusIsOn value="True" />\r\n <ShowConnectionStatusOnlyWhenRunning value="True" />\r\n <ZoomLevel value="0" />\r\n <LayoutType>Horizontal</LayoutType>\r\n <MetaInfo>\r\n <NameIsFileName value="True" />\r\n <Name>Test</Name>\r\n <Description />\r\n <RootToolName />\r\n <ToolVersion />\r\n <ToolInDb value="False" />\r\n <CategoryName />\r\n <SearchTags />\r\n <Author />\r\n <Company />\r\n <Copyright />\r\n <DescriptionLink actual="" displayed="" />\r\n <Example>\r\n <Description />\r\n <File />\r\n </Example>\r\n </MetaInfo>\r\n <Events>\r\n <Enabled value="True" />\r\n </Events>\r\n </Properties>\r\n</AlteryxDocument>\r\n--d1062b6b42d7777ea9f33c8329d169f9\r\nContent-Disposition: form-data; name="name"\r\n\r\nTest\r\n--d1062b6b42d7777ea9f33c8329d169f9\r\nContent-Disposition: form-data; name="owner"\r\n\r\nme@email.com\r\n--d1062b6b42d7777ea9f33c8329d169f9\r\nContent-Disposition: form-data; name="validate"\r\n\r\nfalse\r\n--d1062b6b42d7777ea9f33c8329d169f9\r\nContent-Disposition: form-data; name="isPublic"\r\n\r\ntrue\r\n--d1062b6b42d7777ea9f33c8329d169f9\r\nContent-Disposition: form-data; name="sourceId"\r\n\r\n\r\n--d1062b6b42d7777ea9f33c8329d169f9\r\nContent-Disposition: form-data; name="workerTag"\r\n\r\n\r\n--d1062b6b42d7777ea9f33c8329d169f9\r\nContent-Disposition: form-data; name="canDownload"\r\n\r\ntrue\r\n--d1062b6b42d7777ea9f33c8329d169f9--\r\n
At this point, I cannot determine whether the error is caused by an issue with my request or something wrong on the Alteryx side. I suspect the former, but have no clue how to fix it. Does anyone have experience hitting this particular API and how the request needs to be formatted? The code for my custom tool is attached - it works when I target some of the GET APIs, but not this POST API.
Solved! Go to Solution.
That API does not accept .yxmd workflows. Try this with a .yxzp.
That was it, thanks so much, @TanyaS! Very cool to see Alteryx deploying Alteryx.
Hi @tlarsen7572
Can you please share details on steps or workflow which can be helpful for automated workflow deployment from one server to another server?
Hi@TanyaS
If Alteryx gallery API does not accept .yxmd workflows to post/upload then won't it impact functionality where need to upload it as .yxzp.?
Appreciate your inputs here
@neeleshapatil1, I am still building the process, so I don't have all of the details yet. At this point, I am not actually trying to deploy from one server to another. Rather, I am simply trying to publish some workflows from a directory on my disk drive to the gallery. Ideally, I want to be able to publish yxmd/yxwz files directly without having to first export them as yxzp. But I am running into a problem with this and will be creating a new discussion to see if there is a way around it.
@neeleshapatil1Here is a link for steps on how to automate workflow deployment from one Server to another: https://community.alteryx.com/t5/Alteryx-Server-Knowledge-Base/Migrating-Workflows/ta-p/335774
.yxzp workflows are .yxmd workflows with included dependencies. The functionality should not differ as the format just ensures that required data is included. If you see any deviations though, please let me know!