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!