Month: February 2015

vRealize Orchestrator – adding permissions to vCenter using ONYX

I was asked a question about how to do something in javascript using the vCenter API and my response was ‘check ONYX’ to see what API calls are being made. My colleagues response was that he wasn’t a fan of Onyx. Now, for a moment I thought about what he said, carried on and got to the bottom of the problem. However later on, I gave some thought about what my colleague said and I do understand why ONYX doesn’t give you the desired out of the box solution, but it sure don’t half help get you there. So, I decided to pick a task and see what the ONYX output was and how helpful it was. The task was to add a user to a role in vCenter.

This was the output of ONYX

// ------- SetEntityPermissions -------

var entity = Server.findForType("VC:Folder", managedObject.vimHost.id + "/group-d1");

var permission = System.getModule("com.vmware.onyx").array(VcPermission, 1);
permission[0] = new VcPermission();
permission[0].principal = "CORP\\asmith";
permission[0].group = false;
permission[0].roleId = -2;
permission[0].propagate = true;

managedObject.setEntityPermissions(entity, permission);  // AuthorizationManager

It’s pretty rough I reckon, but I started to break down what it was doing to get me my solution. The first line :


var entity = Server.findForType("VC:Folder", managedObject.vimHost.id + "/group-d1");

Now, firstly I didn’t understand what this line was doing, but its obviously looking for VC:Folder called group-d1. Investigating this further, this is the root DC folder where I was adding permissions. When I tried to create this entity, it didn’t recognise what the managedObject was. Fair enough, as ONYX knew, but the script doesn’t have any input to tell it what object it was managing. So I found a script that created that entity for me:


//Assume only one VC is registered in the configurator
var dcFolders = VcPlugin.getAllDatacenterFolders();

//Default alarms are defined in the root object of the inventory.
var rootDCFolder;
for (i in dcFolders) {
     if (!dcFolders[i].parent) {
                //datacenter folder without parent - we found to root object
          rootDCFolder = dcFolders[i];
          System.log(rootDCFolder.name);
          break;
     }
}

So now I had the rootDCFolder entity which was the folder I was adding the permission to.

Looking at the next bit of ONYX output, it was building up the permissions I was applying.


var permission = System.getModule("com.vmware.onyx").array(VcPermission, 1);
permission[0] = new VcPermission();
permission[0].principal = "CORP\\asmith";
permission[0].group = false;
permission[0].roleId = -2;
permission[0].propagate = true;


I just swapped out and the first line above, var permission = System.getModule(“com.vmware.onyx”).array(VcPermission, 1);, for an array, so it looked like this:

var permission = new Array();

Pretty simple, and then I didn’t change any of the VcPermission method attributes as these were the permissions I wanted to set. This is actually the helpful stuff ONYX spits out in my opinion.

However, I needed to create the ‘authorizationManager’ object or AzMan that some of us would have come across before. So I looked at the API object explorer in vRealize Orchetrator and found the VC:Folder object method that was initially returned in the ONYX output.

I then created the authorizationManager as per what the API object explorer explained.

var entity = rootDCFolder.sdkConnection.authorizationManager;

So the last bit of ONYX code was to run the setEntityPermissions using the entity object I set as an instance of authorizationManager.

entity.setEntityPermissions(rootDCFolder, permission);  // AuthorizationManager

So this is the entire script:

// ------- GetEntity -------

var dcFolders = VcPlugin.getAllDatacenterFolders();
var rootDCFolder;
for (i in dcFolders) {
     if (!dcFolders[i].parent) {
                //datacenter folder without parent - we found to root object
          rootDCFolder = dcFolders[i];
          System.log(rootDCFolder.name);
          break;
     }
}

// ------- SetEntityPermissions -------

var entity = rootDCFolder.sdkConnection.authorizationManager;
var permission = new Array();
permission[0] = new VcPermission();
permission[0].principal = "CORP\\csmith";
permission[0].group = false;
permission[0].roleId = -2;
permission[0].propagate = true;

entity.setEntityPermissions(rootDCFolder, permission); 

So, it wasn’t too difficult but my colleague is right though as straight off the bat, ONYX output doesn’t look useful and can put people off. However, there was no way I would have got as far without using ONYX!

Advertisements

Adding a vNIC to a virtual machine in vRealize Automation Center

I was asked the other day to add 2 nics to a virtual machine. 1 nic had to be an adapter type of E1000 and the other had to be a VMXNET3. The reason behind this was because the VM was being built by PXE and until VMtools was installed as part of the build, the VMXNET3 adapter wouldn’t have been recognised by the build process. I thought that I could just specify the custom properties “VMware.Network.Type”, however this is a global property and applies to all vm nics added at request time and you cannot change the apadter type after you have added a NIC to the vm. So I had to add the additional vNIC at the Machine Provisioned vRA stub workflow stage. I also needed to match the virtual wire that was submitted at request time. That was the challenge and this was how I went around it.

First of all I had to get the virtual wire requested. In this post, I am going to use an example of ‘virtual-wire-001’. I then had to find that virtual wire on the logical switch, or in old ESX terms, the dvSwitch. To do this, I got he host the VM was allocated on, searched for this host in the clusters available, then got the dvSwitch so I could get the dvPortGroup object type.

