cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
Announcements
141
Views
0
Helpful
0
Replies
Elliot Dierksen
Rising star

UCCX 10.6 fails to connect to AXL on CUCM 12.5

I have a really old UCCX script that prompts for auth codes. The first version of it queried a SQL database. The admins where having to double enter this in 1 CUCM cluster and the SQL database. In CUCM 9, I was able to figure out how to make an AXL call from the CCX script to CUCM AXL to look up the auth code, and life was good. I upgraded the CUCM cluster that UCCX queried to 12.5 this weekend, and it stopped working. The java step I was using to make the connections failed with an exception. (as an aside, I couldn't figure out what kind of variable to On Exception step wanted for the 'save root cause' box). It was always a requirement that the CUCM Tomcat certificate be added to the UCCX certificate store as a tomcat-trust. I make sure this was still the case and restart tomcat, but joy. This is what the script looks like. Bear in mind this is over 10 years old and I don't even remember where I got the pieces that I cobbled together to make it work. I had  worked great for a really long time.

set AXLQueryURL = "https://" + ServerHostName + ":8443/axl/"
set SOAPRequest = 
{

// first, create a new buffer:

java.io.StringWriter buffer = new java.io.StringWriter();

// define namespace URI's and prefixes

// (take a look at the SOAP request XML above, you'll see there are two namespace prefix - URI pairs

final String SOAPENV_NAMESPACE_URI = "http://schemas.xmlsoap.org/soap/envelope/";


final String SOAPENV_NAMESPACE_PREFIX = "soapenv";

final String NS_NAMESPACE_URI = "http://www.cisco.com/AXL/API/8.5";

final String NS_NAMESPACE_PREFIX = "ns";

String axlsql = QueryString;

// some of the following methods may throw an exception (~ error), so we want to wrap them

// into a try..catch block. Remember, if an exception occurs, the resulting value,

// thus the soapRequest variable will be null

        try {

// create a document builder "factory" (that builds the document)

// make it namespace aware

// then crate a new document

        javax.xml.parsers.DocumentBuilderFactory factory = javax.xml.parsers.DocumentBuilderFactory.newInstance();

        factory.setNamespaceAware(true);

        javax.xml.parsers.DocumentBuilder documentBuilder = factory.newDocumentBuilder();

        org.w3c.dom.Document document = documentBuilder.newDocument();

// insert the "root" element (soapenv:Envelope), and introduce the required namespace:

        org.w3c.dom.Element root = document.createElementNS(SOAPENV_NAMESPACE_URI, SOAPENV_NAMESPACE_PREFIX + ":Envelope");
	
	

        
        root.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:" + SOAPENV_NAMESPACE_PREFIX, SOAPENV_NAMESPACE_URI);
	    root.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:ns" , "http://www.cisco.com/AXL/API/8.5");

// create the header element (precisely: soapenv:Header)

// we are going to append it to the root element right away (since it should not contain anything)

        org.w3c.dom.Element header = document.createElement("soapenv:Header");

        root.appendChild(header);

// create the body (precisely: soapenv:Body) element:

        org.w3c.dom.Element body = document.createElement("soapenv:Body");

// create another element, ns:executeSQLQuery, now with a different namespace, too:

        org.w3c.dom.Element gca = document.createElementNS(NS_NAMESPACE_URI, NS_NAMESPACE_PREFIX + ":executeSQLQuery");

    

// and, create two other elements, startDate and endDate

// each contains a date-time string:

        org.w3c.dom.Element sql = document.createElement("sql");

        sql.setTextContent(axlsql);

 // adding startDate and endDate to ns:executeSQLQuery

        gca.appendChild(sql);

       

// adding mis:GetCallAggregates to the soapenv:Body element

        body.appendChild(gca);

// adding the soapenv:Body element to the root element (soapenv:Envelope)

        root.appendChild(body);

// and then adding the root element to the document

        document.appendChild(root);

// at this point, we've got the programmatic representation of XML

// but we need to transform it into a String so we can send it to the SOAP server

// this can be achieved, too: the source being the programmatic representation

// and the result is the buffer we specified on the first line

        javax.xml.transform.TransformerFactory transFactory = javax.xml.transform.TransformerFactory.newInstance();

        javax.xml.transform.Transformer transformer = transFactory.newTransformer();

        javax.xml.transform.Source source = new javax.xml.transform.dom.DOMSource(document);

        javax.xml.transform.stream.StreamResult result = new javax.xml.transform.stream.StreamResult(buffer);

        transformer.transform(source, result);

        } catch (Exception e) {

// again, if anything happens,the strack trace is sent to the standard output (stdout.log, most likely)

            e.printStackTrace();

// and then null is returned

            return null;

        } // try..catch block ends here

// but if there are no problems, the buffer is cast into a String:

return buffer.toString();

} //closure ends here

set SOAPResponseString = 
{

// create a ByteArrayOutputStream - this is actually a buffer

// we are going to use to store the response coming from the SOAP server

java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();

// this is quite unnecessary: assigning the value of the soapRequest (still holding our XML document)

// to another variable, named content, type String; but anyway, it's just cleaner

String content = SOAPRequest;
String base64auth = BasicAuthEncoded;

// specify a timeout - 2000 milliseconds - if the web server does not start sending back

// anything within this timeframe, an exception will be raised

int readTimeout = 2000;

// now, the following methods are enclosed by a try..catch block

// to catch any exceptions - we just want to have control over them

// remember, an uncaught exception might stop your CRS script execution

// and you might not want that

try {

// a new URL, which is the soapServiceEndpoint variable value (http://ip:port/ etc):

     java.net.URL url = new java.net.URL(AXLQueryURL);

// creating a HTTP connection to the above URL:

     javax.net.ssl.HttpsURLConnection urlCon = (javax.net.ssl.HttpsURLConnection) url.openConnection();
	


// setting some important header parameters, first of all, content length, this is most likely expected

// by the SOAP server

  urlCon.setFixedLengthStreamingMode(content.length());
// urlCon.setFollowRedirects (false);

// setting the timeout:

     urlCon.setReadTimeout(readTimeout);

// we tell Java we will do input (in other words, we will read):

     urlCon.setDoInput (true);

// we tell Java we will do output (in other words, we will send):

     urlCon.setDoOutput (true);

// we tell Java not to cache:

     urlCon.setUseCaches (false);
	 

// we are using HTTP POST

     urlCon.setRequestMethod("POST");

// finally, we set the Content-Type header,

// this way we are telling the SOAP server we are sending an XML, using the UTF-8 charset
	urlCon.setRequestProperty("Authorization","Basic " + base64auth);
	urlCon.setRequestProperty("Accept","text/*");
     urlCon.setRequestProperty("Content-Type","text/xml");
	 urlCon.setRequestProperty("SOAPAction","CUCM:DB ver=8.5 executeSQLQuery");
//	 urlCon.setRequestProperty("Content-Length","2654");

// opening an OutputStream (this is a one-way channel towards the SOAP server:

     java.io.DataOutputStream output = new java.io.DataOutputStream(urlCon.getOutputStream());

// we write the contents of the content variable (= soapRequest = XML document):

     output.writeBytes(content);

// telling Java to flush "speed up!" and then close the stream:

     output.flush();

     output.close();

// now getting the InputStream (getting a one way channel coming from the SOAP server):

     java.io.DataInputStream input = new java.io.DataInputStream(urlCon.getInputStream());

// buffered read from the InputStream, buffer size 4Kilobytes (= 4096 bytes):

// and the buffer is always written to the other buffer, named baos, that we specified

// on the first line of this block of code

     int bufSize = 4096; // buffer size, bytes

     byte[] bytesRead = new byte[bufSize];

     int bytesReadLength = 0;

     while(( bytesReadLength = input.read( bytesRead )) > 0 ) {

         baos.write(bytesRead,0,bytesReadLength);

     } //while block ends here

// closing the InputStream:

     input.close();

// closing the baos buffer

     baos.close();

} catch (Exception e) {

// again, if an error occurs, let's just send the stack trace to stdout (stdout.log)

// and then return null
    e.printStackTrace();

    return null;

} // try..catch block ends here

// construct a new String, and return that to the CRS script:

return new String(baos.toByteArray());

} // closure ends here



I tried changing the second Java snippet to a Make REST Call step like this, but I still got an exception.

 

Make-REST-call.PNG

Still no luck. My solution was to do a BAT export/import of the auth codes and move them to the cluster that hosts UCCX. The admins now have to double enter the code again which is not ideal. The thing that is really strange is the original code that has worked for 10 years no longer works on the new cluster. The only difference is a new cluster. It is running the same 10.5.2 CUCM that the old one was. I am also sure that the CUCM certificates are in the UCCX certificate store as a tomcat trust. The Make REST Call step does work.

 

Here is the short version? What can't UCCX 10.6 make any kind of tomcat connection to CUCM 12.5? Tomcat version? Cipher versions? I am at a loss.

 

P.S. I know UCCX 10.6 goes end of support at the end of the year. This is part of the process of getting their 11 CUCM clsuters, 2 UCCX clusters, and 2 CXN clusters all up to a current version. Thanks in advance!

0 REPLIES 0
Create
Recognize Your Peers
Content for Community-Ad