vRA Developer: Part 8 – Working with vCAC Reservation Storage


In my previous post, I covered working with vcac reservations and provided examples of how you can retrieve property values and also linked entities, such as networks and virtual machines. In this post I am going to cover reserved storage. I planned to include this in the previous post, but the content was becoming too large, so I decided to split them.

The Actions provided here should be useful if you ever need to work with storage outside of vRA (for example, when adding or resizing a virtual hard disk directly in vCenter) and can be used to query reservation information first. This can prevent cases where storage can exceed that which is allocated/reserved for the tenant.

Here is how the reserved storage looks for the reservation that I will be working with:

All code that I have provided or talked about in this post can be downloaded as a vRO package for your consumption here.

I have also included a number of workflows in the package, which provide examples of these actions being used.

You can find these under ‘Simplygeek -> Library -> Common Workflows -> vRealize Automation -> Examples -> Reservations

Get Reserved Storage Information

The following sections provide vRO Actions that can be used to get information about storage that has been reserved in a reservation or get details of physical capacity.

Get Storage Reserved Capacity for a Reservation

The following action accepts a storage path and the reservation entity and will return the total amount of storage that has been reserved for the reservation.

/*global System vcacHost reservationEntity storagePath*/

/**
 * Gets the reserved storage capacity total for the storage path in the reservation.
 * @author Gavin Stephens <gavin.stephens@simplygeek.co.uk>
 * @version 1.0.0
 * @function getReservedStorageCapacityTotalForReservation
 * @param {vCAC:VCACHOST} vcacHost - The vCAC Host.
 * @param {vCAC:Entity} reservationEntity - The vCAC reservation entity.
 * @param {string} storagePath - The storage path.
 * @returns {number} Returns the reserved storage capacity in GB.
 */

function checkParams(vcacHost, reservationEntity, storagePath) {
    var inputErrors = [];
    var errorMessage;

    if (!vcacHost || System.getObjectType(vcacHost) !== "vCAC:VCACHost") {
        inputErrors.push(" - vcacHost missing or not of type 'vCAC:VCACHost'");
    }
    if (!reservationEntity || System.getObjectType(reservationEntity) !== "vCAC:Entity") {
        inputErrors.push(" - reservationEntity missing or not of type 'vCAC:Entity'");
    }
    if (!storagePath || typeof storagePath !== "string") {
        inputErrors.push(" - storagePath missing or not of type 'string'");
    }
    if (inputErrors.length > 0) {
        errorMessage = "Mandatory parameters not satisfied:\n" + inputErrors.join("\n");
        log.error(errorMessage);
    }
}

var logType = "Action";
var logName = "getReservedStorageCapacityTotalForReservation"; // This must be set to the name of the action
var Logger = System.getModule("com.simplygeek.library.util").logger(logType, logName);
var log = new Logger(logType, logName);
var reservedCapacityGB = 0;
var reservationName = "";
var hostReservationToStorages = [];
var resStoragePaths = [];
var query = "";
var entitySetName = "HostReservationToStorages";
var storageEntities = [];

try {
    checkParams(vcacHost, reservationEntity, storagePath);
    reservationName = reservationEntity.getProperty("HostReservationName");
    log.log("Getting reserved storage capacity total for '" + storagePath + "' in reservation '" + reservationName + "'");
    hostReservationToStorages = reservationEntity.getLink(vcacHost, "HostReservationToStorages");
    resStoragePaths = hostReservationToStorages.map(function(x){return x.getLink(vcacHost, "HostToStorage")[0].getProperty("StoragePath");});
    if (resStoragePaths.indexOf(storagePath) !== -1) {
        query = "HostToStorage/StoragePath eq '" + storagePath + "'";
        storageEntities = System.getModule("com.simplygeek.library.vcac.entities").getVcacEntitiesBySystemQuery(vcacHost,
                                                                                                                entitySetName,
                                                                                                                query);
        reservedCapacityGB = storageEntities[0].getProperty("MaxCapacity");
    } else {
        log.error("Storage path '" + storagePath + "' not found in reservation '" + reservationName + "'");
    }
    log.log("Reserved storage capacity total: " + reservedCapacityGB + " GB");
} catch (e) {
    log.error("Action failed to get reserved storage capacity total for vcac reservation.",e);
}