// get host that is running VM
var vmHost = vcVm.runtime.host.name;

// example name for the virtual wire to look for.
var vNic1Network = "virtual-wire-001 ";

// prepare sdk connection
var sdk = Server.findAllForType("VC:SdkConnection");

// loop through SDK connections
for (var con=0; con < sdk.length; con++){

    // create object of allClusterComputeResources
    var clusters = sdk[con].getAllClusterComputeResources();

     // loop through Clusters in allClusterComputeResources

     for each (var cluster in clusters){
    
        // loop through all hosts in cluster
        for each (var host in cluster.host){
        
            // match vm host to host in cluster
            if (vmHost == host.name){
            
                // get object for cluster
                var vmCluster = clusters;

                // get network object in cluster and match on network name requested
                for each (var dvPortGroup in cluster.network){
                
                    if (dvPortGroup.name.indexOf(vNic1Network) = -1){
                        System.log("Found dvPortGroup object to connect the vNIC to: " + dvPortGroup)};
                        break;
                }
            }
        }
    }
}

What this gave me was a dvPortGroup object that I could use to connect the vNIC to on the virtual machine. Next was to create the vNIC on the virtual machine. Initially, I found this next bit tricky to get my head round, but once I understood the code, it opens up a lot of configuration options not just for adding a vNIC, but also adding other virtual machine configuration specifications:


// creating a config spec
var configSpec = new VcVirtualMachineConfigSpec();
var deviceConfigSpecs = new Array();
var deviceConfigSpec;

// create operation for device config spec
var deviceConfigSpec = new VcVirtualDeviceConfigSpec();
deviceConfigSpec.operation = VcVirtualDeviceConfigSpecOperation.add;

// Create connect info for dvPortgroup
var connectInfo = new VcVirtualDeviceConnectInfo();
connectInfo.allowGuestControl = true;
connectInfo.connected = true;
connectInfo.startConnected = true;

// Create Network BackingInfo
var dvsPortConnection = new VcDistributedVirtualSwitchPortConnection();
var dvSwitch = VcPlugin.convertToVimManagedObject(dvPortGroup, dvPortGroup.config.distributedVirtualSwitch);
dvsPortConnection.switchUuid = dvSwitch.uuid;
dvsPortConnection.portgroupKey = dvPortGroup.key;

var netBackingInfo = new VcVirtualEthernetCardDistributedVirtualPortBackingInfo() ;
netBackingInfo.port = dvsPortConnection;

// Create VirtualNetwork
var vNetwork = new VcVirtualVmxnet3();
vNetwork.backing = netBackingInfo;
vNetwork.unitNumber = 0;
vNetwork.addressType = "Generated";
vNetwork.wakeOnLanEnabled = true;
vNetwork.connectable = connectInfo;

// Creating devicespecs configured in vNetwork object
deviceConfigSpec.device = vNetwork;
deviceConfigSpecs[0] = deviceConfigSpec;

// List of devices
configSpec.deviceChange = deviceConfigSpecs;

// Launch the reconfigVM task
vcVmTask = vcVm.reconfigVM_Task( configSpec );

The key areas in this script are as follows:

// List of devices
configSpec.deviceChange = deviceConfigSpecs;

// Launch the reconfigVM task
vcVmTask = vcVm.reconfigVM_Task( configSpec );

This creates an object that is used to submit the configuration specifications

var configSpec = new VcVirtualMachineConfigSpec();

We then build up this object with various configuration objects that are required. Things like connection information, dvsPortConnection, adapter type settings. Here’s each bit in more info.

For the connection settings, these are quite obvious.

var connectInfo = new VcVirtualDeviceConnectInfo();
connectInfo.allowGuestControl = true;
connectInfo.connected = true;
connectInfo.startConnected = true;

We are basically telling the NIC to be connected at start up and connected by default.

The next was to create the dvsPortConnection settings. Here is where we pass the dvPortGroup object found in the cluster the virtual machine was allocated in.

var dvsPortConnection = new VcDistributedVirtualSwitchPortConnection();
var dvSwitch = VcPlugin.convertToVimManagedObject(dvPortGroup, dvPortGroup.config.distributedVirtualSwitch);
dvsPortConnection.switchUuid = dvSwitch.uuid;
dvsPortConnection.portgroupKey = dvPortGroup.key;

You need to pass in the dvPortGroup object to get the uuid and the key for the dvSiwtch. These values are effectively required to know how to ‘attach’ the vNIC to the dvswitch. If you don’t have these settings, the portgroup will be blank and you will get an invalid backing message, and hence no network connectivity. Once you create this object, you need to add this to the VcVirtualEthernetCardDistributedVirtualPortBackingInfo() object

var netBackingInfo = new VcVirtualEthernetCardDistributedVirtualPortBackingInfo() ;
netBackingInfo.port = dvsPortConnection;

The next section is required to create the VcVirtualVmxnet3 settings. There are different object types for different vNICs. As I needed the vmxnet3 vNIC, I used the VcVirtualVmxnet3() object type. You also have VcVirtualE1000, VcVirtualE1000e, VcVirtualVmxnet2 etc.

