Join the #BuildWithBuildAgent Challenge! Get recognized, earn exclusive swag, and inspire the ServiceNow Community with what you can build using Build Agent.  Join the Challenge.

Calculated value for CMDB for rack units occupied.

Piemur1
Tera Contributor

Hello, I wanted to set up an automatic calculation for how many rack units are occupying a rack. I've created a field entry for the devices with the expectation that they will have a value for how many rack units they will occupy (such as servers and any other devices that could be installed within a rack such as switches, routers, PSUs, etc). And then the plan would be for using the CI Relationship "contains::contained by" to pull the items within the rack and then sum up the rack units and display for the "Rack units in use" field on a given Rack. Currently I have the field on the Servers table (cmdb_ci_servers) and planning on adding the field to more later as we identify what items will be tracked in the Racks. I presume I will be using the Script type rather than Formula.

1 ACCEPTED SOLUTION

HIROSHI SATOH
Mega Sage

Instead of creating a new GlideRecord, you can directly access the child CI like this:

// Initialize the sum
var totalRackUnits = 0;

// Get the list of CIs contained by the rack
var grContainment = new GlideRecord('cmdb_rel_ci');
grContainment.addQuery('parent', current.sys_id);  // Assuming current is the Rack CI
grContainment.addQuery('type.name', 'contains::contained by');
grContainment.query();

while (grContainment.next()) {
    if (grContainment.child) {  // Directly check if the child CI exists
        totalRackUnits += parseInt(grContainment.child.u_rack_units || 0);  // Access the rack units field from child CI
    }
}

// Update the rack's "Rack units in use" field
current.u_rack_units_in_use = totalRackUnits;

View solution in original post

5 REPLIES 5

HIROSHI SATOH
Mega Sage

Understanding the Problem:

You're trying to automatically calculate the total rack units occupied by devices within a rack. You have a field on the cmdb_ci_servers table to capture the rack units occupied by servers. You plan to extend this to other device types and use CI Relationships to sum the values.

Proposed Solution:

  • Create a Custom Calculated Field:

    • On the cmdb_ci_rack table, create a calculated field named rack_units_in_use.
    • Set the data type to integer.
    • Select "Script" as the calculation type.
  • Write the Script:

 

// Initialize the sum
var totalRackUnits = 0;

// Get the list of CIs contained by the rack
var grContainment = new GlideRecord('cmdb_rel_ci');
grContainment.addQuery('parent', current.sys_id);  // Assuming current is the Rack CI
grContainment.addQuery('type.name', 'contains::contained by');
grContainment.query();

while (grContainment.next()) {
    var childCI = new GlideRecord(grContainment.child.cmdb_ci);
    if (childCI.get(grContainment.child.sys_id)) {
        totalRackUnits += parseInt(childCI.u_rack_units || 0);  // Assuming u_rack_units is the field name
    }
}

// Update the rack's "Rack units in use" field
current.u_rack_units_in_use = totalRackUnits;

 

 

 

  • Explanation:

    • The script queries the cmdb_ci_rack_device table for devices contained within the current rack.
    • It iterates through each device, retrieves the corresponding cmdb_ci_server record, and adds the rack_units value to the total.
    • Finally, it sets the calculated field rack_units_in_use on the current rack record.

Additional Considerations:

  • Device Types: Ensure that the script handles other device types besides servers by adjusting the device.get(gr.device) line.
  • Performance: For large numbers of devices, consider optimizing the query and calculations to improve performance.
  • Data Integrity: Implement validation rules to ensure that rack_units values are valid integers.

I think this is the solution, however I'm having trouble getting a result from it. Is the following line supposed to be a new gliderecord for cmdb_ci?

 

var childCI = new GlideRecord(grContainment.child.cmdb_ci);

 

Any test records I have that contains a server that has a u_rack_unit value, it returns with a null value, not even an Int. It might even give a null value for servers that DON'T have a u_rack_unit value, haven't had an opportunity to test that yet...But it seems like it is getting stuck in the while loop, and doesn't exit, therefore it never returns a proper value.

I have determined that the error occurs somewhere within this if statement:

 

 

if (childCI.get(grContainment.child.sys_id)) 

 

It never reaches within the if statement.

Piemur1
Tera Contributor
Performed some troubleshooting with @HIROSHI SATOH and came up with the following as the final solution:
 
// Initialize the sum
    var totalRackUnits = 0;

    // Get the list of CIs contained by the rack
    var grContainment = new GlideRecord('cmdb_rel_ci');
    grContainment.addQuery('parent', current.sys_id); // Assuming current is the Rack CI
    grContainment.addQuery('type.name', 'contains::contained by');
    grContainment.query();

    while (grContainment.next()) {
        if (grContainment.child) { // Directly check if the child CI exists
            totalRackUnits += parseInt(grContainment.child.u_rack_units || 0); // Access the rack units field from child CI
        }
    }

    // Update the rack's "Rack units in use" field
    current.u_rack_units_in_use = totalRackUnits;
 
Again much appreciation for Mr. Satoh for the assistance!