Azure Media Services v3 create asset filter returns BadRequest - azure-media-services

Azure Media Services v3 create asset filter returns BadRequest.
Both code and manifest are included below. Asset duration is 00:00:26.4330000
Have tried adjusting the tracks, no tracks.
Have tried adjusting the time parameters.
Any ideas on what is wrong?
Is it possible for the API to report more information on what is wrong?
Can a sample be created that shows how to use AssetFilters.CreateOrUpdate with and without track filters?
Code
var timingData = GetManifestTimingData(new Uri(asset.ManifestUrl));
Log.Info($"Timescale: {timingData.TimeScale} Offset: {timingData.TimestampOffset} clip: ( {TimeSpan.FromSeconds(startTimeSec)} - {TimeSpan.FromSeconds(endTimeSec)} ) as ( {TimeSpan.FromSeconds(startTimeSec)} to {TimeSpan.FromSeconds(endTimeSec)} ) {name} ----- {asset.ToAssetInfo()?.hashKey} {asset.Name} -- Manifest: {asset.PlaybackUrl}");
if (startTimeSec >= timingData.AssetDuration.TotalSeconds)
{
Log.Error($"Invalid start time: {startTimeSec} > {timingData.AssetDuration}");
return null;
}
if (endTimeSec >= timingData.AssetDuration.TotalSeconds)
{
endTimeSec = (int)Math.Floor(timingData.AssetDuration.TotalSeconds);
}
var startTimeSpan = timingData.OffSetAsTimeSpan + TimeSpan.FromSeconds(startTimeSec);
var endTimeSpan = timingData.OffSetAsTimeSpan + TimeSpan.FromSeconds(endTimeSec);
double timeScale = timingData.TimeScale ?? TimeSpan.TicksPerSecond;
var scaledStartTime = Convert.ToInt64(Math.Truncate(startTimeSpan.Ticks * (timeScale / TimeSpan.TicksPerSecond)));
var scaledEndTime = Convert.ToInt64(Math.Truncate(endTimeSpan.Ticks * (timeScale / TimeSpan.TicksPerSecond)));
var range = new PresentationTimeRange(scaledStartTime, scaledEndTime, 9223372036854775807, 0, (long)timeScale, false);
var tracks = new List<FilterTrackSelection>
{
new FilterTrackSelection(new List<FilterTrackPropertyCondition>
{
new FilterTrackPropertyCondition(FilterTrackPropertyType.Type, "Audio", FilterTrackPropertyCompareOperation.Equal),
}),
new FilterTrackSelection(new List<FilterTrackPropertyCondition>
{
new FilterTrackPropertyCondition(FilterTrackPropertyType.Type, "Video", FilterTrackPropertyCompareOperation.Equal),
}),
};
var firstQuality = new FirstQuality(128000);
var filterParams = new AssetFilter(null, name, FilterType, range, firstQuality, tracks);
var filter = _client.AssetFilters.CreateOrUpdate(ResourceGroup, AccountName, asset.Id, name, filterParams);
if (filter == null)
{
Log.Warn($"Failed to create filter {name} in {asset}");
return null;
}
return filter;
Manifest
<SmoothStreamingMedia MajorVersion="2" MinorVersion="2" Duration="264333333" TimeScale="10000000">
<StreamIndex Chunks="13" Type="video" Url="QualityLevels({bitrate})/Fragments(video={start time})" QualityLevels="1">
<QualityLevel Index="0" Bitrate="770760" FourCC="H264" MaxWidth="1280" MaxHeight="720" CodecPrivateData="000000016764001FACD9405005BA10000003001000000303C0F18319600000000168EBECB22C" />
<c t="0" d="20333333" r="2" />
<c d="20333334" />
<c d="20333333" r="2" />
<c d="20333334" />
<c d="20333333" r="2" />
<c d="20333334" />
<c d="20333333" r="2" />
<c d="20333334" />
<c d="20333333" />
</StreamIndex>
<StreamIndex Chunks="14" Type="audio" Url="QualityLevels({bitrate})/Fragments(aac_UND_2_127999={start time})" QualityLevels="1" Name="aac_UND_2_127999">
<QualityLevel AudioTag="255" Index="0" BitsPerSample="16" Bitrate="127999" FourCC="AACL" CodecPrivateData="1190" Channels="2" PacketSize="4" SamplingRate="48000" />
<c t="0" d="20053333" r="2" />
<c d="20053334" />
<c d="20053333" r="2" />
<c d="20053334" />
<c d="20053333" r="2" />
<c d="20053334" />
<c d="20053333" r="2" />
<c d="20053334" />
<c d="20053333" />
<c d="3626667" />
</StreamIndex>
<Protection>
<ProtectionHeader SystemID="B47B251A-2409-4B42-958E-08DBAE7B4EE9">
<ContentProtection schemeIdUri="urn:mpeg:dash:sea:2012" xmlns:sea="urn:mpeg:dash:schema:sea:2012">
<sea:SegmentEncryption schemeIdUri="urn:mpeg:dash:sea:aes128-cbc:2013" />
<sea:KeySystem keySystemUri="urn:mpeg:dash:sea:keysys:http:2013" />
<sea:CryptoPeriod IV="0xF6BCAD06C97D0FEC81B702C86183355B" keyUriTemplate="https://testurstream.keydelivery.westus.media.azure.net?kid=d6c1f008-d43f-4c60-926f-76ba613b7b4b" />
</ContentProtection>
</ProtectionHeader>
</Protection>
</SmoothStreamingMedia>