return reservedCapacityGB;

Log output:

[] [I] [Action: getReservedCapacityForStorageReservation] Getting reserved storage capacity for 'DSC-SITEA-BRONZE-01' in reservation 'RES-SITEA-vSphere-Resource-01'
[] [I] [Action: getReservedCapacityForStorageReservation] Storage capacity reserved total: 200

Get Storage Reserved Capacity Used for a Reservation

The following action accepts a storage path and the reservation entity and will return the amount of reserved storage capacity that has been used for the reservation.

/*global System vcacHost reservationEntity storagePath*/

/**
 * Gets the reserved storage capacity used for the storage path in the reservation.
 * @author Gavin Stephens <gavin.stephens@simplygeek.co.uk>
 * @version 1.0.0
 * @function getReservedStorageCapacityUsedForReservation
 * @param {vCAC:VCACHOST} vcacHost - The vCAC Host.
 * @param {vCAC:Entity} reservationEntity - The vCAC reservation entity.
 * @param {string} storagePath - The storage path.
 * @returns {number} Returns the reserved storage capacity used in GB.
 */

function checkParams(vcacHost, reservationEntity, storagePath) {
    var inputErrors = [];
    var errorMessage;

    if (!vcacHost || System.getObjectType(vcacHost) !== "vCAC:VCACHost") {
        inputErrors.push(" - vcacHost missing or not of type 'vCAC:VCACHost'");
    }
    if (!reservationEntity || System.getObjectType(reservationEntity) !== "vCAC:Entity") {
        inputErrors.push(" - reservationEntity missing or not of type 'vCAC:Entity'");
    }
    if (!storagePath || typeof storagePath !== "string") {
        inputErrors.push(" - storagePath missing or not of type 'string'");
    }
    if (inputErrors.length > 0) {
        errorMessage = "Mandatory parameters not satisfied:\n" + inputErrors.join("\n");
        log.error(errorMessage);
    }
}

var logType = "Action";
var logName = "getReservedStorageCapacityUsedForReservation"; // This must be set to the name of the action
var Logger = System.getModule("com.simplygeek.library.util").logger(logType, logName);
var log = new Logger(logType, logName);
var reservedCapacityUsedGB = 0;
var reservationName = "";
var reservationId = "";
var hostReservationToStorages = [];
var hostReservationToStorage;
var resStoragePaths = [];
var query = "";
var entitySetName = "HostReservationToStorageStats";
var storageStatsEntities = [];
var hostToStorageId = "";

try {
    checkParams(vcacHost, reservationEntity, storagePath);
    reservationName = reservationEntity.getProperty("HostReservationName");
    reservationId = reservationEntity.getProperty("HostReservationID");
    log.log("Getting reserved storage capacity used for '" + storagePath + "' in reservation '" + reservationName + "'");
    hostReservationToStorages = reservationEntity.getLink(vcacHost, "HostReservationToStorages");
    resStoragePaths = hostReservationToStorages.map(function(x){return x.getLink(vcacHost,
                                                                                 "HostToStorage")[0].getProperty("StoragePath");});
    if (resStoragePaths.indexOf(storagePath) !== -1) {
        hostReservationToStorage = hostReservationToStorages.filter(function(x){return x.getLink(vcacHost,
                                                                                                 "HostToStorage")[0].getProperty("StoragePath") === storagePath;});
        hostToStorageId = hostReservationToStorage[0].getLink(vcacHost, "HostToStorage")[0].getProperty("HostToStorageID");
        query = "HostReservationID eq guid'" + reservationId + "' and HostToStorageID eq guid'" + hostToStorageId + "'";
        storageStatsEntities = System.getModule("com.simplygeek.library.vcac.entities").getVcacEntitiesBySystemQuery(vcacHost,
                                                                                                                     entitySetName,
                                                                                                                     query);
        reservedCapacityUsedGB = storageStatsEntities[0].getProperty("StorageAllocated");
    } else {
        log.error("Storage path '" + storagePath + "' not found in reservation '" + reservationName + "'");
    }

    log.log("Reserved storage capacity used: " + reservedCapacityUsedGB + " GB");
} catch (e) {
    log.error("Action failed to get reserved storage capacity used for vcac reservation.",e);
}

