UCSD - Convert ACI/APIC Inspector JSON to UCSD Task

Version 10

    Version 1

      

     

    Task Name

    Create from the JSON from the APIC Inspector a UCSD task

    Description

     

    Prerequisites
    1. Tested on 6.0
    CategoryWorkflow
    ComponentsvSphere 5.x
    User Inputs
    Output

    Instructions for Regular Workflow Use:

    1. Download the attached .ZIP file below to your computer. *Remember the location of the saved file on your computer.
    2. Unzip the file on your computer. Should end up with a .WFD file.
    3. Log in to UCS Director as a user that has "system-admin" privileges.
    4. Navigate to "Policies-->Orchestration" and click on "Import".
    5. Click "Browse" and navigate to the location on your computer where the .WFDX file resides. Choose the .WFDX file and click "Open".
    6. Click "Upload" and then "OK" once the file upload is completed. Then click "Next".
    7. Click the "Select" button next to "Import Workflows". Click the "Check All" button to check all checkboxes and then the "Select" button.
    8. Click "Submit".
    9. A new folder should appear in "Policies-->Orchestration" that contains the imported workflow. You will now need to update the included tasks with information about the specific environment

     

     

     

     

    Lets start out by all the credit goes to Russ W.

     

    The purpose of this write up is to take the APIC Inspector JASON and create a UCSD task from it.

     

     

    Step 1)

         Copy below script into a Cloupia task:

     

    Screen Shot 2016-10-11 at 5.09.00 PM.png

     

    importPackage(java.io);

    importPackage(java.util);

    importPackage(com.cloupia.lib.util);

     

    // REPLACE THE CURLY BRACES BELOW WITH A SINGLE LINE OF JSON RETRIEVED FROM APIC VIA

    // THE API INSPECTOR. RESULTING CLOUPIA SCRIPT WILL BE WRITTEN BY DEFAULT TO THE

    // FOLLOWING LOCATION ON UCS DIRECTOR: /tmp/apic_wf.js

     

    var jsonString = {};

     

    var outputFileName = "/tmp/apic_wf.js";

     

    // comma separated list of rollback task inputs.

    // e.g. var taskInputs = ["russ","whitear"];

    var taskInputs = [];

     

    // Set to true if rollback registration is required (You will need to supply any

    // variables that are required for rollback.

    var registerRollbackTask = false;

     

    // Name of the rollback workflow task.

    var rollbackTaskName = "";

     

    // comma separated list of rollback task inputs (e.g. ["tenant","bd"]

    // e.g. var rollbackTaskInputs = ["tenant","bd","vip"];

    var rollbackTaskInputs = [];

     

     

     

    function getKids( prefix, jsonObject, iterator ) {

        for( var x in jsonObject ) {

     

            if( iterator != -1 ) {

                logger.addInfo( prefix + ".add(new TreeMap());" );

                bw.write(prefix + ".add(new TreeMap());\n" );

      

                prefix = prefix + ".get(\"" +iterator+ "\")";

            }

     

            logger.addInfo( prefix + ".put(\""+x+"\",new TreeMap());" );

            bw.write(prefix + ".put(\""+x+"\",new TreeMap());\n");

     

            logger.addInfo( prefix + ".get(\""+x+"\").put(\"attributes\",new TreeMap());" );

            bw.write(prefix + ".get(\""+x+"\").put(\"attributes\",new TreeMap());\n");

     

            logger.addInfo( prefix + ".get(\""+x+"\").put(\"children\",new ArrayList());" );

            bw.write(prefix + ".get(\""+x+"\").put(\"children\",new ArrayList());\n");

     

            prefix = prefix + ".get(\""+x+"\")";

     

     

            //logger.addInfo( "prefix: " +prefix );

     

            if( jsonObject[x]["attributes"] ) {

                for( var k in jsonObject[x]["attributes"] ) {

                    logger.addInfo(prefix +".get(\"attributes\").put(\""+k+"\",\""+jsonObject[x]["attributes"][k]+"\");");

                    bw.write(prefix +".get(\"attributes\").put(\""+k+"\",\""+jsonObject[x]["attributes"][k]+"\");\n");

                }

            }

     

            bw.flush();

     

            if( jsonObject[x]["children"] ) {

                if( jsonObject[x]["children"].length > 0 ) {

      

                    for( var i=0; i < jsonObject[x]["children"].length; i++ ) {

              

                        var stub = prefix+".get(\"children\")";

              

                        getKids( stub, jsonObject[x]["children"][i], i );

                    }

                }

            } else {

                logger.addInfo( "jsonObject[" +x+ "][children] doesn't exist." );

            }

        }

    }

     

     

    // main();

     

    bw = new BufferedWriter(new FileWriter(outputFileName));

     

    bw.write('importPackage(java.util);'+"\n");

    bw.write('importPackage(java.lang);'+"\n");

    bw.write('importPackage(java.io);'+"\n");

    bw.write('importPackage(com.cloupia.lib.util);'+"\n");

    bw.write('importPackage(org.apache.commons.httpclient);'+"\n");

    bw.write('importPackage(org.apache.commons.httpclient.cookie);'+"\n");

    bw.write('importPackage(org.apache.commons.httpclient.methods);'+"\n");

    bw.write('importPackage(org.apache.commons.httpclient.auth);'+"\n");

    bw.write('importPackage(org.apache.commons.httpclient.protocol);'+"\n");

    bw.write('importClass(org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory);'+"\n");

    bw.write('importPackage(com.cloupia.lib.cIaaS.vcd.api);'+"\n");

    bw.write(''+"\n");

    bw.write('/****************************************************************************************/'+"\n");

    bw.write('/**                                                                                    **/'+"\n");

    bw.write('/**                           !!! IMPORTANT NOTE !!!                                   **/'+"\n");

    bw.write('/**                                                                                    **/'+"\n");

    bw.write('/**                                                                                    **/'+"\n");

    bw.write('/**         THIS SCRIPT REQUIRES A MINIMUM UCS DIRECTOR VERSION OF 5.4.0.0             **/'+"\n");

    bw.write('/**                                                                                    **/'+"\n");

    bw.write('/****************************************************************************************/'+"\n");

    bw.write(''+"\n");

    bw.write('//----------------------------------------------------------------------------------------'+"\n");

    bw.write('//                                 ### FUNCTIONS ###'+"\n");

    bw.write('//----------------------------------------------------------------------------------------'+"\n");

    bw.write(''+"\n");

    bw.write('//----------------------------------------------------------------------------------------'+"\n");

    bw.write('//'+"\n");

    bw.write('//        Author: Russ Whitear (rwhitear@cisco.com)'+"\n");

    bw.write('//'+"\n");

    bw.write('// Function Name: httpRequest()'+"\n");

    bw.write('//'+"\n");

    bw.write('//       Version: 3.0'+"\n");

    bw.write('//'+"\n");

    bw.write('// Modifications: Added HTTP header Connection:close to execute method to overcome the'+"\n");

    bw.write('//                CLOSE_WAIT issue caused with releaseConnection().'+"\n");

    bw.write('//'+"\n");

    bw.write('//                Modified SSL socket factory code to work with UCS Director 5.4.0.0.'+"\n");

    bw.write('//'+"\n");

    bw.write('//   Description: HTTP Request function - httpRequest.'+"\n");

    bw.write('//'+"\n");

    bw.write('//                I have made the httpClient functionality more object like in order to '+"\n");

    bw.write('//                make cloupia scripts more readable when making many/multiple HTTP/HTTPS '+"\n");

    bw.write('//                requests within a single script. '+"\n");

    bw.write('//'+"\n");

    bw.write('//      Usage: 1. var request = new httpRequest();                   // Create new object.'+"\n");

    bw.write('//                '+"\n");

    bw.write('//             2. request.setup("192.168.10.10","https","admin","cisco123");      // SSL.'+"\n");

    bw.write('//          or:   request.setup("192.168.10.10","http","admin","cisco123");       // HTTP.'+"\n");

    bw.write('//          or:   request.setup("192.168.10.10","https");           // SSL, no basicAuth.'+"\n");

    bw.write('//          or:   request.setup("192.168.10.10","http");            // HTTP, no basicAuth.'+"\n");

    bw.write('//'+"\n");

    bw.write('//             3. request.getRequest("/");                    // HTTP GET (URI). '+"\n");

    bw.write('//          or:   request.postRequest("/","some body text");  // HTTP POST (URI,BodyText). '+"\n");

    bw.write('//          or:   request.deleteRequest("/");                 // HTTP DELETE (URI). '+"\n");

    bw.write('//'+"\n");

    bw.write('//  (optional) 4. request.contentType("json");            // Add Content-Type HTTP header.'+"\n");

    bw.write('//          or:   request.contentType("xml"); '+"\n");

    bw.write('//'+"\n");

    bw.write('//  (optional) 5. request.addHeader("X-Cloupia-Request-Key","1234567890");  // Any Header.'+"\n");

    bw.write('//'+"\n");

    bw.write('//             6. var statusCode = request.execute();                     // Send request.'+"\n");

    bw.write('//'+"\n");

    bw.write('//             7. var response = request.getResponse("asString");   // Response as string.'+"\n");

    bw.write('//          or:   var response = request.getResponse("asStream");   // Response as stream.'+"\n");

    bw.write('//'+"\n");

    bw.write('//             8. request.disconnect();                             // Release connection.'+"\n");

    bw.write('//'+"\n");

    bw.write('//'+"\n");

    bw.write('//          Note: Be sure to add these lines to the top of your script:'+"\n");

    bw.write('//'+"\n");

    bw.write('//          importPackage(java.util);'+"\n");

    bw.write('//          importPackage(com.cloupia.lib.util);'+"\n");

    bw.write('//          importPackage(org.apache.commons.httpclient);'+"\n");

    bw.write('//          importPackage(org.apache.commons.httpclient.cookie);'+"\n");

    bw.write('//          importPackage(org.apache.commons.httpclient.methods);'+"\n");

    bw.write('//          importPackage(org.apache.commons.httpclient.auth);'+"\n");

    bw.write('//          importPackage(org.apache.commons.httpclient.protocol);'+"\n");

    bw.write('//          importClass(org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory);'+"\n");

    bw.write('//          importPackage(com.cloupia.lib.cIaaS.vcd.api);'+"\n");

    bw.write('//'+"\n");

    bw.write('//----------------------------------------------------------------------------------------'+"\n");

    bw.write(''+"\n");

    bw.write('var httpRequest = function () {};'+"\n");

    bw.write(''+"\n");

    bw.write('httpRequest.prototype.setup = function(serverIp, transport, username, password) {'+"\n");

    bw.write('    this.serverIp = serverIp;'+"\n");

    bw.write('    this.transport = transport;'+"\n");

    bw.write('    this.username = username;'+"\n");

    bw.write('    this.password = password;'+"\n");

    bw.write('    '+"\n");

    bw.write('    '+"\n");

    bw.write('    this.httpClient = new HttpClient();'+"\n");

    bw.write('    '+"\n");

    bw.write('    // Decide whether to create an HTTP or HTTPS connection based on "transport".'+"\n");

    bw.write('    if( this.transport == "https" ) {   '+"\n");

    bw.write('        this.httpClient = CustomEasySSLSocketFactory.getIgnoreSSLClient(this.serverIp, 443);'+"\n");

    bw.write('        this.httpClient.getParams().setCookiePolicy("default");'+"\n");

    bw.write('    } else {'+"\n");

    bw.write('        // Create new HTTP connection.'+"\n");

    bw.write('        this.httpClient.getHostConfiguration().setHost(this.serverIp, 80, "http");       '+"\n");

    bw.write('    }'+"\n");

    bw.write('    '+"\n");

    bw.write('    this.httpClient.getParams().setCookiePolicy("default");'+"\n");

    bw.write('    '+"\n");

    bw.write('    // If username and password supplied, then use basicAuth.'+"\n");

    bw.write('    if( this.username && this.password ) {'+"\n");

    bw.write('        this.httpClient.getParams().setAuthenticationPreemptive(true);'+"\n");

    bw.write('        this.defaultcreds = new UsernamePasswordCredentials(this.username, this.password);'+"\n");

    bw.write('        this.httpClient.getState().setCredentials(new AuthScope(this.serverIp, -1, null), this.defaultcreds);'+"\n");

    bw.write('    }'+"\n");

    bw.write('};'+"\n");

    bw.write(''+"\n");

    bw.write('httpRequest.prototype.contentType = function(contentType) {'+"\n");

    bw.write('    this.contentType = contentType;'+"\n");

    bw.write('    '+"\n");

    bw.write('    this.contentTypes = ['+"\n");

    bw.write('        ["xml","application/xml"],'+"\n");

    bw.write('        ["json","application/json"]'+"\n");

    bw.write('    ];'+"\n");

    bw.write('    '+"\n");

    bw.write('    for( this.i=0; this.i<this.contentTypes.length; this.i++) '+"\n");

    bw.write('        if(this.contentTypes[this.i][0] == this.contentType)'+"\n");

    bw.write('            this.httpMethod.addRequestHeader("Content-Type", this.contentTypes[this.i][1]);'+"\n");

    bw.write('};'+"\n");

    bw.write(''+"\n");

    bw.write('httpRequest.prototype.addHeader = function(headerName,headerValue) {'+"\n");

    bw.write('    this.headerName = headerName;'+"\n");

    bw.write('    this.headerValue = headerValue;'+"\n");

    bw.write('    '+"\n");

    bw.write('    this.httpMethod.addRequestHeader(this.headerName, this.headerValue);'+"\n");

    bw.write('};'+"\n");

    bw.write(''+"\n");

    bw.write('httpRequest.prototype.execute = function() {    '+"\n");

    bw.write('    // Connection:close is hard coded here in order to ensure that the TCP connection'+"\n");

    bw.write('    // gets torn down immediately after the request. Comment this line out if you wish to'+"\n");

    bw.write('    // experiment with HTTP persistence.'+"\n");

    bw.write('    this.httpMethod.addRequestHeader("Connection", "close");'+"\n");

    bw.write('    '+"\n");

    bw.write('    this.httpClient.executeMethod(this.httpMethod);'+"\n");

    bw.write('    '+"\n");

    bw.write('    // Retrieve status code.'+"\n");

    bw.write('    this.statusCode = this.httpMethod.getStatusCode();'+"\n");

    bw.write('    '+"\n");

    bw.write('    return this.statusCode;'+"\n");

    bw.write('}'+"\n");

    bw.write(''+"\n");

    bw.write('httpRequest.prototype.getRequest = function(uri) {'+"\n");

    bw.write('    this.uri = uri;'+"\n");

    bw.write(''+"\n");

    bw.write('    // Get request.'+"\n");

    bw.write('    this.httpMethod = new GetMethod(this.uri);'+"\n");

    bw.write('};'+"\n");

    bw.write(''+"\n");

    bw.write('httpRequest.prototype.postRequest = function(uri,bodytext) {'+"\n");

    bw.write('    this.uri = uri;'+"\n");

    bw.write('    this.bodytext = bodytext;'+"\n");

    bw.write('    '+"\n");

    bw.write('    // POST Request.'+"\n");

    bw.write('    this.httpMethod = new PostMethod(this.uri);'+"\n");

    bw.write('    this.httpMethod.setRequestEntity(new StringRequestEntity(this.bodytext));'+"\n");

    bw.write('};'+"\n");

    bw.write(''+"\n");

    bw.write('httpRequest.prototype.getResponse = function(asType) {'+"\n");

    bw.write('    this.asType = asType;'+"\n");

    bw.write(''+"\n");

    bw.write('    if( this.asType == "asStream" )'+"\n");

    bw.write('        return this.httpMethod.getResponseBodyAsStream();'+"\n");

    bw.write('    else'+"\n");

    bw.write('        return this.httpMethod.getResponseBodyAsString();'+"\n");

    bw.write('};'+"\n");

    bw.write(''+"\n");

    bw.write('httpRequest.prototype.deleteRequest = function(uri) {'+"\n");

    bw.write('    this.uri = uri;'+"\n");

    bw.write(''+"\n");

    bw.write('    // Get request.'+"\n");

    bw.write('    this.httpMethod = new DeleteMethod(this.uri);'+"\n");

    bw.write('};'+"\n");

    bw.write(''+"\n");

    bw.write(''+"\n");

    bw.write('httpRequest.prototype.disconnect = function() {'+"\n");

    bw.write('    // Release connection.'+"\n");

    bw.write('    this.httpMethod.releaseConnection();'+"\n");

    bw.write('};'+"\n");

    bw.write(''+"\n");

    bw.write(''+"\n");

    bw.write(''+"\n");

    bw.write('// main()'+"\n");

    bw.write(''+"\n");

    bw.write('var apicLogin = input.apicLogin;'+"\n");

    bw.write('var apicPassword = input.apicPassword;'+"\n");

    bw.write('var apicIP = input.apicIP;'+"\n");

    bw.write(''+"\n");

    bw.write('// Place individual variables here...'+"\n");

    bw.write('// var TENANTNAME = ctxt.getInput("A");...'+"\n");

    bw.write('// var TENANTNAME = input.A;...'+"\n");

    bw.write(''+"\n");

     

    if(taskInputs.length) {

        for( var i=0; i < taskInputs.length; i++ ) {

            bw.write('var '+taskInputs[i]+' = input.'+taskInputs[i]+';'+"\n");

        }

    }

     

     

    bw.write(''+"\n");

    bw.write('//'+"\n");

    bw.write(''+"\n");

    bw.write('var requestURI = "/api/mo/.json";'+"\n");

    bw.write(''+"\n");

    bw.write('// Create JSON login data.'+"\n");

    bw.write('var aaaUser = new TreeMap();'+"\n");

    bw.write('aaaUser.put("aaaUser",new TreeMap());'+"\n");

    bw.write(''+"\n");

    bw.write('aaaUser.get("aaaUser").put("attributes",new TreeMap());'+"\n");

    bw.write('aaaUser.get("aaaUser").put("children",new ArrayList());'+"\n");

    bw.write(''+"\n");

    bw.write('aaaUser.get("aaaUser").get("attributes").put("name",apicLogin);'+"\n");

    bw.write('aaaUser.get("aaaUser").get("attributes").put("pwd",apicPassword);'+"\n");

    bw.write(''+"\n");

    bw.write('var loginUri  = "/api/mo/aaaLogin.json";'+"\n");

    bw.write('var loginData = JSON.javaToJsonString(aaaUser, aaaUser.getClass());'+"\n");

    bw.write(''+"\n");

    bw.write(''+"\n");

    bw.write(''+"\n");

    bw.write('// PASTE APIC JSON REQUEST DATA HERE...'+"\n");

    bw.write(''+"\n");

     

    bw.write('var javaMap = new TreeMap();\n'+"\n");

     

    getKids( "javaMap", jsonString, -1 );

     

    bw.write("\nvar requestData = JSON.javaToJsonString(javaMap, javaMap.getClass());\n");

    bw.write(''+"\n");

    bw.write('//'+"\n");

    bw.write(''+"\n");

     

    bw.write('requestData = requestData+""; // Convert requestData from object to string.'+"\n");

    bw.write('requestData = requestData.replace(/\\\\/g,""); // Overcome some APIC ugliness.'+"\n");

     

    bw.write(''+"\n");

    bw.write(''+"\n");

    bw.write('logger.addInfo("requestData: " +requestData);'+"\n");

    bw.write(''+"\n");

    bw.write('var request = new httpRequest();'+"\n");

    bw.write('             '+"\n");

    bw.write('request.setup(apicIP,"https"); '+"\n");

    bw.write(''+"\n");

    bw.write('request.postRequest(loginUri,loginData);'+"\n");

    bw.write(''+"\n");

    bw.write('request.contentType("json"); '+"\n");

    bw.write(''+"\n");

    bw.write('var statusCode = request.execute();                   '+"\n");

    bw.write(''+"\n");

    bw.write('var response = request.getResponse("asString");  '+"\n");

    bw.write(''+"\n");

    bw.write('logger.addInfo("Status code: " +statusCode );'+"\n");

    bw.write(''+"\n");

    bw.write('logger.addInfo("Response: " +response );'+"\n");

    bw.write(''+"\n");

    bw.write('request.postRequest(requestURI,requestData);'+"\n");

    bw.write(''+"\n");

    bw.write('var statusCode = request.execute();'+"\n");

    bw.write(''+"\n");

    bw.write('var response = request.getResponse("asString");  '+"\n");

    bw.write(''+"\n");

    bw.write('logger.addInfo("Status code: " +statusCode );'+"\n");

    bw.write(''+"\n");

    bw.write('var responseData = JSON.getJsonElement(response,null);'+"\n");

    bw.write(''+"\n");

    bw.write('if( responseData.has("imdata") && responseData.get("imdata").size() ) {'+"\n");

    bw.write('    '+"\n");

    bw.write('    for( var i = 0; i < responseData.get("imdata").size(); i++ ) {'+"\n");

    bw.write('        '+"\n");

    bw.write('        if( responseData.get("imdata").get(i).has("error") ) {'+"\n");

    bw.write('            if( responseData.get("imdata").get(i).get("error").has("attributes") ) {'+"\n");

    bw.write('                if( responseData.get("imdata").get(i).get("error").get("attributes").has("code") ) {'+"\n");

    bw.write('                    logger.addError("APIC Error Code: " + responseData.get("imdata").get(i).get("error").get("attributes").get("code") );'+"\n");

    bw.write('                }'+"\n");

    bw.write('                if( responseData.get("imdata").get(i).get("error").get("attributes").has("text") ) {'+"\n");

    bw.write('                    logger.addError("APIC Error Text: " + responseData.get("imdata").get(i).get("error").get("attributes").get("text") );'+"\n");

    bw.write('                }'+"\n");

    bw.write('            }'+"\n");

    bw.write('            '+"\n");

    bw.write('            // Set failed.'+"\n");

    bw.write('            ctxt.setFailed("Request failed.");'+"\n");

    bw.write('        }'+"\n");

    bw.write('    }'+"\n");

    bw.write('}'+"\n");

    bw.write(''+"\n");

    bw.write('request.disconnect();  '+"\n");

    bw.write(''+"\n");

    bw.write(''+"\n");

    bw.write(''+"\n");+"\n";

     

    if(registerRollbackTask) {

        bw.write('//----------------------------------------------------------------------------------------'+"\n");

        bw.write('//'+"\n");

        bw.write('//        Author: Russ Whitear (rwhitear@cisco.com)'+"\n");

        bw.write('//'+"\n");

        bw.write('// Function Name: registerUndoTask(apicLogin,apicPassword,apicPassword)'+"\n");

        bw.write('//'+"\n");

        bw.write('//       Version: 1.0'+"\n");

        bw.write('//'+"\n");

        bw.write('//    Parameters: apicLogin;         APIC User.'+"\n");

        bw.write('//                apicPassword;      APIC Password.'+"\n");

        bw.write('//                apicIP;            APIC IP.'+"\n");

        bw.write('//'+"\n");

        bw.write('//                '+"\n");

        bw.write('//   Description: Rollback functionality.'+"\n");

        bw.write('//'+"\n");

        bw.write('//'+"\n");

        bw.write('//----------------------------------------------------------------------------------------'+"\n");

        bw.write(''+"\n");

     

        if(rollbackTaskInputs.length) {

            var inputStr = "";

     

            for( var i=0; i < rollbackTaskInputs.length; i++ ) {

                inputStr += ","+rollbackTaskInputs[i];

            }

     

            bw.write('function registerUndoTask(apicLogin,apicPassword,apicIP'+inputStr+') {'+"\n");

        } else {

            bw.write('function registerUndoTask(apicLogin,apicPassword,apicIP) {'+"\n");

        }

     

        bw.write(''+"\n");

        bw.write('    // register undo task    '+"\n");

        bw.write('    var undoHandler = "custom_'+rollbackTaskName+'";'+"\n");

        bw.write('    var undoContext = ctxt.createInnerTaskContext(undoHandler);'+"\n");

        bw.write('    var undoConfig = undoContext.getConfigObject();'+"\n");

        bw.write('    '+"\n");

        bw.write('    // These are the variables that the rollback wf task gets called with. Extra values'+"\n");

        bw.write('    // maybe required for each specific workflow task. An extra example below.'+"\n");

        bw.write('    undoConfig.apicLogin = apicLogin;'+"\n");

        bw.write('    undoConfig.apicPassword = apicPassword;'+"\n");

        bw.write('    undoConfig.apicIP = apicIP;'+"\n");

        bw.write(''+"\n");

        bw.write('    // Add any further workflow inputs below (Use the 3 above for guidance).'+"\n");

     

        if(rollbackTaskInputs.length) {

            for( var i=0; i < rollbackTaskInputs.length; i++ ) {

                bw.write('    undoConfig.'+rollbackTaskInputs[i]+' = '+rollbackTaskInputs[i]+';'+"\n");

            }

        }

     

        bw.write(''+"\n");

        bw.write('    //'+"\n");

        bw.write(''+"\n");

        bw.write('    ctxt.getChangeTracker().undoableResourceModified("Rollback (Description here)", "","rollback ","Rollback (Description here)",undoHandler,undoConfig);'+"\n");

        bw.write('}'+"\n");

     

        bw.write("\n");

        bw.write('//Register rollback task.'+"\n");

     

        if(rollbackTaskInputs.length) {

            var inputStr = "";

     

            for( var i=0; i < rollbackTaskInputs.length; i++ ) {

                inputStr += ","+rollbackTaskInputs[i];

            }

     

            bw.write('registerUndoTask(apicLogin,apicPassword,apicIP'+inputStr+');'+"\n");

        } else {

            bw.write('registerUndoTask(apicLogin,apicPassword,apicIP);'+"\n");

        }

     

    }

     

    bw.flush();

    bw.close();

     

    Step 2)

         Open up the task and fix up a few things...

     

         Screen Shot 2016-10-11 at 5.17.02 PM.png

     

         Obtain from the APIC Inspector the JASON String:

     

         Screen Shot 2016-10-11 at 5.28.04 PM.png

     

         You are looking for the payload

         Screen Shot 2016-10-11 at 1.06.57 PM.png

     

         Adjust for inputs for the new task:

     

              In this case I have a Tenant Name:

     

              Screen Shot 2016-10-11 at 5.34.00 PM.png

     

         Run workflow

     

         Screen Shot 2016-10-11 at 5.34.57 PM.png

     

    This created a file on the UCSD appliance in /tmp:

     

              Screen Shot 2016-10-11 at 5.56.23 PM.png

     

    The file should look some thing like this:

     

    importPackage(java.util);

    importPackage(java.lang);

    importPackage(java.io);

    importPackage(com.cloupia.lib.util);

    importPackage(org.apache.commons.httpclient);

    importPackage(org.apache.commons.httpclient.cookie);

    importPackage(org.apache.commons.httpclient.methods);

    importPackage(org.apache.commons.httpclient.auth);

    importPackage(org.apache.commons.httpclient.protocol);

    importClass(org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory);

    importPackage(com.cloupia.lib.cIaaS.vcd.api);

     

    /****************************************************************************************/

    /**                                                                                    **/

    /**                           !!! IMPORTANT NOTE !!!                                   **/

    /**                                                                                    **/

    /**                                                                                    **/

    /**         THIS SCRIPT REQUIRES A MINIMUM UCS DIRECTOR VERSION OF 5.4.0.0             **/

    /**                                                                                    **/

    /****************************************************************************************/

     

    //----------------------------------------------------------------------------------------

    //                                 ### FUNCTIONS ###

    //----------------------------------------------------------------------------------------

     

    //----------------------------------------------------------------------------------------

    //

    //        Author: Russ Whitear (rwhitear@cisco.com)

    //

    // Function Name: httpRequest()

    //

    //       Version: 3.0

    //

    // Modifications: Added HTTP header Connection:close to execute method to overcome the

    //                CLOSE_WAIT issue caused with releaseConnection().

    //

    //                Modified SSL socket factory code to work with UCS Director 5.4.0.0.

    //

    //   Description: HTTP Request function - httpRequest.

    //

    //                I have made the httpClient functionality more object like in order to

    //                make cloupia scripts more readable when making many/multiple HTTP/HTTPS

    //                requests within a single script.

    //

    //      Usage: 1. var request = new httpRequest();                   // Create new object.

    //         

    //             2. request.setup("192.168.10.10","https","admin","cisco123");      // SSL.

    //          or:   request.setup("192.168.10.10","http","admin","cisco123");       // HTTP.

    //          or:   request.setup("192.168.10.10","https");           // SSL, no basicAuth.

    //          or:   request.setup("192.168.10.10","http");            // HTTP, no basicAuth.

    //

    //             3. request.getRequest("/");                    // HTTP GET (URI).

    //          or:   request.postRequest("/","some body text");  // HTTP POST (URI,BodyText).

    //          or:   request.deleteRequest("/");                 // HTTP DELETE (URI).

    //

    //  (optional) 4. request.contentType("json");            // Add Content-Type HTTP header.

    //          or:   request.contentType("xml");

    //

    //  (optional) 5. request.addHeader("X-Cloupia-Request-Key","1234567890");  // Any Header.

    //

    //             6. var statusCode = request.execute();                     // Send request.

    //

    //             7. var response = request.getResponse("asString");   // Response as string.

    //          or:   var response = request.getResponse("asStream");   // Response as stream.

    //

    //             8. request.disconnect();                             // Release connection.

    //

    //

    //          Note: Be sure to add these lines to the top of your script:

    //

    //          importPackage(java.util);

    //          importPackage(com.cloupia.lib.util);

    //          importPackage(org.apache.commons.httpclient);

    //          importPackage(org.apache.commons.httpclient.cookie);

    //          importPackage(org.apache.commons.httpclient.methods);

    //          importPackage(org.apache.commons.httpclient.auth);

    //          importPackage(org.apache.commons.httpclient.protocol);

    //          importClass(org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory);

    //          importPackage(com.cloupia.lib.cIaaS.vcd.api);

    //

    //----------------------------------------------------------------------------------------

     

    var httpRequest = function () {};

     

    httpRequest.prototype.setup = function(serverIp, transport, username, password) {

        this.serverIp = serverIp;

        this.transport = transport;

        this.username = username;

        this.password = password;

     

     

        this.httpClient = new HttpClient();

     

        // Decide whether to create an HTTP or HTTPS connection based on "transport".

        if( this.transport == "https" ) {

            this.httpClient = CustomEasySSLSocketFactory.getIgnoreSSLClient(this.serverIp, 443);

            this.httpClient.getParams().setCookiePolicy("default");

        } else {

            // Create new HTTP connection.

            this.httpClient.getHostConfiguration().setHost(this.serverIp, 80, "http");

        }

     

        this.httpClient.getParams().setCookiePolicy("default");

     

        // If username and password supplied, then use basicAuth.

        if( this.username && this.password ) {

            this.httpClient.getParams().setAuthenticationPreemptive(true);

            this.defaultcreds = new UsernamePasswordCredentials(this.username, this.password);

            this.httpClient.getState().setCredentials(new AuthScope(this.serverIp, -1, null), this.defaultcreds);

        }

    };

     

    httpRequest.prototype.contentType = function(contentType) {

        this.contentType = contentType;

     

        this.contentTypes = [

            ["xml","application/xml"],

            ["json","application/json"]

        ];

     

        for( this.i=0; this.i<this.contentTypes.length; this.i++)

            if(this.contentTypes[this.i][0] == this.contentType)

                this.httpMethod.addRequestHeader("Content-Type", this.contentTypes[this.i][1]);

    };

     

    httpRequest.prototype.addHeader = function(headerName,headerValue) {

        this.headerName = headerName;

        this.headerValue = headerValue;

     

        this.httpMethod.addRequestHeader(this.headerName, this.headerValue);

    };

     

    httpRequest.prototype.execute = function() {

        // Connection:close is hard coded here in order to ensure that the TCP connection

        // gets torn down immediately after the request. Comment this line out if you wish to

        // experiment with HTTP persistence.

        this.httpMethod.addRequestHeader("Connection", "close");

     

        this.httpClient.executeMethod(this.httpMethod);

     

        // Retrieve status code.

        this.statusCode = this.httpMethod.getStatusCode();

     

        return this.statusCode;

    }

     

    httpRequest.prototype.getRequest = function(uri) {

        this.uri = uri;

     

        // Get request.

        this.httpMethod = new GetMethod(this.uri);

    };

     

    httpRequest.prototype.postRequest = function(uri,bodytext) {

        this.uri = uri;

        this.bodytext = bodytext;

     

        // POST Request.

        this.httpMethod = new PostMethod(this.uri);

        this.httpMethod.setRequestEntity(new StringRequestEntity(this.bodytext));

    };

     

    httpRequest.prototype.getResponse = function(asType) {

        this.asType = asType;

     

        if( this.asType == "asStream" )

            return this.httpMethod.getResponseBodyAsStream();

        else

            return this.httpMethod.getResponseBodyAsString();

    };

     

    httpRequest.prototype.deleteRequest = function(uri) {

        this.uri = uri;

     

        // Get request.

        this.httpMethod = new DeleteMethod(this.uri);

    };

     

     

    httpRequest.prototype.disconnect = function() {

        // Release connection.

        this.httpMethod.releaseConnection();

    };

     

     

     

    // main()

     

    var apicLogin = input.apicLogin;

    var apicPassword = input.apicPassword;

    var apicIP = input.apicIP;

     

    // Place individual variables here...

    // var TENANTNAME = ctxt.getInput("A");...

    // var TENANTNAME = input.A;...

     

    var NewTenant = input.NewTenant;

     

    //

     

    var requestURI = "/api/mo/.json";

     

    // Create JSON login data.

    var aaaUser = new TreeMap();

    aaaUser.put("aaaUser",new TreeMap());

     

    aaaUser.get("aaaUser").put("attributes",new TreeMap());

    aaaUser.get("aaaUser").put("children",new ArrayList());

     

    aaaUser.get("aaaUser").get("attributes").put("name",apicLogin);

    aaaUser.get("aaaUser").get("attributes").put("pwd",apicPassword);

     

    var loginUri  = "/api/mo/aaaLogin.json";

    var loginData = JSON.javaToJsonString(aaaUser, aaaUser.getClass());

     

     

     

    // PASTE APIC JSON REQUEST DATA HERE...

     

    var javaMap = new TreeMap();

     

    javaMap.put("fvTenant",new TreeMap());

    javaMap.get("fvTenant").put("attributes",new TreeMap());

    javaMap.get("fvTenant").put("children",new ArrayList());

    javaMap.get("fvTenant").get("attributes").put("dn","uni/tn-orfapitesttenant");

    javaMap.get("fvTenant").get("attributes").put("name","orfapitesttenant");

    javaMap.get("fvTenant").get("attributes").put("rn","tn-orfapitesttenant");

    javaMap.get("fvTenant").get("attributes").put("status","created");

     

    var requestData = JSON.javaToJsonString(javaMap, javaMap.getClass());

     

    //

     

    requestData = requestData+""; // Convert requestData from object to string.

    requestData = requestData.replace(/\\/g,""); // Overcome some APIC ugliness.

     

     

    logger.addInfo("requestData: " +requestData);

     

    var request = new httpRequest();

          

    request.setup(apicIP,"https");

     

    request.postRequest(loginUri,loginData);

     

    request.contentType("json");

     

    var statusCode = request.execute();            

     

    var response = request.getResponse("asString");

     

    logger.addInfo("Status code: " +statusCode );

     

    logger.addInfo("Response: " +response );

     

    request.postRequest(requestURI,requestData);

     

    var statusCode = request.execute();

     

    var response = request.getResponse("asString");

     

    logger.addInfo("Status code: " +statusCode );

     

    var responseData = JSON.getJsonElement(response,null);

     

    if( responseData.has("imdata") && responseData.get("imdata").size() ) {

     

        for( var i = 0; i < responseData.get("imdata").size(); i++ ) {

     

            if( responseData.get("imdata").get(i).has("error") ) {

                if( responseData.get("imdata").get(i).get("error").has("attributes") ) {

                    if( responseData.get("imdata").get(i).get("error").get("attributes").has("code") ) {

                        logger.addError("APIC Error Code: " + responseData.get("imdata").get(i).get("error").get("attributes").get("code") );

                    }

                    if( responseData.get("imdata").get(i).get("error").get("attributes").has("text") ) {

                        logger.addError("APIC Error Text: " + responseData.get("imdata").get(i).get("error").get("attributes").get("text") );

                    }

                }

         

                // Set failed.

                ctxt.setFailed("Request failed.");

            }

        }

    }

     

    request.disconnect();

     

     

    This section needs to change to my Tenant variable:

     

    var NewTenant = input.NewTenant;

     

    From:

         javaMap.get("fvTenant").get("attributes").put("dn","uni/tn-orfapitesttenant");

         javaMap.get("fvTenant").get("attributes").put("name","orfapitesttenant");

         javaMap.get("fvTenant").get("attributes").put("rn","tn-orfapitesttenant");

    To:

         javaMap.get("fvTenant").get("attributes").put("dn","uni/tn-"+NewTenant+"");

         javaMap.get("fvTenant").get("attributes").put("name",""+NewTenant+"");

         javaMap.get("fvTenant").get("attributes").put("rn","tn-"+NewTenant+"");

     

    Note: Fast way to change these

         cat apic_wf.js | sed s/orfapitesttenant/\"+NewTenant+\"/g

     

     

    Create input variables at the worflow level for this:

     

    Screen Shot 2016-10-11 at 6.09.38 PM.png

     

    Or just quick and dirty test this like this:

     

         Screen Shot 2016-10-11 at 6.21.04 PM.png

     

    This file can now be pasted into a Cloupia task and executed:

     

     

     

    Screen Shot 2016-10-11 at 6.26.50 PM.png


    User input:

     

         Screen Shot 2016-10-11 at 6.27.08 PM.png

     

    Original work by Russ:

     

     

    Conversion Workflow Task

    APIC_API_Inspector_2_UCSD_WF_wRollback_v3_5.4.0.0_plus.js - Box

     

    Baseline Workflow Task Template

    apic_baseline_template.wfdx - Box

     

    HowTo Video

    APIC_JSON_to_UCSD_JS.mp4 - Box