Managing vCenter datastores cluster with VCF Orchestrator

Beginning

Today, I’ll configure a storage DRS cluster in vCenter using VCF Orchestrator.

The goal

To cover the most common functionality and make it as general and generic as possible.

Something like that…

Final Workflow

Let’s see how to get there. I wanted to:

  • Support multiple vCenters.
  • Support multiple datastore clusters.
  • Support default and most common settings adjustments.
  • Provide the defaults where applicable.

vCenters

To get all the vCenters and show them in the custom form’s dropdown box, I am using a simple function as an action element, looking for all objects of type VC:SdkConnection and returning it as an array, because that’s what the dropdown box is expecting.

/**
 *
 * @return {Array/string}
 */
(function () {
  const sdkConnections = Server.findAllForType('c') as VcSdkConnection[];
  const vcNames = sdkConnections.map(vc =>
    vc.id
  );
  return vcNames;
});

Datastore clusters

To get all available clusters, the idea is the same (to write a function in the action element), but the code, of course, is different.

First, I need to get the SDK connection (vCenter) as an object. For that, I am using the function I already wrote called getVcSdkConnectionByName, which can be found here. Once I have it, I can use a built-in method called getAllVimManagedObject and provide a StoragePod (which is a datastore cluster in API language) as a managed object I am looking for. This method returns an array of objects (datastoreClusters variable), so I should get all the available datastore clusters in that vCenter.

If this array is not empty (important to check), I am looping through and get the names to show them in the workflow dropdown box.

/**
 * @param {string} vCenter - vCenter name
 *
 * @return {Array/string}
 */
(function (vCenter) {
  if (!vCenter) return [""];
  let datastoreClusters = [];

  if (vCenter) {
    const sdkConnection = System.getModule('com.examples.vmware_aria_orchestrator_examples.actions')
      .vcSdkManagement()
      .VcSdkManagement.prototype.getVcSdkConnectionByName(vCenter);
    datastoreClusters = sdkConnection.getAllVimManagedObjects("StoragePod", null, null);
  }

  if (datastoreClusters.length !== 0) {
    let datastoreClusterNames = [];
    for (var i = 0; i < datastoreClusters.length; i++) {
      datastoreClusterNames.push(datastoreClusters[i].name);
    }
    return datastoreClusterNames;
  }
});

The logic

Let’s think… To do any manipulation with a datastore cluster, there are a few requirements that must be defined:

  1. StorageResourceManager
  2. VcStoragePod
  3. VcStorageDrsConfigSpec

And more, based on how many use cases should be covered. In my case, I need those two more, because I want to be able to control DRS load balancing features.

  1. VcStorageDrsIoLoadBalanceConfig
  2. VcStorageDrsSpaceLoadBalanceConfig

Therefore, my brand new DatastoreClusterManagement class looks like that:

DatastoreClusterManagement class

Find storage pod

First thing first. To modify a datastore cluster, I should find it and return its object. The name of the cluster I am getting from the workflow’s form and passing to the findStoragePod as storagePodName argument.

Now, I can use vCenter.getAllVimManagedObjects('StoragePod', [], "xpath:name[matches(.,'" + storagePodName + "')]") to find the object.

It is a best practice to use xpath for a global searches/filters.

getAllVimManagedObjects always returns an arrays. Therefore, I want to make sure it’s not empty and its unique.

private findStoragePod(vCenter: VcSdkConnection, storagePodName: string): VcStoragePod {
  const storagePods = vCenter.getAllVimManagedObjects('StoragePod', [], "xpath:name[matches(.,'" + storagePodName + "')]");
  if (storagePods.length === 0) {
    throw new Error(`Storage Pod with name ${storagePodName} not found.`);
  }
  if (storagePods.length > 1) {
    throw new Error(`Multiple Storage Pods found with name ${storagePodName}. Please specify a unique name.`);
  }
  return storagePods[0] as VcStoragePod;
}

findStoragePod method