return reservedCapacityUsedGB;

Log output:

[] [I] [Action: getStorageReservedCapacityUsedForReservation] Getting reserved storage capacity used for 'DSC-SITEA-BRONZE-01' in reservation 'RES-SITEA-vSphere-Resource-01'
[] [I] [Action: getStorageReservedCapacityUsedForReservation] Reserved storage capacity used: 21

Get Total Physical Storage Capacity

The following action accepts a storage path and the reservation entity and will return the total amount of physical storage available.

/*global System vcacHost reservationEntity storagePath*/

/**
 * Gets the total physical storage capacity for the storage path in the reservation.
 * @author Gavin Stephens <gavin.stephens@simplygeek.co.uk>
 * @version 1.0.0
 * @function getPhysicalStorageCapacityTotalForReservation
 * @param {vCAC:VCACHOST} vcacHost - The vCAC Host.
 * @param {vCAC:Entity} reservationEntity - The vCAC reservation entity.
 * @param {string} storagePath - The storage path.
 * @returns {number} Returns the total physical storage capacity in GB.
 */

function checkParams(vcacHost, reservationEntity, storagePath) {
    var inputErrors = [];
    var errorMessage;

    if (!vcacHost || System.getObjectType(vcacHost) !== "vCAC:VCACHost") {
        inputErrors.push(" - vcacHost missing or not of type 'vCAC:VCACHost'");
    }
    if (!reservationEntity || System.getObjectType(reservationEntity) !== "vCAC:Entity") {
        inputErrors.push(" - reservationEntity missing or not of type 'vCAC:Entity'");
    }
    if (!storagePath || typeof storagePath !== "string") {
        inputErrors.push(" - storagePath missing or not of type 'string'");
    }
    if (inputErrors.length > 0) {
        errorMessage = "Mandatory parameters not satisfied:\n" + inputErrors.join("\n");
        log.error(errorMessage);
    }
}

var logType = "Action";
var logName = "getPhysicalStorageCapacityTotalForReservation"; // This must be set to the name of the action
var Logger = System.getModule("com.simplygeek.library.util").logger(logType, logName);
var log = new Logger(logType, logName);
var totalPhysicalCapacityGB = 0;
var reservationName = "";
var hostReservationToStorages = [];
var resStoragePaths = [];
var query = "";
var entitySetName = "Storage";
var storageEntities = [];

try {
    checkParams(vcacHost, reservationEntity, storagePath);
    reservationName = reservationEntity.getProperty("HostReservationName");
    log.log("Getting total physical storage capacity for '" + storagePath + "' in reservation '" + reservationName + "'");
    hostReservationToStorages = reservationEntity.getLink(vcacHost, "HostReservationToStorages");
    resStoragePaths = hostReservationToStorages.map(function(x){return x.getLink(vcacHost, "HostToStorage")[0].getProperty("StoragePath");});
    if (resStoragePaths.indexOf(storagePath) !== -1) {
        query = "StorageName eq '" + storagePath + "'";
        storageEntities = System.getModule("com.simplygeek.library.vcac.entities").getVcacEntitiesBySystemQuery(vcacHost,
                                                                                                                entitySetName,
                                                                                                                query);
        totalPhysicalCapacityGB = storageEntities[0].getProperty("StorageTotalCapacityGB");
    } else {
        log.error("Storage path '" + storagePath + "' not found in reservation '" + reservationName + "'");
    }
    log.log("Total physical storage capacity: " + totalPhysicalCapacityGB + " GB");
} catch (e) {
    log.error("Action failed to get total physical storage capacity for vcac reservation.",e);
}

return totalPhysicalCapacityGB;

Log output:

[] [I] [Action: getPhysicalStorageCapacityTotalForReservation] Getting total physical storage capacity for 'DSC-SITEA-BRONZE-01' in reservation 'RES-SITEA-vSphere-Resource-01'
[] [I] [Action: getPhysicalStorageCapacityTotalForReservation] Total physical storage capacity: 200 GB

Get Free Physical Storage Capacity

The following action accepts a storage path and the reservation entity and will return the amount of free physical storage available. This is useful if reservations are heavily oversubscribed making it difficult to determine if the physical layer has free storage available.

