Attribute Inheritance in CI Classes

General Add comments
by:

Sometimes it is important to understand the impact of a CI in the big service delivery picture. In such a case you could investigate all CI´s that are affected by this CI, but it is also possible to summarize this impact into a number of attributes, such as SoX relevance and Security Level.

In this article I will show a relatively simple concept of making sure that these attributes are inherited and calculated from the parents to their children (and in turn to their children… etc).

The setup used in this example is as follows:

  • A customer has several Applications in his CMDB.
  • Each of these applications has a number of instances (for instance Production, Development, etc).
  • Each of these Application Instances is supported by one or more Servers.
  • Each Server supports one or more Application Instances.
  • Each Server also resides in one Data Center.

The goal of this exercise is to make sure that – at any time – you know if a certain Server or Data Center is supporting a SoX compliant Application Instance and what the maximum Security Level (0, 1, 2, 3, 4 or 5) of the supported Application Instances is.

The logic to accomplish this basically consists of three (3) notification rules and a calculation.

  • Notification 1: If a relationship is created, the inherited values of any child affected should be recalculated
  • Notification 2: If a relationship is removed, the inherited values of any child affected should be recalculated
  • Notification 3: If any inherited values of a CI are updated, the Children of the CI should recalculate their values
  • Calculation: If a CI is updated, values of the CI itself should be recalculated (this can be limited to “if any relevant fields of the CI are updated”)

Example

Imagine the following setup:

  • Application Instance 1: API001
  • Application Instance 2: API002
  • Server 1: SRV001
  • Server 2: SRV002
  • Server 3: SRV003
  • Data Center 1: DC001

Now let´s assume the following relationship setup:
 

 

The idea is that the inheritance mechanism makes sure that a CI always contains the highest value of all CI´s that are it´s parents (or parent´s parents, etc.). In this example this means that the high values (True for SoX and 4 for Security Level) are set in each CI that is used to support them.

Setup

The next pages contain the code and the setup that can be used to implement this feature.

To test with the exact same code as below, do the following:

  • Create a table called u_application_instance, extending cmdb_ci
  • On cmdb_ci, add the following fields:
    • u_inheritance_steps: Integer
    • u_sox: boolean
    • u_sec_level: choice (choices: 0, 1, 2, 3, 4 and 5)

Create and activate three business rules, add an Event to the registry and create a Script Action.

How this is done is described on the following pages.

Business Rule 1: Inheritance: Calculate values

 

//****<<80 characters long>>******************************************************************
// Name = Inheritance: Calculate Values
// Author = Martijn Odijk
// Date =
// Input = n/a
// Output = n/a
//
// This business rule is part of 3 business rules:
// * Inheritance: Calculate Values
// * Inheritance: Notify on CI
// * Inheritance: Notify on Relationship
//
// Some attributes of CI´s should be inherited by it´s children.
// Setup is that Applications are left out of this logic,
// but that Instances of an application –such as Production or Development-
// get values that are inherited by databases and servers that are used to
// support them.
// These instances are store in the table u_application_instance
//****<<80 characters long>>******************************************************************

 // MODIFICATIONS NEEDED FOR EXTRA INHERITED FIELDS (1 / 5):
// Overview: list of inherited fields >>
// u_sec_level: array, ‘5’=max
// u_sox: boolean, true=max
// END MODIFICATIONS (1 / 5)

 var grUpRelations;
var grParents;
var varParentID;
var varUpdates;

 // MODIFICATIONS NEEDED FOR EXTRA INHERITED FIELDS (2 / 5):
// initialize the inherited fields and set them to the minimal values.
var max_u_sec_level =’0′;
var max_u_sox=false;

 var temp_u_sec_level;
var temp_u_sox;

 // How to define an array. The order is used. First value is Highest.
var arr_u_sec_level = new Array(‘5′,’4′,’3′,’2′,’1′,’0’);
var arr_u_sec_level_max;
var arr_u_sec_level_temp;
// END MODIFICATIONS (2 / 5)

 // Get all parents
grUpRelations = new GlideRecord(‘cmdb_rel_ci’);
grUpRelations.addQuery(‘child’,current.sys_id);
grUpRelations.query();

 // check if there are any parents. If yes: update all the inherited fields
// on the current record, unless the CI is an application or applicatoin instance
if(grUpRelations.hasNext() && current.sys_class_name != ‘u_application_instance’ && current.sys_class_name != ‘cmdb_ci_appl’){

  while(grUpRelations.next()) {
// loop trough all parents
varParentID = grUpRelations.getValue(‘parent’);
grParents= new GlideRecord(‘cmdb_ci’);
grParents.addQuery(‘sys_id’,varParentID);
grParents.query();
// Apply the filter. You will find only one CI as parent of each relation
while(grParents.next()) {
// Go to the record and fetch the values
// MODIFICATIONS NEEDED FOR EXTRA INHERITED FIELDS (3 / 5):
// Determine the highest value for each inherited field by comparing
         // them to the previously found highest value

  temp_u_sox= grParents.getValue(‘u_sox’);
if(temp_u_sox==true){
         // Update the newly found maximum value
            max_u_sox = true;
        }

  // Loop through any Array and find the matching values for max and temp:
temp_u_sec_level = grParents.getValue(‘u_sec_level’);
for(var i=0;i<arr_u_sec_level.length;i++) {
if(max_u_sec_level==arr_u_sec_level[i]){ arr_u_sec_level_max=i; }
if(temp_u_sec_level==arr_u_sec_level[i]){ arr_u_sec_level_temp=i; }
}
if(arr_u_sec_level_temp < arr_u_sec_level_max){
         // Update the newly found maximum value
            max_u_sec_level = temp_u_sec_level;
        }
// END MODIFICATIONS (3 / 5)
}
}

  // MODIFICATIONS NEEDED FOR EXTRA INHERITED FIELDS (4 / 5):
// Set the values on the CI to the maximum values found
current.u_sox=max_u_sox;
current.u_sec_level=max_u_sec_level;
// END MODIFICATIONS (4 / 5)}

 }

  if(current.sys_class_name == ‘u_application_instance’){
    // If we´re dealing with an application instance,
    // the u_inheritance_steps must be initialized.
    current.u_inheritance_steps=1;
    }
    
      // MODIFICATIONS NEEDED FOR EXTRA INHERITED FIELDS (5 / 5):
