Notifications

63 views

Issue

Symptoms

While inserting a Computer/Server CI in the CMDB, either manually, via a Discovery tool, or some other import, you may see errors at the SQL level related to failure to insert the CI because it is already inserted. Other code running as part of the insert, or in reaction to the insert, may not work as expected.

e.g. 

FAILED TRYING TO EXECUTE ON CONNECTION nn: INSERT INTO cmdb (`a_str_5`, `a_int_8`, `skip_sync`, `operational_status....
java.sql.BatchUpdateException: Duplicate entry '7caaf9c31b9dff846825a64fad4bcb6a' for key 'PRIMARY' 
: java.sql.SQLException: java.sql.BatchUpdateException: Duplicate entry '7caaf9c31b9dff846825a64fad4bcb6a' for key 'PRIMARY': com.glide.db.StatementBatcher.getSQLException(StatementBatcher.java:469)

Release

All recent versions up to at least Madrid.

Environment

Any instance with Discovery or Service Mapping installed.

Cause

There is probably a custom business rule running for insert of CI relationships, that makes an update to the parent CI before it exists. This causes a premature insert, after which anything else running as part of the transaction will probably behave in various spectacularly unexpected ways. Let me explain:

  • If the CI being inserted is a Computer [cmdb_ci_computer], or Server or some other class that extends Computer, then the out-of-box business rule "Virtual Computer Check" will run.
  • This runs before insert of the Computer CI, because the "IsVirtual" flag needs adding before insert.
  • If this finds a VM instance record, it known the CI is Virtual, and also create an "instantiates" relationship between VM and Instance. A Relationship record is inserted.
  • All insert Business Rules for a Relationship record [cmdb_rel_ci] will run as the Relationship record is inserted.
  • If the custom business rule makes an .update() to the parent of the relationship, causing a premature insert because the computer CI hasn't inserted yet.
  • The remaining Relationship insert business rules complete.
  • The remaining before insert Computer CI business rules complete.
  • Now the actual Computer CI insert should happen, but it errors because the sys_id was inserted already.

Resolution

You cannot assume that both parent and child CIs exist at the point that the Relationship record is inserted. "Virtual Computer Check" is just one example of code that may insert he relationship before the CI, and there are probably others.

You need to avoid causing a premature insert, as other out-of-box code cannot cope in this situation.

Your custom implementation needs redesigning, so that it takes these facts into account.

Additional Information

It has always been the platform behavior that a get for a nonexistent record will initialize a new GlideRecord. The same applies when dot walking reference fields in scripts to get the object of the referenced record, as in this case. Any subsequent update to that will cause an insert.

That insert behaviour is documented in the GlideRecord documentation, under update(): "Updates the GlideRecord with any changes that have been made. If the record does not exist, it is inserted."

Article Information

Last Updated:2019-08-02 20:43:27
Published:2019-05-13