var vNetwork = new VcVirtualVmxnet3();
vNetwork.backing = netBackingInfo;
vNetwork.unitNumber = 0;
vNetwork.addressType = "Generated";
vNetwork.wakeOnLanEnabled = true;
vNetwork.connectable = connectInfo;

What we are doing now is adding some of the previously created objects to the VcVirtualVmxnet3 object, for example the netBackingInfo, connectInfo etc. This is making up the profile of the vNIC.

Once we have created the vNIC profile, we just need to execute the object on the vNIC.

// Creating devicespecs configured in vNetwork object
deviceConfigSpec.device = vNetwork;
deviceConfigSpecs[0] = deviceConfigSpec;

// List of devices
configSpec.deviceChange = deviceConfigSpecs;

// Launch the reconfigVM task
vcVmTask = vcVm.reconfigVM_Task( configSpec );

In my vRO workflow, the vcVm is the VC:VirtualMachine object passed in to the stub workflow.

Here’s a look at the workflow:

Screen Shot 2015-02-17 at 20.35.50 1

and here are the input parameters:

Screen Shot 2015-02-17 at 20.36.54

Hope this helps

vRealize Orchestrator – connecting to more than one domain using the Active Directory plugin

  1. The vRealize Orchestrator plugin only supports connecting to one active directory domain so what happens if you want to connect to more than one domain to create a user or an organizational unit? Well, it is possible to refocus the active directory plugin on the fly to do just that but you need to consider how this will work in your environment and design your AD workflows appropriately.

    Firstly, lets take a look at the vRO Active Directory plugin ‘Configure Active Directory server’ workflow that configures the plugin to connect to a domain.

    Screen Shot 2015-03-08 at 14.21.03

    When you run the workflow to add a domain, you are presented with the following form:

    Screen Shot 2015-03-08 at 14.23.08

    Now you can relate these presentation inputs to what is going on inside the workflow. So the first scripting element in the workflow determines whether you are using SSL and the second workflow element imports the certificate if you are.

    The reason why I mention this is that if you are using SSL for LDAP connectivity, it’s worth importing all your domain SSL certificates into vRO so vRO can use a valid certificate if you are to refocus the plugin to connect to a domain over SSL.

    Now if we take a look at the ‘Update configuration’ scripting element, you can see the following code:

    
    var configuration = new AD_ServerConfiguration();
    configuration.host = host;
    configuration.port = port;
    configuration.ldapBase = ldapBase;
    configuration.useSSL = useSSL;
    configuration.defaultDomain = defaultDomain;
    configuration.useSharedSession = useSharedSession;
    configuration.sharedUserName = sharedUserName;
    configuration.sharedUserPassword = sharedUserPassword;
    
    ConfigurationManager.validateConfiguration(configuration);
    ConfigurationManager.updateConfiguration(configuration);
    
    

    So what you can do is run this specific block of code to connect to another domain each and every time time you want to do domain operations in a specific domain in a multi-domain environment. It’s best to use a configuration element to store your domain information and by using some logic, you can determine what domain you want to use and then use the values in your configuration element to populate the required domain configuration values in the block of code above.

    However, there is one absolute key thing here to implement and that is design your workflow using the LockingSystem scripting class. Any workflow that needs to configure active directory objects will need to run the block of code that refocuses the domain connection to use, then run a workflow to create, update, read, delete AD objects. So you need to let workflow operation finish first before allowing another workflow change the focus of the domain that you are connecting to. You can do this using the LockingSystem scripting class, example as follows:

    Screen Shot 2015-03-08 at 14.39.09

    So the set lock would look like this:

    
    LockingSystem.lockAndWait("AdOperationLock", workflow.id);
    
    

    Then once the lock is set, the refocus domain code runs and you can change to a different domain,  then run an AD operation, then remove the lock. So the remove lock would look like this:

    
    LockingSystem.unlock("AdOperationLock", workflow.id);
    
    

    You can have multiple workflows using this locking system, as long as the lock you use is called the same, in other words “AdOperationLock” in the example above.

    Also, you could use an action item to lock and refocus the domain connection and use the action item for any workflows you are calling that run AD operations, making the locking and refocus aspects modularized. Remember to unlock the lock and to use the same lockid name, for example “AdOperationLock”.

    There are limitations with this as you can only ever run one workflow to read / configure / delete active directory objects at any one time as you can’t have refocusing happen when existing AD operation workflows are running. However, most of the time active directory updates are generally small operations and the workflows should run pretty quick. Therefore, if you do have a lot of AD operations, the likelihood is that you should only have a few seconds to wait until your workflow in waiting runs – workflows check every 2 seconds to see if the lock it has has been released in the vRA database, so the length of time the workflow in waiting will have to wait before it runs will be 2 seconds max plus the length of time the current workflow execution time is. However this is something you need to consider in your environment.

    There are other solutions in a multi-domain environment, for example using PowerShell scripts, but if you can keep it all in vRO, you can keep all the code in one place, and create modular workflow elements for AD operations, then it’s one less programming language and dependancy to manage in vRO.