if(!current.u_sec_level.changes() && !current.u_sox.changes()){
// END MODIFICATIONS (5 / 5)

     // Check if any fields have been updated.
    // If this is not the case, set the u_inherited_steps to 0,
    // so the children will not be triggered to recalculate.
    current.u_inheritance_steps=0;
    // else, do nothing; The inheritance value has been set by the parents
}

Business Rule 2: Inheritance: Notify on CI

 

 

 

//****<<80 characters long>>******************************************************************
// Name: Inheritance: Notify on CI
// Author = Martijn Odijk
// Date =
// Input = n/a
// Output = n/a
//
// This business rule is part of 3 business rules:
// * Inheritance: Calculate Values
// * Inheritance: Notify on CI
// * Inheritance: Notify on Relationship
//
// check if the field u_inheritance_step has been updated.
// If not, it should be set to 1: a new inheritance flow is triggered.
// notify the children to refresh their inherited values
// set the counter: no more then 20 steps should be needed
// (otherwise we’re in a loop, so we should break)
//****<<80 characters long>>******************************************************************

 var grDownRelations;
var grChildren;
var varChildID;
var intInheritanceStep;
var grWhere;
intInheritanceStep = current.u_inheritance_steps + 1;
// If the inheritance value is 0, then no fields were updated according
// to the “Inheritance: Calculate Values” business rule
if(intInheritanceStep<=20 && intInheritanceStep>=2){
// if no inheritance fields have been updated, the “Inheritance: Calculate Values”
// business rule has set the value of u_inheritance_steps to 0, which means no inheritance
// values were changed. Otherwise it has been set to 1 (or more)
// this check makes sure that there are 2 ways to end the flow:
// either run into the 20 steps, (preventing loops in CI Relations)
// or stop updating inheriting fields because it is not needed anymore.
grDownRelations = new GlideRecord(‘cmdb_rel_ci’);
grDownRelations.addQuery(‘parent’,current.sys_id);
grDownRelations.query();
grChildren = new GlideRecord(‘cmdb_ci’);
grWhere = grChildren.addQuery(‘sys_id’, ”);
while(grDownRelations.next()) {
// loop through all the relationships pointing to children.
// add all the children to an OR statement
// The GlideRecord.update() command for grChildren only seems to work,
     // if you create a new GlideRecord for each child you find.
varChildID= grDownRelations.getValue(‘child’);
grWhere.addOrCondition(‘sys_id’,varChildID);
}
grChildren.query();
// Inform the children that they should update.
updateChild(grChildren,intInheritanceStep);
}

 // For additional security, the occasional double update, to prevent updates from being run in the same session, and to be sure that we do not create an endless loop, a script action is used to perform the actual update, and set the steps to 0 of the current CI.
gs.eventQueue(‘update.current.ci.inheritance’, current, gs.getUserID(), gs.getUserName());

 function updateChild(gr,intStep){
while(gr.next()) {
// Update the u_inheritance_steps field in the child.
     // This triggers the recalculation of the child.
gr.setValue(‘u_inheritance_steps’, intStep);
gr.update();
}
}

Business Rule 3: Inheritance: Notify on Relationship

 

 

//****<<80 characters long>>******************************************************************
// Name: Inheritance: Notify on Relationship
// Author = Martijn Odijk
// Date =
// Input = n/a
// Output = n/a
//
// This business rule is part of 3 business rules:
// * Inheritance: Calculate Values
// * Inheritance: Notify on CI
// * Inheritance: Notify on Relationship
//
// After the deletion or insertion of a CI Relationship,
// The child should refresh its Inherited values.
//****<<80 characters long>>******************************************************************

 var grChildren;
grChildren= new GlideRecord(‘cmdb_ci’);
grChildren.addQuery (‘sys_id’,current.child);
grChildren.query();
// Apply the filter. You will find only one CI is connected to this relation
while(grChildren.next()) {
// Update the u_inheritance_steps field in the child.
// it will always be the first step in a line of updates, so set it to 1.
// This will automatically trigger the recalculation of the CI.
grChildren.setValue(‘u_inheritance_steps’, 1);
grChildren.update();
}

Registry: update.current.ci.inheritance

Register the event that you call in the Notify on CI business rule:

 

Script Action: Update Inheritance of CI

 

current.u_inheritance_steps = 0;

current.update();

 

Please don’t hesitate to contact me if you have any questions. You can reach me via email on: martijn.odijk@2e2.nl.

Leave a Reply