There was a known bug that we hit with Asset Filters that was fixed and rolled out to production now. Looks like you may have hit the same bug. The team is working on also fixing this issue in the .NET SDK and rolling it out.
For now, can you first delete any and all old filters created in v3 API. To fix the issue, you need to remove all old asset and global filters first from this account. We had a versioning mis-match on the filters when we moved from preview to GA that caused a mismatch (and thus the error message you are seeing.) You should be able to get a more detailed error message also if you look at the stacktrace. It typically would show a version conflict issue. Let us know what you see in the details of the error.

Carlos,
Looking at this today for you. Sorry for delay.
I'm using the Postman collection just to see what is going on with the .NET SDK exactly.
Looks like the following filer works fine. I think that the issue you are getting is related to the line of code that creates the new PresentationTimeRange. The values for presentaitonWindowDuration and liveBackoffDuration are not needed for a VOD filter. They are only used for live filters. Try using the following.
new PresentationTimeRange(scaledStartTime, scaledEndTime, null, null, (long)timeScale, null);
{
"properties": {
"presentationTimeRange": {
"startTimestamp": 0,
"endTimestamp": 264333333,
"presentationWindowDuration": null,
"liveBackoffDuration": null,
"timescale": 10000000,
"forceEndTimestamp": null
},
"tracks": [{
"trackSelections": [{
"property": "Type",
"operation": "Equal",
"value": "Video"
},
{
"property": "Type",
"operation": "Equal",
"value": "Audio"
}
]
}]
}
}
I'll double check to see if this is an issue when I run it through the .NET SDK.
I think that our issue here may be that the values for presentationTimeRange are all marked as "REQUIRED" in the current Swagger file here:
https://github.com/Azure/azure-rest-api-specs/blob/dec75495352902ebb6393d42c50465b6195f239d/specification/mediaservices/resource-manager/Microsoft.Media/stable/2018-07-01/AccountFilters.json#L63

Related

SWXMLHash can't parse a [XMLIndexer]