/*global System vcacHost reservationEntity storagePath*/

/**
 * Gets the free physical storage capacity for the storage path in the reservation.
 * @author Gavin Stephens <gavin.stephens@simplygeek.co.uk>
 * @version 1.0.0
 * @function getPhysicalStorageCapacityFreeForReservation
 * @param {vCAC:VCACHOST} vcacHost - The vCAC Host.
 * @param {vCAC:Entity} reservationEntity - The vCAC reservation entity.
 * @param {string} storagePath - The storage path.
 * @returns {number} Returns the free physical storage capacity in GB.
 */

function checkParams(vcacHost, reservationEntity, storagePath) {
    var inputErrors = [];
    var errorMessage;

    if (!vcacHost || System.getObjectType(vcacHost) !== "vCAC:VCACHost") {
        inputErrors.push(" - vcacHost missing or not of type 'vCAC:VCACHost'");
    }
    if (!reservationEntity || System.getObjectType(reservationEntity) !== "vCAC:Entity") {
        inputErrors.push(" - reservationEntity missing or not of type 'vCAC:Entity'");
    }
    if (!storagePath || typeof storagePath !== "string") {
        inputErrors.push(" - storagePath missing or not of type 'string'");
    }
    if (inputErrors.length > 0) {
        errorMessage = "Mandatory parameters not satisfied:\n" + inputErrors.join("\n");
        log.error(errorMessage);
    }
}

var logType = "Action";
var logName = "getPhysicalStorageCapacityFreeForReservation"; // This must be set to the name of the action
var Logger = System.getModule("com.simplygeek.library.util").logger(logType, logName);
var log = new Logger(logType, logName);
var freePhysicalCapacityGB = 0;
var reservationName = "";
var hostReservationToStorages = [];
var resStoragePaths = [];
var query = "";
var entitySetName = "Storage";
var storageEntities = [];

try {
    checkParams(vcacHost, reservationEntity, storagePath);
    reservationName = reservationEntity.getProperty("HostReservationName");
    log.log("Getting free physical storage capacity for '" + storagePath + "' in reservation '" + reservationName + "'");
    hostReservationToStorages = reservationEntity.getLink(vcacHost, "HostReservationToStorages");
    resStoragePaths = hostReservationToStorages.map(function(x){return x.getLink(vcacHost, "HostToStorage")[0].getProperty("StoragePath");});
    if (resStoragePaths.indexOf(storagePath) !== -1) {
        query = "StorageName eq '" + storagePath + "'";
        storageEntities = System.getModule("com.simplygeek.library.vcac.entities").getVcacEntitiesBySystemQuery(vcacHost,
                                                                                                                entitySetName,
                                                                                                                query);
        freePhysicalCapacityGB = storageEntities[0].getProperty("StorageFreeCapacityGB");
    } else {
        log.error("Storage path '" + storagePath + "' not found in reservation '" + reservationName + "'");
    }
    log.log("Free physical storage capacity: " + freePhysicalCapacityGB + " GB");
} catch (e) {
    log.error("Action failed to get free physical storage capacity for vcac reservation.",e);
}

return freePhysicalCapacityGB;

Log output:

[Action: getPhysicalStorageCapacityFreeForReservation] Getting free physical storage capacity for 'DSC-SITEA-BRONZE-01' in reservation 'RES-SITEA-vSphere-Resource-01'
[] [I] [Action: getPhysicalStorageCapacityFreeForReservation] Free physical storage capacity: 196 GB

Update Reserved Storage for a Reservation

The following code will allow you to change the amount of storage that has been reserved in a reservation, for a given storage path/datastore.

/*global System vcacHost reservationEntity storagePath newReservedCapacity*/

/**
 * Updates the reserved storage capacity for the storage path in the reservation.
 * @author Gavin Stephens <gavin.stephens@simplygeek.co.uk>
 * @version 1.0.0
 * @function updateReservedStorageCapacityForReservation
 * @param {vCAC:VCACHOST} vcacHost - The vCAC Host.
 * @param {vCAC:Entity} reservationEntity - The vCAC reservation entity.
 * @param {string} storagePath - The storage path.
 * @param {number} newReservedCapacity - The amount of storage to reserve.
 */

