04-26-2018 04:38 PM
Unlike all other "get" calls, GetIlsConfigReq forces you to explicitly supply returnedTags, like you do with list methods.
<xsd:complexType name="GetIlsConfigReq">
<xsd:sequence>
<xsd:sequence>
<xsd:element minOccurs="0" name="clusterId" type="xsd:string"/>
</xsd:sequence>
<xsd:element name="returnedTags" type="axlapi:NewIlsConfig"/>
</xsd:sequence>
</xsd:complexType>
If you compare this to any arb. "get" request, returnedTags is missing a minOccurs tag:
<xsd:complexType name="GetSipProfileReq">
<xsd:sequence>
<xsd:choice>
<xsd:element name="name" type="axlapi:String100"/>
<xsd:element name="uuid" type="axlapi:XUUID"/>
</xsd:choice>
<xsd:element minOccurs="0" name="returnedTags" type="axlapi:RSipProfile"/>
</xsd:sequence>
<xsd:attribute name="sequence" type="xsd:unsignedLong" use="optional"/>
It just looks to me like this was missed in when the schema was defined... Here's an example where I didn't supply returnedTags
def main():
session = Session()
session.verify = False
session.auth = HTTPBasicAuth(USERNAME, PASSWORD)
transport = Transport(cache=SqliteCache(), session=session, timeout=60)
history = HistoryPlugin()
client = Client(wsdl=WSDL, transport=transport, plugins=[history])
axl = client.create_service(BINDING_NAME, ADDRESS)
try:
print(axl.getIlsConfig())
except XMLParseError as parse_error:
print(parse_error.message)
print()
finally:
try:
for hist in [history.last_sent, history.last_received]:
print(etree.tostring(hist["envelope"], encoding="unicode", pretty_print=True))
except IndexError:
pass
if __name__ == '__main__':
main()
Zeep is enforcing it:
File "C:\Users\jonathan.els\Envs\suds\lib\site-packages\zeep\xsd\elements\element.py", line 191, in render
self._render_value_item(parent, value, render_path)
File "C:\Users\jonathan.els\Envs\suds\lib\site-packages\zeep\xsd\elements\element.py", line 215, in _render_value_item
return self.type.render(node, value, None, render_path)
File "C:\Users\jonathan.els\Envs\suds\lib\site-packages\zeep\xsd\types\complex.py", line 253, in render
element.render(parent, element_value, child_path)
File "C:\Users\jonathan.els\Envs\suds\lib\site-packages\zeep\xsd\elements\indicators.py", line 241, in render
element.render(parent, element_value, child_path)
File "C:\Users\jonathan.els\Envs\suds\lib\site-packages\zeep\xsd\elements\element.py", line 185, in render
self.validate(value, render_path)
File "C:\Users\jonathan.els\Envs\suds\lib\site-packages\zeep\xsd\elements\element.py", line 236, in validate
"Missing element %s" % (self.name), path=render_path)
zeep.exceptions.ValidationError: Missing element returnedTags (getIlsConfig.returnedTags)
bug?
04-26-2018 04:51 PM
There's also at least one more bug here with clusterId. This is not supposed to be a mandatory attribute and is marked as optional:
<xsd:complexType name="GetIlsConfigReq">
<xsd:sequence>
<xsd:sequence>
<xsd:element minOccurs="0" name="clusterId" type="xsd:string"/>
</xsd:sequence>
<xsd:element name="returnedTags" type="axlapi:NewIlsConfig"/>
</xsd:sequence>
</xsd:complexType>
If I do this (axl.getIlsConfig(returnedTags={"clusterUriString": ""}), without a clusterId, it works:
def main():
session = Session()
session.verify = False
session.auth = HTTPBasicAuth(USERNAME, PASSWORD)
transport = Transport(cache=SqliteCache(), session=session, timeout=60)
history = HistoryPlugin()
client = Client(wsdl=WSDL, transport=transport, plugins=[history])
axl = client.create_service(BINDING_NAME, ADDRESS)
try:
print(axl.getIlsConfig(returnedTags={"clusterUriString": ""}))
except XMLParseError as parse_error:
print(parse_error.message)
finally:
try:
for hist in [history.last_sent, history.last_received]:
print(etree.tostring(hist["envelope"], encoding="unicode", pretty_print=True))
except IndexError:
pass
if __name__ == '__main__':
main()
however, as soon as I specify that I want the clusterId as a returned tag, then it fails:
def main():
session = Session()
session.verify = False
session.auth = HTTPBasicAuth(USERNAME, PASSWORD)
transport = Transport(cache=SqliteCache(), session=session, timeout=60)
history = HistoryPlugin()
client = Client(wsdl=WSDL, transport=transport, plugins=[history])
axl = client.create_service(BINDING_NAME, ADDRESS)
try:
print(axl.getIlsConfig(returnedTags={"clusterId": "", "clusterUriString": ""}))
except XMLParseError as parse_error:
print(parse_error.message)
finally:
try:
for hist in [history.last_sent, history.last_received]:
print(etree.tostring(hist["envelope"], encoding="unicode", pretty_print=True))
except IndexError:
pass
if __name__ == '__main__':
main()
Response from CUCM:
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:Body>
<ns0:getIlsConfig xmlns:ns0="http://www.cisco.com/AXL/API/11.5">
<returnedTags>
<clusterId></clusterId>
<clusterUriString></clusterUriString>
</returnedTags>
</ns0:getIlsConfig>
</soap-env:Body>
</soap-env:Envelope>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<soapenv:Fault>
<faultcode>soapenv:Server</faultcode>
<faultstring/>
<detail>
<axlError>
<axlcode>-1</axlcode>
<axlmessage/>
<request>getIlsConfig</request>
</axlError>
</detail>
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>
If then I go and specify the clusterId up front, then it works:
def main():
session = Session()
session.verify = False
session.auth = HTTPBasicAuth(USERNAME, PASSWORD)
transport = Transport(cache=SqliteCache(), session=session, timeout=60)
history = HistoryPlugin()
client = Client(wsdl=WSDL, transport=transport, plugins=[history])
axl = client.create_service(BINDING_NAME, ADDRESS)
try:
print(axl.getIlsConfig(clusterId="StandAloneCluster", returnedTags={"clusterId": "", "clusterUriString": ""}))
except XMLParseError as parse_error:
print(parse_error.message)
finally:
try:
for hist in [history.last_sent, history.last_received]:
print(etree.tostring(hist["envelope"], encoding="unicode", pretty_print=True))
except IndexError:
pass
if __name__ == '__main__':
main()
This really should be consistent with other API calls. The others usually offer a choice of a name/pattern setc, or the uuid. If there's no uuid for clusterid, then really the clusterid name should be enforced here.
03-24-2021 07:55 AM
Hey Jonathon, I am running into the same issue when attempting to pull the ilsconfig via AXL. I get the same error you referenced above "zeep.exceptions.ValidationError: Missing element returnedTags (getIlsConfig.returnedTags)", but it wasn't clear to me on how you resolved it. I also thought it was weird that the returnedTags was needed in a get request, since my other AXL pulls only used this attribute in a list request and this was the only get function that threw a zeep exception on returnedTags.
What exactly did you modify to get this working?
03-24-2021 08:06 AM
I figured it out, based on your notes above. I created this function and was successful in returning the dataset, I just need to remember to pull the Cluster ID from the Enterprise Parameters before running this function:
def get_ils_config(self, clusterId):
try:
return self.client.getIlsConfig(clusterId=clusterId, returnedTags={"clusterUriString": ""})["return"]
except Fault as e:
return e
Discover and save your favorite ideas. Come back to expert answers, step-by-step guides, recent topics, and more.
New here? Get started with these tips. How to use Community New member guide