UCSD - Multi VM Provisioning with Post Provisioning and Rollback Example (Swiss Army Knife)

Version 10
    Task Name

    Multi VM Provisioning with Post Provisioning and Rollback

    Description

     

    Prerequisites
    1. Tested on 5.4
    CategoryWorkflow
    ComponentsvSphere 5.x
    User Inputse-mail address
    Outpute-mail with counter

    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

     

     

    The Workflow:

    Screen Shot 2015-11-17 at 4.04.53 PM.png'

     

    The workflow input with marked changes for different environment:

     

    Screen Shot 2015-11-17 at 4.04.24 PM.png

     

    Catalog and VDC need to change from drop down in admin Input Value!

    If desired the starting VM number needs to change as well.

     

    The mapped input in the VM deploy task:

     

    Screen Shot 2015-11-17 at 4.05.05 PM.png

     

    Screen Shot 2015-11-17 at 4.05.22 PM.png

     

    Screen Shot 2015-11-17 at 4.05.37 PM.png

     

    Workflow execution:

     

    Screen Shot 2015-11-17 at 4.06.16 PM.png

     

    The catalog with the post Provisioning workflow selected:

     

    Screen Shot 2015-11-17 at 4.07.01 PM.png

     

    The workflow will e-mail 2 inout variables:

     

    Screen Shot 2015-11-17 at 4.07.42 PM.png

     

    The post provisioning workflow:

     

    Screen Shot 2015-11-17 at 4.07.51 PM.png

     

    This workflow is also in the attached zip file.

     

    The workflow will kick off 2 child workflows (Since deploy 2 VMs was selected):

     

    Screen Shot 2015-11-17 at 4.25.09 PM.png

     

    The e-mail from the post provisioning workflow:

     

    Screen Shot 2015-11-17 at 4.30.03 PM.png

    System Policy:

     

    Screen Shot 2016-11-18 at 2.17.59 PM.png

     

     

    The Code:

     

    importPackage(com.cloupia.model.cIM);

    importPackage(java.util);

    importPackage(java.lang);

    importPackage(java.io);

    importPackage(com.cloupia.lib.util);

    importPackage(com.cloupia.model.cIM);

    importPackage(com.cloupia.service.cIM.inframgr);

    importPackage(org.apache.commons.httpclient);

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

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

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

    importPackage(com.cloupia.model.cEvent.notify);

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

    importPackage(com.cloupia.fw.objstore);

    importPackage(com.cloupia.lib.cIaaS.vmware);

    importPackage(com.cloupia.feature.customactions.configs);

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

     

     

    var delaySecondsBetweenInvocation = 30;

     

     

    function sleep()

    {

                  var milliseconds = delaySecondsBetweenInvocation * 1000;

                  Thread.sleep(milliseconds);

    }

     

     

    var catID = input.CatalogName;

    var vdcID = input.VDCName;

    var vmowner = input.VMOwner;

    var vmname = input.VMName;

    var vmcomment = input.VMComment;

    var vmcpu = input.VMCPU;

    var vmmemory = input.VMMemory;

    var vmdisksize = input.VMDiskSize;

    var wfi1 = input.WorkflowInput1;

    var wfi2 = input.WorkflowInput2;

    var counter = input.Counter;

    var startcounter = input.StartCounter;

    //

    // Convert the VDC and Catalog ID to a name

    //

    var vdc2 = VDCUtil.getVDC(vdcID);

    var vdcName = vdc2.getVdcName();

    var cat2 = VDCUtil.getVDCCatalogItem(catID);

    var catName = cat2.getCatalogItemName();

    logger.addInfo("---------------------------------");

    logger.addInfo("params vdcID = "+vdcID);

    logger.addInfo("params vdcName = "+vdcName);

    logger.addInfo("params catID = "+catID);

    logger.addInfo("params cat = "+catName);

    logger.addInfo("---------------------------------");

    //

    // Set up the provision VM information

    //

    var params = new APIProvisionParams();

     

     

    logger.addInfo("params cat = "+catName);

    params.setCatalogName(catName);

     

     

    logger.addInfo("VDC  = "+vdcName);

    params.setVdcName(vdcName);

     

     

    logger.addInfo("params vmowner = "+vmowner);

    params.setUserID(vmowner);

     

     

    logger.addInfo("params vmname = "+vmname);

    params.setVmName(vmname);

     

     

    logger.addInfo("params vmcomment = "+vmcomment);

    params.setComments(vmcomment);

     

     

    logger.addInfo("params vmcpu = "+vmcpu);

    params.setCores(vmcpu);

     

     

    logger.addInfo("params vmmemory = "+vmmemory);

    params.setMemoryMB(vmmemory);

     

     

    logger.addInfo("params disksize1 = "+vmdisksize);

    params.setDiskGB(vmdisksize);

    //

    //If Post Provision workflow has user inputs then the following code is required to pass user inputs to API.

    //If the post provision workflow has only task inputs then skip the below code.

    //It is not required to setPostProvWFUserInputs.

    //remember the catalog has the post provisioning workflow

    //here only the inout parameters for the postprovisioning workflow are set

    //

    logger.addInfo("params wfi1 = "+wfi1);

    var nv1 = new APINameValue("A1",wfi1);

     

     

    logger.addInfo("params wfi2 = "+wfi2);

    var nv2 = new APINameValue("A2",wfi2);

     

     

    logger.addInfo("---------------------------------");

     

     

    var list = new APINameValueList();

    list.addNameValue(nv1);

    list.addNameValue(nv2);

    //Add this inputs list to provision params.

    params.setPostProvWFUserInputs(list);

    //

    // Call New Service Request provision VM

    //

     

     

    var qty = 1;

     

     

    try {

        qty = Integer.valueOf(counter);

    } catch( e) {

        logger.addWarning("Invalid counter specified:"+counter+ " provisioning one VM");

    }

    try {

        sc = Integer.valueOf(startcounter);

    } catch( e) {

        logger.addWarning("Invalid start counter specified:"+startcounter+ " provisioning one VM");

    }

     

     

    logger.addInfo("Start Counter ="+ startcounter);

     

     

    var childSrIdArray = [];

    // start loop

    for (var ctr = 0; ctr < qty; ctr = ctr + 1)

    {

      logger.addInfo("Provision VM ="+ (ctr+1) + " of "+qty);

     

     

      var number = sc + ctr + 1;

      logger.addInfo("VM Number ="+ number);

     

     

      logger.addInfo("params vmname = "+vmname+number);

      params.setVmName(vmname+number);

     

     

      logger.addInfo("params vmcomment = "+vmcomment+number);

      params.setComments(vmcomment+number);

     

     

      logger.addInfo("-------------------Provsion VM---------------------------------");

      var srId = ctxt.getAPI().userAPIProvisionRequest(params);

     

      logger.addInfo("childSrId= "+srId);

      childSrIdArray[ctr] = srId;

     

     

      logger.addInfo("Sleeping for a bit (30 sec...");

      sleep();

    }

    // end loop

     

     

    logger.addInfo("-------------------Waiting for Child Workflow(s) to Finish---------------------------------");

     

     

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

    {

                    var childSrId = childSrIdArray[i];

                    var status = ctxt.waitForCompletion(childSrId, 1800000);      

                    if (status == 0)

                    {

                                    logger.addInfo("Provisioned SR ID  ="+ childSrId+ " successfully.");

                    } else {

                                    logger.addError("SR ID  ="+ childSrId+ " failed");

                    }

    }

     

     

    rollbackMultiVM(childSrIdArray);

     

     

    function rollbackMultiVM(childSrIdArray){

     

     

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

     

      var srId = childSrIdArray[i];

     

      var vmList = GroupManagerImpl.getVMsAssociatedWithServiceRequest(srId);

     

      ctxt.getChangeTracker().undoableResourceModified(VMwareAssetTypeConstants.VMWARE_RELEASE_IP, srId+"",srId+"",

                    "IP to be released for SR:" + srId,

                    RemoveIPAddressReservationConfig.HANDLER_NAME,

                    new RemoveIPAddressReservationConfig(srId));

     

      if(vmList != null && vmList.size()>0){

      for(var j=0; j<vmList.size(); j++){

      var gvm = vmList.get(j);

      ctxt.getChangeTracker().undoableResourceModified(VMwareAssetTypeConstants.VMWARE_VM, String.valueOf(gvm.getVmId()),

      gvm.getInstanceId(), "VM " + gvm.getInstanceId() + " provisioned on the host " + gvm.getParentHost(),

      DeleteVMConfig.HANDLER_NAME,

      new DeleteVMConfig(gvm.getVmId()));

      }

      }

      }

    }

     

     

     

    Run with 3 VM's and rollback:

     

     

     

    Workflow Inputs:

    - VMname

    - VMComment

    - VDC

    - Catalog

    - Memory

    - CPU

    - Disk

    - HowManyVMs

    - VMStartCounter

    - WorkFlowInput1

    - WorkFlowInput2

    - VMOwner

     

     

     

     

    Nov 24, 2015 17:52:43 UTC Request submitted

    Nov 24, 2015 17:52:48 UTC Executing workflow item number 1

    Nov 24, 2015 17:52:48 UTC Completed workflow item number 0, with status Completed

    Nov 24, 2015 17:52:55 UTC Executing workflow item number 2

    Nov 24, 2015 17:52:55 UTC Trigger context executeWorkFlowStep called

    Nov 24, 2015 17:52:55 UTC Executing custom action MultiVMDeploymentWithPostprovisioning (custom_MultiVMDeploymentwithPostProvisioning)

    Nov 24, 2015 17:52:55 UTC Executing custom action MultiVMDeploymentWithPostprovisioning (custom_MultiVMDeploymentwithPostProvisioning)

    Nov 24, 2015 17:52:55 UTC Executing custom script for MultiVMDeploymentwithPostProvisioning

    Nov 24, 2015 17:52:58 UTC ---------------------------------

    Nov 24, 2015 17:52:58 UTC params vdcID = 127

    Nov 24, 2015 17:52:58 UTC params vdcName = VDC-Prod

    Nov 24, 2015 17:52:58 UTC params catID = 154

    Nov 24, 2015 17:52:58 UTC params cat = LinuxWebApp

    Nov 24, 2015 17:52:58 UTC ---------------------------------

    Nov 24, 2015 17:52:58 UTC params cat = LinuxWebApp

    Nov 24, 2015 17:52:58 UTC VDC = VDC-Prod

    Nov 24, 2015 17:52:58 UTC params vmowner = orf

    Nov 24, 2015 17:52:58 UTC params vmname = Rock

    Nov 24, 2015 17:52:58 UTC params vmcomment = Rock

    Nov 24, 2015 17:52:58 UTC params vmcpu = 2

    Nov 24, 2015 17:52:58 UTC params vmmemory = 2048

    Nov 24, 2015 17:52:58 UTC params disksize1 = 10

    Nov 24, 2015 17:52:58 UTC params wfi1 = happy

    Nov 24, 2015 17:52:58 UTC params wfi2 = tuesday

    Nov 24, 2015 17:52:58 UTC ---------------------------------

    Nov 24, 2015 17:52:58 UTC Start Counter =99

    Nov 24, 2015 17:52:58 UTC Provision VM =1 of 3

    Nov 24, 2015 17:52:58 UTC VM Number =100

    Nov 24, 2015 17:52:58 UTC params vmname = Rock100

    Nov 24, 2015 17:52:58 UTC params vmcomment = Rock100

    Nov 24, 2015 17:52:58 UTC -------------------Provsion VM---------------------------------

    Nov 24, 2015 17:53:04 UTC childSrId= 5903

    Nov 24, 2015 17:53:04 UTC Sleeping for a bit (30 sec...

    Nov 24, 2015 17:53:34 UTC Provision VM =2 of 3

    Nov 24, 2015 17:53:34 UTC VM Number =101

    Nov 24, 2015 17:53:34 UTC params vmname = Rock101

    Nov 24, 2015 17:53:34 UTC params vmcomment = Rock101

    Nov 24, 2015 17:53:34 UTC -------------------Provsion VM---------------------------------

    Nov 24, 2015 17:53:41 UTC childSrId= 5904

    Nov 24, 2015 17:53:41 UTC Sleeping for a bit (30 sec...

    Nov 24, 2015 17:54:11 UTC Provision VM =3 of 3

    Nov 24, 2015 17:54:11 UTC VM Number =102

    Nov 24, 2015 17:54:11 UTC params vmname = Rock102

    Nov 24, 2015 17:54:11 UTC params vmcomment = Rock102

    Nov 24, 2015 17:54:11 UTC -------------------Provsion VM---------------------------------

    Nov 24, 2015 17:54:17 UTC childSrId= 5905

    Nov 24, 2015 17:54:17 UTC Sleeping for a bit (30 sec...

    Nov 24, 2015 17:54:47 UTC -------------------Done Waiting for Child Workflow to Finish---------------------------------

    Nov 24, 2015 18:08:40 UTC Workflow with SR-ID 5903 is complete

    Nov 24, 2015 18:08:40 UTC Provisioned SR ID =5903 successfully.

    Nov 24, 2015 18:08:50 UTC Workflow with SR-ID 5904 is complete

    Nov 24, 2015 18:08:50 UTC Provisioned SR ID =5904 successfully.

    Nov 24, 2015 18:09:00 UTC Workflow with SR-ID 5905 is complete

    Nov 24, 2015 18:09:00 UTC Provisioned SR ID =5905 successfully.

    Nov 24, 2015 18:09:00 UTC Task #1 (MultiVMDeploymentWithPostprovisioning (custom_MultiVMDeploymentwithPostProvisioning)) completed successfully in 965 seconds

    Nov 24, 2015 18:09:00 UTC Input/Output values for Task #1 (MultiVMDeploymentWithPostprovisioning (custom_MultiVMDeploymentwithPostProvisioning)):

    Nov 24, 2015 18:09:00 UTC [Mapped Input: CatalogName = 154]

    Nov 24, 2015 18:09:00 UTC [Mapped Input: VDCName = 127]

    Nov 24, 2015 18:09:00 UTC [Template Input:VMOwner = ${INITIATING_USER}]

    Nov 24, 2015 18:09:00 UTC [Resolved Template Input: VMOwner = orf]

    Nov 24, 2015 18:09:00 UTC [Mapped Input: VMOwner = orf]

    Nov 24, 2015 18:09:00 UTC [Mapped Input: VMName = Rock]

    Nov 24, 2015 18:09:00 UTC [Mapped Input: VMComment = Rock]

    Nov 24, 2015 18:09:00 UTC [Mapped Input: VMCPU = 2]

    Nov 24, 2015 18:09:00 UTC [Mapped Input: VMMemory = 2048]

    Nov 24, 2015 18:09:00 UTC [Mapped Input: VMDiskSize = 10]

    Nov 24, 2015 18:09:00 UTC [Mapped Input: WorkflowInput1 = happy]

    Nov 24, 2015 18:09:00 UTC [Mapped Input: WorkflowInput2 = tuesday]

    Nov 24, 2015 18:09:00 UTC [Mapped Input: Counter = 3]

    Nov 24, 2015 18:09:00 UTC [Mapped Input: StartCounter = 99]

    Nov 24, 2015 18:09:00 UTC Completed workflow item number 1, with status Completed

    Nov 24, 2015 18:09:06 UTC Executing workflow item number 3

    Nov 24, 2015 18:09:06 UTC Completed workflow item number 2, with status Completed

     

     

    The rollback options:

     

    Screen Shot 2015-11-24 at 12.20.48 PM.png

     

    The rollback:

     

    Screen Shot 2015-11-24 at 12.23.27 PM.png

     

    Here are the other options that the current workflow does not account for as input to the API call:

     

    Screen Shot 2016-03-09 at 1.34.59 PM.png

     

    In ASCII form:

     

    /app/api/rest?formatType=json&opName=userAPIProvisionRequest&opData={param0:{"catalogName":"sample","vdcName":"sample","userID":"sample","durationHours":1000,"beginTime":0,"quantity":1000,"memoryMB":0,"diskGB":1000,"cores":1000,"estimatedCost":1000.0,"comments":"sample","additionalInfo":"sample","chargeFrequency":1000,"nicAliasName":"sample","nicPortGroupName":"sample","resourceAllocated":true,"allocatedHost":"sample","allocatedDataStore":"sample","allocatedResourcePool":"sample","altAllocatedHost":"sample","altAllocatedDataStore":"sample","altAllocatedResourcePool":"sample","customStartupMemory":1000.0,"customMaxMemory":1000.0,"customMemoryBuffer":1000.0,"customMemoryConfig":true,"customStoragePolicy":"sample","allocatedCluster":"sample","customCpuSockets":1000,"customCpuCoresPerSocket":1000,"altAllocatedCluster":"sample","allocatedAddnlDatastores":"sample","altAllocatedAddnlDatastores":"sample","altAllocatedAddnlVNICs":"sample","altAllocatedAddnlVNICsIpv6":"sample","selectedDiskDataStore":"sample","actionId":"sample","vmName":"sample","vdcCategory":"sample","windowsLicensePool":"sample","templateUserId":"sample","templatePassword":"sample","credentialOption":"sample","provisionAllDisk":true,"enableGuestCustomization":true,"enablePostProvisioningCustomActions":true,"workflow":"sample","vmId":1000,"vMAppChargeFrequency":1000,"activeVMAppCost":1000.0,"inactiveVMAppCost":1000.0,"useLinkedClone":true,"snapshotId":1000,"snapshotKey":"sample","newSnapshotName":"sample","isHighlyAvailable":true,"overrideCatalogCategoryId":1000,"nicIPAddressOverride":"sample","postProvWFUserInputs":{"list":[{"name":"sample","value":"sample"},{"name":"sample","value":"sample"}]}}}

     

     

     

    Notes on the rollback Function.

    Thank you goes to Gabor Szabo and Tejeswar Sahu

     

    Questions:

     

     

    I would like to ask some clarification question:

    1.)    [endif]Is there a mandatory rule for the format of the „undoHandler” variable or can I choose it freely?

    2.)    [endif]What is the role of the first four parameter of the “ChangeTracker().undoableResourceModified()” method (assetType, assetId, assetLabel, description)? Where are these used and are there any rule for the values I need to be aware of?

    3.)    [endif]Do I need to clean-up the resources I have used for the rollback (like the undoContext or undoConfig)? Or it is done automatically?



     

    answer for my Q1:


    the format of the „undoHandler” string MUST be „custom_<Name-Of-A-Custom-Task>”, otherwise UCSD Javascript interpreter throws an exception.

     

    Example: if a custom task is called “MyTask”, the undoHandler must be “custom_MyTask”. Either “custom1_MyTask” or “custom_xxMyTask” throws exception. Interestingly the undoHandler don’t need to refer to the same task, only it must include a valid custom task name (example: if I have another custom task called “MyOtherTask”, the undoHandler of “MyTask” can be “custom_MyOtherTask”). In such case the “MyTask” rollback workflow will call the “MyOtherTask” task with the prepared undoConfig oblect.




    3 answers from the BU:

     

    Generally we use the below line of code for registering the rollback task in the script part of custom task.

     

    ctxt.getChangeTracker().undoableResourceModified(String assetType, String assetId, String assetLabel, String description, String undoTaskHandlerName, Object undoTaskConfigPOJO)

    Here the last two parameters (undoTaskHandlerName, undoTaskConfigPOJO) are most important.

     

    1.)    [endif] Is there a mandatory rule for the format of the “undoHandler” variable or can I choose it freely?(In this case “undoTaskHandlerName”)?

    Ans:We can’t choose it freely.It should and must be the task name which we want to register for the rollback purpose. We can get this task name as shown below.

    First we need to drag and drop the task into the workflow designer and from there we can find the task name.


    Unknown.png


     

    2.)    [endif] What is the role of the first four parameter of the “ChangeTracker().undoableResourceModified()” method (assetType, assetId, assetLabel, description)? Where are these used and are there any rule for the values I need to be aware of?

    Ans: assetId and description is used as shown below when we right click on the SR and try to roll back it.


    Unknown-1.png


     

     

    As per my understanding ,assetType and assetLabel is not holding much significant role in our case and can be passed any string types.

     

    [if !supportLists]3.)    [endif]Do I need to clean-up the resources I have used for the rollback (like the undoContext or undoConfig)? Or it is done automatically?

          Ans: Here undoContext or undoconfig are just like any other script variable in the script section.So these things will be taken care by the UCSD platform.