function checkParams(vcacHost, reservationEntity, storagePath, newReservedCapacity) {
    var inputErrors = [];
    var errorMessage;

    if (!vcacHost || System.getObjectType(vcacHost) !== "vCAC:VCACHost") {
        inputErrors.push(" - vcacHost missing or not of type 'vCAC:VCACHost'");
    }
    if (!reservationEntity || System.getObjectType(reservationEntity) !== "vCAC:Entity") {
        inputErrors.push(" - reservationEntity missing or not of type 'vCAC:Entity'");
    }
    if (!storagePath || typeof storagePath !== "string") {
        inputErrors.push(" - storagePath missing or not of type 'string'");
    }
    if (typeof newReservedCapacity !== "number") {
        inputErrors.push(" - newReservedCapacity missing or not of type 'number'");
    }
    if (inputErrors.length > 0) {
        errorMessage = "Mandatory parameters not satisfied:\n" + inputErrors.join("\n");
        log.error(errorMessage);
    }
}

var logType = "Action";
var logName = "updateReservedStorageCapacityForReservation"; // This must be set to the name of the action
var Logger = System.getModule("com.simplygeek.library.util").logger(logType, logName);
var log = new Logger(logType, logName);
var currentReservedCapacity = 0;
var propertyToUpdate = "MaxCapacity";
var reservationName = "";
var storageReservationViewEntities = [];
var query = "";
var entitySetName = "HostReservationToStorages";

try {
    checkParams(vcacHost, reservationEntity, storagePath, newReservedCapacity);
    reservationName = reservationEntity.getProperty("HostReservationName");
    log.log("Updating reserved storage capacity for '" + storagePath + "' in reservation '" +
            reservationName + "' to " + newReservedCapacity + " GB.");
    currentReservedCapacity = System.getModule("com.simplygeek.library.vcac.reservations.storage").getReservedStorageCapacityTotalForReservation(vcacHost,
                                                                                                                                                 reservationEntity,
                                                                                                                                                 storagePath);
    if (newReservedCapacity < 0) {
        log.error("Cannot set reserved storage capacity to a value less than 0.");
    } else if (newReservedCapacity === currentReservedCapacity) {
        log.log("Current reserved storage capacity is already set to " + newReservedCapacity + " GB.");
    } else {
        query = "HostToStorage/StoragePath eq '" + storagePath + "'";
        storageReservationViewEntities = System.getModule("com.simplygeek.library.vcac.entities").getVcacEntitiesBySystemQuery(vcacHost,
                                                                                                                               entitySetName,
                                                                                                                               query);
        System.getModule("com.simplygeek.library.vcac.entities").updatePropertyValueForVcacEntity(storageReservationViewEntities[0],
                                                                                                  propertyToUpdate,
                                                                                                  newReservedCapacity);
        log.log("Successfully updated reserved storage capacity to " + newReservedCapacity + " GB.");
    }
} catch (e) {
    log.error("Action failed to update reserved storage capacity for vcac reservation.",e);
}

Log output:

[] [I] [Action: updateReservedStorageCapacityForReservation] Updating reserved storage capacity for 'DSC-SITEA-BRONZE-01' in reservation 'RES-SITEA-vSphere-Resource-01' to 205 GB.
[] [I] [Action: getReservedStorageCapacityTotalForReservation] Getting reserved storage capacity total for 'DSC-SITEA-BRONZE-01' in reservation 'RES-SITEA-vSphere-Resource-01'
[] [I] [Action: getReservedStorageCapacityTotalForReservation] Reserved storage capacity total: 200 GB
[] [I] [Action: updateReservedStorageCapacityForReservation] Successfully updated reserved storage capacity to 205 GB.

This action won’t attempt to update the reservation if the value being set is the same as what is currently configured and will display this output in the log:

[] [I] [Action: updateReservedStorageCapacityForReservation] Current reserved storage capacity is already set to 205 GB.

That concludes this section on vcac reservations. In my next post I am going to focus on compute resource and storage entities.

I hope this has been useful. If you discover bugs with any of my code, require some help or simply need an ad-hoc solution, then please drop me a message via the Drift app.

Please rate this post!

Average rating / 5. Vote count:

Leave a Reply

avatar
  Subscribe  
Notify of