I am trying for first time to parse a XML file and I am using SWXMLHash.
My xml file is:
<weatherdata xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://api.met.no/weatherapi/locationforecast/1.9/schema" created="2018-02-13T18:12:31Z">
<meta>
<model name="LOCAL" termin="2018-02-13T12:00:00Z" runended="2018-02-13T14:27:32Z" nextrun="2018-02-13T22:00:00Z" from="2018-02-13T19:00:00Z" to="2018-02-16T06:00:00Z" />
<model name="EPS" termin="2018-02-13T00:00:00Z" runended="2018-02-13T09:03:05Z" nextrun="2018-02-13T22:00:00Z" from="2018-02-16T12:00:00Z" to="2018-02-22T18:00:00Z" />
</meta>
<product class="pointData">
<time datatype="forecast" from="2018-02-13T19:00:00Z" to="2018-02-13T19:00:00Z">
<location altitude="0" latitude="" longitude="">
<temperature id="TTT" unit="celsius" value="3.5"/>
<windDirection id="dd" deg="158.8" name="S"/>
<windSpeed id="ff" mps="8.8" beaufort="5" name="Frisk bris"/>
<windGust id="ff_gust" mps="15.0"/>
<areaMaxWindSpeed mps="13.8"/>
<humidity value="82.1" unit="percent"/>
<pressure id="pr" unit="hPa" value="1002.5"/>
<cloudiness id="NN" percent="99.3"/>
<fog id="FOG" percent="0.0"/>
<lowClouds id="LOW" percent="73.2"/>
<mediumClouds id="MEDIUM" percent="0.0"/>
<highClouds id="HIGH" percent="91.0"/>
<dewpointTemperature id="TD" unit="celsius" value="0.6"/>
</location>
</time>
The <time> </time> repeates.
Having made a let parsedResultXML = SWXMLHash.parse(data)
I am trying to parse with a for in loop
for node in parsedResultXML["weatherdata"]["product"]["time"].all{
print(node)
}
I get results
<time to="2018-02-14T01:00:00Z" from="2018-02-14T01:00:00Z" datatype="forecast">
<location latitude="" longitude="" altitude="0">
<temperature id="TTT" unit="celsius" value="3.4"></temperature>
<windDirection id="dd" name="S" deg="158.7"></windDirection>
<windSpeed name="Liten kuling" mps="11.1" id="ff" beaufort="6"></windSpeed>
<windGust id="ff_gust" mps="19.0"></windGust>
<areaMaxWindSpeed mps="17.5"></areaMaxWindSpeed>
<humidity unit="percent" value="88.3"></humidity>
<pressure id="pr" unit="hPa" value="1002.5"></pressure>
<cloudiness id="NN" percent="99.3"></cloudiness>
<fog id="FOG" percent="0.1"></fog>
<lowClouds id="LOW" percent="98.6"></lowClouds>
<mediumClouds id="MEDIUM" percent="93.4"></mediumClouds>
<highClouds id="HIGH" percent="57.8"></highClouds>
<dewpointTemperature id="TD" unit="celsius" value="1.5"></dewpointTemperature>
</location>
</time>
But I can't access the elements.
Using
for node in parsedResultXML["weatherdata"]["product"]["time"].all{
node["time"].element?.attribute(by: "from")?.text
}
I don't get any results back.
Any idea??
Thanks
You're close... as #rmaddy commented, node is already indexed to "time". So instead of:
for node in parsedResultXML["weatherdata"]["product"]["time"].all {
node["time"].element?.attribute(by: "from")?.text
}
Do this instead:
for node in parsedResultXML["weatherdata"]["product"]["time"].all {
node.element?.attribute(by: "from")?.text
}

how to delete a scenario in atg through API methods

I have created a scenario by creating a myScenario.sdl in my local config folder /atg/registry/data/scenarios/myScenario.sdl
myScenario.sdl
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE process SYSTEM "dynamosystemresource:/atg/dtds/pdl/pdl_1.0.dtd">
<process author="admin" creation-time="1413804041263" enabled="false" last-modified-by="admin" modification-time="1413804191188">
<segment migrate-subjects="true">
<segment-name>ItemAddedToOrder</segment-name>
<!--================================-->
<!--== Item added to order Quantity with fraction is defined -->
<!--================================-->
<event id="1">
<event-name>atg.commerce.order.ItemAddedToOrder</event-name>
<filter construct="event-property-filter" operator="isNotNull">
<event-property construct="event-property">
<property-name>quantityWithFraction</property-name>
</event-property>
</filter>
</event>
<!--================================-->
<!--== Log a message message: Quantity With Fraction is Defines logTriggeringEvent: true -->
<!--================================-->
<action id="2">
<action-name>Log a message</action-name>
<action-param name="message">
<constant>Quantity With Fraction is Defines</constant>
</action-param>
<action-param name="logTriggeringEvent">
<constant type="java.lang.Boolean">true</constant>
</action-param>
</action>
</segment>
</process>
And enabled the scenario:
Registry scenarioRegistry = scenarioManager.getScenarioRegistry();
byte[] data = (byte[]) scenarioRegistry.getItem(pScenarioPath);
String xml = null;
if (data != null) {
xml = new String(data, "UTF-8");
} else {
Assert.fail("No scenario is existed to enable/disable");
}
String updatedXml;
if (scenarioState && xml != null) {
updatedXml = xml.replaceAll("enabled=\"false\"", "enabled=\"true\"");
} else {
updatedXml = xml.replaceAll("enabled=\"true\"", "enabled=\"false\"");
}
scenarioRegistry.putItem(pScenarioPath, updatedXml.getBytes("UTF-8"));
Now with this above written code, I can both disable or enable the scenario by changing the state as false and true respectively. But I want to delete the scenario(please remember, my requirement is DELETE not DISABLE SCENARIO). I know using scenarioManager.updateScenario() deleted the scenario. Is my understanding right?
One more thing, I know I can delete the scenario directly from ACC. But I need to code via code not manually from ACC.
Please share your thoughts!
Did you try scenarioRegistry.removeItem(path);