Build storage DRS config spec

To build a spec, I need a few things:

  1. Define a spec using a VcStorageDrsConfigSpec() class.
  2. Define a pod config using a VcStorageDrsPodConfigSpec class.
  3. Have all the values I want to set by getting them from the custom form.

To accomplish that, let’s create a new method called buildStorageDrsConfigSpec and implement the necessary logic. All the supported parameters of podConfig can be found in the VCF Orchestrator’s API. I’ve only included the parameters that I needed.

const spec = new VcStorageDrsConfigSpec();
const podConfig = new VcStorageDrsPodConfigSpec();
const spaceLoadBalanceConfig = { minSpaceUtilizationDifference, spaceThresholdMode, freeSpaceThresholdGB, spaceUtilizationThreshold };

podConfig.defaultVmBehavior = defaultVmBehavior;
podConfig.ioLoadBalanceConfig = this.buildIoLoadBalanceConfig(ioLoadImbalanceThreshold, ioLatencyThreshold);
podConfig.spaceLoadBalanceConfig = this.buildSpaceLoadBalanceConfig(spaceLoadBalanceConfig);
podConfig.ioLoadBalanceEnabled = ioLoadBalanceEnabled;
podConfig.defaultIntraVmAffinity = defaultIntraVmAffinity;
podConfig.automationOverrides = new VcStorageDrsAutomationConfig();
podConfig.loadBalanceInterval = loadBalanceInterval;
podConfig.enabled = isEnabled;

spec.podConfigSpec = podConfig;

return spec;

buildStorageDrsConfigSpec method

The workflow

The scriptable task in the workflow itself is pretty simple:

  • Get VC instance object
const sdkConnection: VcSdkConnection = System.getModule('com.examples.vmware_aria_orchestrator_examples.actions')
      .vcSdkManagement()
      .VcSdkManagement.prototype.getVcSdkConnectionByName(vCenter);
  • Define new instance of DatastoreClusterManagement class
const datastoreCluster = new DatastoreClusterManagement();
  • Pass all the variables and trigger the configuration
const task = datastoreCluster.configureStorageDrsForPod(
      { vc: sdkConnection, datastoreClusterName, defaultVmBehavior, ioLoadImbalanceThreshold, ioLatencyThreshold, minSpaceUtilizationDifference, spaceThresholdMode, freeSpaceThresholdGB, spaceUtilizationThreshold, ioLoadBalanceEnabled, defaultIntraVmAffinity, loadBalanceInterval, isEnabled });
    System.getModule("com.vmware.library.vc.basic").vim3WaitTaskEnd(task, true, 2);

Tests

Let’s start the workflow. It is starting with pre-defined default values, tips for the operator, and smart selections. In that example, Space Threshold Mode can be either Utilization or Free Space. If Utilization is selected, the value will be Space Utilization Threshold.

Workflow inputs

If Free Space is selected, it switches to Free Space mode, and the Space Utilization Threshold input disappears.

Workflow inputs

Run the workflow. In the logs, I can see the selected vCenter was found, and the cluster was reconfigured successfully.

Workflow execution logs

The same is visible on the vCenter side. All the provided values were set correctly.

Datastore Cluster Settings in vCenter

Summary

Today, we witnessed another excellent instance of utilizing Orchestrator to automate and control of configuration changes.

For instance, I can set the minimum and maximum values permitted for thresholds, following to the company’s policies. This task becomes significantly challenging when relying purely on the vCenter’s GUI.

Source Code

The source code with the unit tests can be found here.

The vRO package is also available here and the external ECMASCRIPT package here.

All packages should be imported

💡

Would you consider referring this post to a friend if you enjoy my job? Your support helps me to grow and brings more aspiring mates into the community.
I also want to hear from you about how I can improve my topics! Please leave a comment with the following:
– Topics you’re interested in for future editions
– Your favorite part or take away from this one

I’ll do my best to read and respond to every single comment!

Similar Posts