Drools camel multiple ksession not firing

I am using drools 5.6. In camel-server.xml I have my route defined as:
<route>
<from uri="cxfrs://bean://rsServer"/>
<policy ref="droolsPolicy">
<unmarshal ref="xstream-json" />
<to uri="drools:node1" />
<marshal ref="xstream-json" />
</policy>
</route>
I am not defining a ksession. Then in my knowledge-service.xml I have 2 sessions defined (by user) that point to different DRL files. These import the same common DRL file
<drools:kbase id="kbase1" node="node1">
<drools:resources>
<drools:resource ref="ruletemplate" />
<drools:resource type="DRL" source="classpath:7.drl"/>
</drools:resources>
</drools:kbase>
<drools:ksession id="ksession-7" type="stateless" kbase="kbase1" node="node1"/>
<drools:kbase id="kbase2" node="node1">
<drools:resources>
<drools:resource ref="ruletemplate" />
<drools:resource type="DRL" source="classpath:12.drl"/>
</drools:resources>
</drools:kbase>
<drools:ksession id="ksession-12" type="stateless" kbase="kbase2" node="node1"/>
The idea is the ksession will be defined in the JSON request passed in:
{"batch-execution": { "lookup":"ksession-12", "commands": [ { "insert": { "out-identifier": ...
The server starts up and changing the lookup between 7 and 12 works. HOWEVER whatever lookup I run first is the only rule that actually fires. So if I start the server and run ksession-7 it will run successfully, then change to ksession-12 nothing happens (does not hit debugging in 12.drl)
If I then restart the server and run 12 first it will run successfully, then change to ksession-7 and nothing happens
I am confused by this and believe I am missing something. My goal is to have a common rule template with specific rules for each user. Can anyone help guide me why this is not being directed correctly (or not processing)
EDIT: Adding example
t1.drl:
package org.company.t1.rules
import org.test.*
rule "check patients age" dialect "mvel"
when
$p : Patient( age >= 10)
then
System.out.println("t1 - age greater then 10")
$ca = new Message("age greater then 10")
$p.alerts.add($ca)
end
t2.drl:
package org.company.t2.rules
import org.test.*
rule "check patients age" dialect "mvel"
when
$p : Patient( age >= 15)
then
System.out.println("t2 - age greater then 15")
$ca = new Message("age greater then 15")
$p.alerts.add($ca)
end
ruletemplate.drl:
package org.test
declare Message
text : String
end
declare Patient
id:String
age : Integer
alerts : java.util.ArrayList
end
rule "setup rule for alerts" dialect "mvel" salience 100
when
$p : Patient()
then
System.out.println("initialize array")
$p.alerts = new java.util.ArrayList();
end
knowledge-server.xml:
<drools:resource id="ruletemplate" type="DRL" source="classpath:ruletemplate.drl" />
<drools:kbase id="kbase5" node="node1">
<drools:resources>
<drools:resource ref="ruletemplate" />
<drools:resource type="DRL" source="classpath:t1.drl"/>
</drools:resources>
</drools:kbase>
<drools:kbase id="kbase6" node="node1">
<drools:resources>
<drools:resource ref="ruletemplate" />
<drools:resource type="DRL" source="classpath:t2.drl"/>
</drools:resources>
</drools:kbase>
<drools:ksession id="ksession5" type="stateless" kbase="kbase5" node="node1"/>
<drools:ksession id="ksession6" type="stateless" kbase="kbase6" node="node1"/>
First request that works:
{"batch-execution": { "lookup":"ksession5", "commands": [ { "insert": { "out-identifier": "patient", "object": { "org.test.Patient":[{"age":16}]}}},{"fire-all-rules": ""}]}}
{"execution-results":{"results":{"result":{"identifier":"patient","value":{"org.test.Patient":{"age":16,"alerts":{"org.test.Message":{"text":"age greater then 10"}}}}},"fact-handle":{"identifier":"patient","external-form":"0:2:537549803:537549803:2:DEFAULT"}}}}
Request 2: (doesnt work unless run first after server restart:
{"batch-execution": { "lookup":"ksession6", "commands": [ { "insert": { "out-identifier": "patient", "object": { "org.test.Patient":[{"age":16}]}}},{"fire-all-rules": ""}]}}
{"execution-results":{"results":{"result":{"identifier":"patient","value":{"org.test.Patient":{"age":16}}},"fact-handle":{"identifier":"patient","external-form":"0:2:552327108:552327108:2:DEFAULT"}}}}
Tailing catalina.out shows the debugger output for t1 as it was run first, but nothing on t2
What are you inserting? what kind of rules do you have in there?
Could be that the first run everything works well and the second is crashing in the back?

Return value when internally calling target with phing/phingcall

I am calling a target by means of phingcall command.
I want to pass back a status variable from the called target or at least change the existing value from the calling target.
Goal: I want to branch in my main target controlling logic if the sub target fails which I indicate with a property.
The code below does not work. Any idea how to make it work or an altertive approach for my goal?
Thanks,
Juergen
<target name="main">
<echo>target a</echo>
<echo>${bOk}</echo>
<exec command="echo 1" outputProperty="bOk" />
<echo>bOk is 1: ${bOk}</echo>
<phingcall inheritRefs="true" target="sub">
</phingcall>
<echo>bOk should now be 0: ${bOk}</echo>
</target>
<target name="sub">
<echo>target b</echo>
<echo>bOk is 1: ${bOk}</echo>
<exec command="echo 0" outputProperty="bOk" />
<echo>bOk now is 0: ${bOk}</echo>
</target>
The problem here is that
<echo>bOk should now be 0: ${bOk}</echo>
echos
bOk should now be 0: 1
Even with the great help of #phing IRC I couldn't solve the problem.
I decided to write a custom task to account for data passing between targets:
<?php
require_once "phing/Task.php";
class rvGlobalTask extends Task {
private static $bOk = 1;
private $sMode = null;
private $bValue = null;
private $outputProperty = null;
public function setSMode( $sMode ) {
$this->sMode = $sMode;
}
public function setBValue( $bValue ) {
$this->bValue = $bValue;
}
public function setOutputProperty( $outputProperty ) {
$this->outputProperty = $outputProperty;
}
public function main() {
if ( $this->sMode == "set" ) {
rvGlobalTask::$bOk = $this->bValue;
} else {
$this->project->setProperty(
$this->outputProperty,
rvGlobalTask::$bOk
);
}
}
}
?>
This works fine for my problem. Perhaps someone else finds this useful as well.
Here's how you use an ExecTask to capture output.
<?xml version="1.0" encoding="UTF-8"?>
<project name="example" default="check-composer">
<!-- set a property to contain the output -->
<property name="whichComposer" value="" />
<!-- check if composer (getcomposer.org) is installed globally -->
<target name="check-composer">
<!-- put the output of "which" in our property -->
<exec command="which composer" outputProperty="whichComposer" />
<!-- act on what we found out -->
<if>
<contains string="${whichComposer}" substring="composer" />
<then>
<echo>Composer installed at ${whichComposer}</echo>
</then>
<else>
<echo message="better install composer. ${whichComposer}"/>
</else>
</if>
</target>
</project>

suds: incorrect marshaling of Array of Arrays

I try to talk to a load balancer (Zeus ZXTM) with python:
a = client.factory.create('StringArrayArray')
b = client.factory.create('StringArray')
b.value = ['node01:80',]
a.value = [b,]
client.service.addDrainingNodes(['my pool'], a)
But I get the following error:
suds.WebFault: Server raised fault: 'Not an ARRAY reference at /usr/local/zeus/zxtmadmin/lib/perl/Zeus/ZXTM/SOAPBase.pm line 772.
Extract of the schema definition:
<types>
<xsd:schema targetNamespace='http://soap.zeus.com/zxtm/1.0/'
xmlns='http://www.w3.org/2001/XMLSchema'
xmlns:SOAP-ENC='http://schemas.xmlsoap.org/soap/encoding/'
xmlns:wsdl='http://schemas.xmlsoap.org/wsdl/'>
<xsd:complexType name="StringArray">
<xsd:complexContent>
<xsd:restriction base='SOAP-ENC:Array'>
<xsd:attribute ref='SOAP-ENC:arrayType' wsdl:arrayType='xsd:string[]'/>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="StringArrayArray">
<xsd:complexContent>
<xsd:restriction base='SOAP-ENC:Array'>
<xsd:attribute ref='SOAP-ENC:arrayType' wsdl:arrayType='zeusns:StringArray[]'/>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>
</types>
<message name="addDrainingNodesRequest">
<part name="names" type="zeusns:StringArray" />
<part name="values" type="zeusns:StringArrayArray" />
</message>
<message name="addDrainingNodesResponse"></message>
<portType name="PoolPort">
<operation name="addDrainingNodes">
<documentation>
Add nodes to the lists of draining nodes, for each of the named pools.
</documentation>
<input message="zeusns:addDrainingNodesRequest"/>
<output message="zeusns:addDrainingNodesResponse"/>
</operation>
</portType>
</definitions>
I also tried like this:
client.service.addDrainingNodes(['my pool'], [['node01:80']])
which worked in SOAPpy but now in suds I get:
suds.WebFault: Server raised fault: 'Value isn't an array'
Comparison between what SOAPpy and what suds sends:
SOAPpy (works):
<ns1:addDrainingNodes xmlns:ns1="http://soap.zeus.com/zxtm/1.0/Pool/" SOAP-ENC:root="1">
<v1 SOAP-ENC:arrayType="xsd:string[1]" xsi:type="SOAP-ENC:Array">
<item>my pool</item>
</v1>
<v2 SOAP-ENC:arrayType="xsd:list[1]" xsi:type="SOAP-ENC:Array">
<item SOAP-ENC:arrayType="xsd:string[1]" xsi:type="SOAP-ENC:Array">
<item>node01:80</item>
</item>
</v2>
</ns1:addDrainingNodes>
suds (doesn't work):
<ns4:addDrainingNodes>
<names xsi:type="ns0:StringArray" ns3:arrayType="ns2:string[1]">
<item xsi:type="ns2:string">my pool</item>
</names>
<values xsi:type="ns0:StringArrayArray" ns3:arrayType="ns0:StringArray[1]">
<item xsi:type="ns2:string">node01:80</item>
</values>
</ns4:addDrainingNodes>
Context:
I'm new to suds and Soap
there's only the SOAP interface to the ZXTM loadbalancer
using python2.6 and suds 0.3.9
we used to use ZSI's SOAPpy, but had issues using it under python 2.6
Edit: Added suds/SOAPpy payloads
After trying
zillions of different arguments to this function
wsdl2py from ZSI
I found out that suds 4.0 offers plugins, that solves this case by hacking, but nonetheless I think that's a suds bug:
class FixArrayPlugin(Plugin):
def sending(self, context):
command = context.envelope.getChild('Body').getChildren()[0].name
if command == 'addDrainingNodes':
context.envelope.addPrefix('xsd', 'http://www.w3.org/1999/XMLSchema')
values = context.envelope.getChild('Body').getChild('addDrainingNodes').getChild('values')
values.set('SOAP-ENC:arrayType', 'xsd:list[1]')
values.set('xsi:type', 'SOAP-ENC:Array')
item = values[0]
item.set('SOAP-ENC:arrayType', 'xsd:list[1]')
item.set('xsi:type', 'SOAP-ENC:Array')
client = Client(wsdl, location=location, plugins=[FixArrayPlugin()])
a = client.factory.create('StringArrayArray')
b = client.factory.create('StringArray')
b.item = ['node01:80']
a.item = [b,]
client.service.addDrainingNodes(['my pool'], a)
I'm looking forward for this issue to be fixed, IMO this should be a one liner
I'm leaving this open as I'm still interested in better alternatives
What looks strange to me is you have to explicitly construct types like 'StringArrayArray' and 'StringArray' - a smart enough SOAP client in a language like python should be able to figure this out via reflection, examining the arguments you pass to the service call. I'm guessing they're declared in the wsdl as something like "SOAP-ENC:Array" - if so they're not intended to be objects. That would also make sense with the error message "Not an ARRAY reference". Have you tried just;
a = [ ['node01:80',], ]
client.service.addDrainingNodes(['my pool'], a)
Or failing that perhaps...
a = client.factory.create('StringArrayArray')
b = ['node01:80',]
a.value = [ b, ]
client.service.addDrainingNodes(['my pool'], a)
Good luck.