diff --git a/dictionaries/dictionary.itop.core.php b/dictionaries/dictionary.itop.core.php
index dddbfb3f4..d53457694 100644
--- a/dictionaries/dictionary.itop.core.php
+++ b/dictionaries/dictionary.itop.core.php
@@ -525,6 +525,7 @@ Dict::Add('EN US', 'English', 'English', array(
'Core:Synchro:label_obj_deleted' => 'Deleted (%1$s)',
'Core:Synchro:label_obj_obsoleted' => 'Obsoleted (%1$s)',
'Core:Synchro:label_obj_disappeared_errors' => 'Errors (%1$s)',
+ 'Core:Synchro:label_obj_disappeared_no_action' => 'No Action (%1$s)',
'Core:Synchro:label_obj_unchanged' => 'Unchanged (%1$s)',
'Core:Synchro:label_obj_updated' => 'Updated (%1$s)',
'Core:Synchro:label_obj_updated_errors' => 'Errors (%1$s)',
@@ -534,7 +535,7 @@ Dict::Add('EN US', 'English', 'English', array(
'Core:Synchro:label_obj_new_errors' => 'Errors (%1$s)',
'Core:Synchro:History' => 'Synchronization History',
'Core:SynchroLogTitle' => '%1$s - %2$s',
- 'Core:Synchro:Nb_Replica' => 'Replica: %1$s',
+ 'Core:Synchro:Nb_Replica' => 'Replica processed: %1$s',
'Core:Synchro:Nb_Class:Objects' => '%1$s: %2$s',
));
?>
diff --git a/synchro/synchro_exec.php b/synchro/synchro_exec.php
index 3d4c67520..80a39b2a0 100644
--- a/synchro/synchro_exec.php
+++ b/synchro/synchro_exec.php
@@ -136,7 +136,7 @@ foreach(explode(',', $sDataSourcesList) as $iSDS)
}
foreach ($aResults as $sMessage)
{
- $oP->p($sMessage);
+ $oP->p('#'.$sMessage);
}
if ($oStatLog->Get('status') == 'error')
{
@@ -152,9 +152,10 @@ foreach(explode(',', $sDataSourcesList) as $iSDS)
$oP->p("Objects creation errors: ".$oStatLog->Get('stats_nb_obj_created_errors'));
$oP->p("Objects updated: ".$oStatLog->Get('stats_nb_obj_updated'));
$oP->p("Objects update errors: ".$oStatLog->Get('stats_nb_obj_updated_errors'));
- $oP->p("Objects reconciled (updated): ".$oStatLog->Get('stats_nb_new_updated'));
- $oP->p("Objects reconciled (unchanged): ".$oStatLog->Get('stats_nb_new_unchanged'));
+ $oP->p("Objects reconciled (updated): ".$oStatLog->Get('stats_nb_obj_new_updated'));
+ $oP->p("Objects reconciled (unchanged): ".$oStatLog->Get('stats_nb_obj_new_unchanged'));
$oP->p("Objects reconciliation errors: ".$oStatLog->Get('stats_nb_replica_reconciled_errors'));
+ $oP->p("Replica disappeared, no action taken: ".$oStatLog->Get('stats_nb_replica_disappeared_no_action'));
}
catch(Exception $e)
{
diff --git a/synchro/synchro_import.php b/synchro/synchro_import.php
index 82ac3f6d1..c259ca20c 100644
--- a/synchro/synchro_import.php
+++ b/synchro/synchro_import.php
@@ -374,6 +374,9 @@ try
//
try
{
+ $oP->add_comment('Load--------------');
+ $oP->add_comment('------------------');
+
if ($bSimulate)
{
CMDBSource::Query('START TRANSACTION');
@@ -444,19 +447,62 @@ try
}
}
+ if (($sOutput == "summary") || ($sOutput == 'details'))
+ {
+ $oP->add_comment("Data Source: ".$iDataSourceId);
+ $oP->add_comment("Synchronize: ".($bSynchronize ? '1' : '0'));
+ $oP->add_comment("Class: ".$sClass);
+ $oP->add_comment("Separator: ".$sSep);
+ $oP->add_comment("Qualifier: ".$sQualifier);
+ $oP->add_comment("Charset Encoding:".$sCharSet);
+ $oP->add_comment("Data Size: ".strlen($sCSVData));
+ $oP->add_comment("Data Lines: ".$iLineCount);
+ $oP->add_comment("Columns: ".implode(', ', $aInputColumns));
+ $oP->add_comment("Output format: ".$sOutput);
+ // $oP->add_comment("Report level: ".$sReportLevel);
+ $oP->add_comment("Simulate: ".($bSimulate ? '1' : '0'));
+ $oP->add_comment("Change tracking comment: ".$sComment);
+ $oP->add_comment("Issues (before synchro): ".$iCountErrors);
+ // $oP->add_comment("Warnings: ".$iCountWarnings);
+ $oP->add_comment("Created (before synchro): ".$iCountCreations);
+ $oP->add_comment("Updated (before synchro): ".$iCountUpdates);
+ }
+
//////////////////////////////////////////////////
//
// Synchronize
//
if ($bSynchronize)
{
- $aTraces = array();
- $oStatLog = $oDataSource->Synchronize($aTraces, $oLoadStartDate);
- //echo "#@# Synchronize() returned :
\n";
- //echo "
\n";
- //print_r($aTraces);
- //print_r($oStatLog);
- //echo "
\n";
+ $aResults = array();
+ $oStatLog = $oDataSource->Synchronize($aResults, $oLoadStartDate);
+ $oP->add_comment('Synchronization---');
+ $oP->add_comment('------------------');
+ if ($sOutput == 'details')
+ {
+ foreach ($aResults as $sMessage)
+ {
+ $oP->add_comment($sMessage);
+ }
+ }
+ if ($oStatLog->Get('status') == 'error')
+ {
+ $oP->p("ERROR: ".$oStatLog->Get('last_error'));
+ }
+ $oP->add_comment("Replicas: ".$oStatLog->Get('stats_nb_replica_total'));
+ $oP->add_comment("Replicas touched since last synchro: ".$oStatLog->Get('stats_nb_replica_seen'));
+ $oP->add_comment("Objects deleted: ".$oStatLog->Get('stats_nb_obj_deleted'));
+ $oP->add_comment("Objects deletion errors: ".$oStatLog->Get('stats_nb_obj_deleted_errors'));
+ $oP->add_comment("Objects obsoleted: ".$oStatLog->Get('stats_nb_obj_obsoleted'));
+ $oP->add_comment("Objects obsolescence errors: ".$oStatLog->Get('stats_nb_obj_obsoleted_errors'));
+ $oP->add_comment("Objects created: ".$oStatLog->Get('stats_nb_obj_created'));
+ $oP->add_comment("Objects creation errors: ".$oStatLog->Get('stats_nb_obj_created_errors'));
+ $oP->add_comment("Objects updated: ".$oStatLog->Get('stats_nb_obj_updated'));
+ $oP->add_comment("Objects update errors: ".$oStatLog->Get('stats_nb_obj_updated_errors'));
+ $oP->add_comment("Objects reconciled (updated): ".$oStatLog->Get('stats_nb_obj_new_updated'));
+ $oP->add_comment("Objects reconciled (unchanged): ".$oStatLog->Get('stats_nb_obj_new_unchanged'));
+ $oP->add_comment("Objects reconciliation errors: ".$oStatLog->Get('stats_nb_replica_reconciled_errors'));
+ $oP->add_comment("Replica disappeared, no action taken: ".$oStatLog->Get('stats_nb_replica_disappeared_no_action'));
}
}
catch(Exception $e)
@@ -480,27 +526,6 @@ try
{
$oP->add($iCountErrors);
}
-
- if (($sOutput == "summary") || ($sOutput == 'details'))
- {
- $oP->add_comment("Data Source: ".$iDataSourceId);
- $oP->add_comment("Synchronize: ".($bSynchronize ? '1' : '0'));
- $oP->add_comment("Class: ".$sClass);
- $oP->add_comment("Separator: ".$sSep);
- $oP->add_comment("Qualifier: ".$sQualifier);
- $oP->add_comment("Charset Encoding:".$sCharSet);
- $oP->add_comment("Data Size: ".strlen($sCSVData));
- $oP->add_comment("Data Lines: ".$iLineCount);
- $oP->add_comment("Columns: ".implode(', ', $aInputColumns));
- $oP->add_comment("Output format: ".$sOutput);
-// $oP->add_comment("Report level: ".$sReportLevel);
- $oP->add_comment("Simulate: ".($bSimulate ? '1' : '0'));
- $oP->add_comment("Change tracking comment: ".$sComment);
- $oP->add_comment("Issues: ".$iCountErrors);
-// $oP->add_comment("Warnings: ".$iCountWarnings);
- $oP->add_comment("Created: ".$iCountCreations);
- $oP->add_comment("Updated: ".$iCountUpdates);
- }
}
catch(ExchangeException $e)
{
diff --git a/synchro/synchrodatasource.class.inc.php b/synchro/synchrodatasource.class.inc.php
index 2aa3de2d7..aa126e321 100644
--- a/synchro/synchrodatasource.class.inc.php
+++ b/synchro/synchrodatasource.class.inc.php
@@ -228,7 +228,9 @@ EOF
);
$oPage->add($this->HtmlBox('repl_ignored', $aData, '#999').' | ');
$oPage->add("\n");
- $oPage->add($this->HtmlBox('repl_disappeared', $aData, '#630', 'rowspan="3"').'| => | '.$this->HtmlBox('obj_deleted', $aData, '#000'));
+ $oPage->add($this->HtmlBox('repl_disappeared', $aData, '#630', 'rowspan="4"').'=> | '.$this->HtmlBox('obj_disappeared_no_action', $aData, '#333'));
+ $oPage->add("
\n");
+ $oPage->add($this->HtmlBox('obj_deleted', $aData, '#000'));
$oPage->add("
\n");
$oPage->add($this->HtmlBox('obj_obsoleted', $aData, '#630'));
$oPage->add("
\n");
@@ -271,6 +273,7 @@ EOF
'obj_deleted' => $oLastLog->Get('stats_nb_obj_deleted'),
'obj_obsoleted' => $oLastLog->Get('stats_nb_obj_obsoleted'),
'obj_disappeared_errors' => $oLastLog->Get('stats_nb_obj_obsoleted_errors') + $oLastLog->Get('stats_nb_obj_deleted_errors'),
+ 'obj_disappeared_no_action' => $oLastLog->Get('stats_nb_replica_disappeared_no_action'),
'obj_updated' => $oLastLog->Get('stats_nb_obj_updated'),
'obj_updated_errors' => $oLastLog->Get('stats_nb_obj_updated_errors'),
'obj_new_updated' => $oLastLog->Get('stats_nb_obj_new_updated'),
@@ -279,7 +282,7 @@ EOF
'obj_created_errors' => $oLastLog->Get('stats_nb_obj_created_errors'),
);
$iReconciledErrors = $oLastLog->Get('stats_nb_replica_reconciled_errors');
- $iDisappeared = $aData['obj_disappeared_errors'] + $aData['obj_obsoleted'] + $aData['obj_deleted'];
+ $iDisappeared = $aData['obj_disappeared_errors'] + $aData['obj_obsoleted'] + $aData['obj_deleted'] + $aData['obj_disappeared_no_action'];
$aData['repl_disappeared'] = $iDisappeared;
$iNewErrors = $aData['obj_created_errors'] + $oLastLog->Get('stats_nb_replica_reconciled_errors');
$aData['obj_new_errors'] = $iNewErrors;
@@ -499,6 +502,7 @@ EOF
$oStatLog->Set('stats_nb_obj_updated_errors', 0);
// $oStatLog->Set('stats_nb_replica_reconciled', 0);
$oStatLog->Set('stats_nb_replica_reconciled_errors', 0);
+ $oStatLog->Set('stats_nb_replica_disappeared_no_action', 0);
$oStatLog->Set('stats_nb_obj_new_updated', 0);
$oStatLog->Set('stats_nb_obj_new_unchanged',0);
@@ -545,6 +549,8 @@ EOF
throw new SynchroExceptionNotStarted(Dict::S('Core:SyncDataSourceAccessRestriction'));
}
+ $sDeletePolicy = $this->Get('delete_policy');
+
// Count the replicas
$sSelectAll = "SELECT SynchroReplica WHERE sync_source_id = :source_id";
$oSetAll = new DBObjectSet(DBObjectSearch::FromOQL($sSelectAll), array() /* order by*/, array('source_id' => $this->GetKey()));
@@ -584,10 +590,10 @@ EOF
}
while($oReplica = $oSetToObsolete->Fetch())
{
- // TO DO: take the appropriate action based on the 'delete_policy' field
- $sUpdateOnObsolete = $this->Get('delete_policy');
- if ( ($sUpdateOnObsolete == 'update') || ($sUpdateOnObsolete == 'update_then_delete') )
+ switch ($sDeletePolicy)
{
+ case 'update':
+ case 'update_then_delete':
$aTraces[] = "Destination object: (dest_id:".$oReplica->Get('dest_id').") to be updated";
$aToUpdate = array();
$aToUpdate = explode(';', $this->Get('delete_policy_update')); //ex: 'status:obsolete;description:stopped',
@@ -601,10 +607,16 @@ EOF
$aToUpdate[$sAttCode] = $sValue;
}
}
- $oReplica->UpdateDestObject($aToUpdate, $oMyChange, $oStatLog, $aTraces, 'stats_nb_obj_obsoleted');
+ $oReplica->UpdateDestObject($aToUpdate, $oMyChange, $oStatLog, $aTraces);
+ $oReplica->Set('status', 'obsolete');
+ $oReplica->DBUpdateTracked($oMyChange);
+ break;
+
+ case 'delete':
+ default:
+ $aTraces[] = "Destination object: (dest_id:".$oReplica->Get('dest_id').") to be DELETED";
+ $oReplica->DeleteDestObject($oMyChange, $oStatLog, $aTraces);
}
- $oReplica->Set('status', 'obsolete');
- $oReplica->DBUpdateTracked($oMyChange);
}
//Count "seen" objects
@@ -674,37 +686,34 @@ EOF
// Get all the replicas that are to be deleted
//
- $oDeletionDate = $oLastFullLoadStartDate;
- $sDeleteRetention = trim($this->Get('delete_policy_retention'));
- if (strlen($sDeleteRetention) > 0)
+ if ($sDeletePolicy == 'update_then_delete')
{
- $sInterval = '-'.$sDeleteRetention;
- // Note: the PHP doc states that Modify return FALSE in case of error
- // but, this is actually NOT the case
- // Therefore, I do compare before and after, considering that the
- // format is incorrect when the datetime remains unchanged
- $sBefore = $oDeletionDate->Format('Y-m-d H:i:s');
- $oDeletionDate->Modify($sInterval);
- $sAfter = $oDeletionDate->Format('Y-m-d H:i:s');
- if ($sBefore == $sAfter)
+ $oDeletionDate = $oLastFullLoadStartDate;
+ $sDeleteRetention = trim($this->Get('delete_policy_retention')); // MUST NOT BE NULL
+ if (strlen($sDeleteRetention) > 0)
{
- throw new SynchroExceptionNotStarted("Data exchange: Wrong interval specification", array('interval' => $sInterval, 'source_id' => $this->GetKey()));
+ $sInterval = '-'.$sDeleteRetention;
+ // Note: the PHP doc states that Modify return FALSE in case of error
+ // but, this is actually NOT the case
+ // Therefore, I do compare before and after, considering that the
+ // format is incorrect when the datetime remains unchanged
+ $sBefore = $oDeletionDate->Format('Y-m-d H:i:s');
+ $oDeletionDate->Modify($sInterval);
+ $sAfter = $oDeletionDate->Format('Y-m-d H:i:s');
+ if ($sBefore == $sAfter)
+ {
+ throw new SynchroExceptionNotStarted("Data exchange: Wrong interval specification", array('interval' => $sInterval, 'source_id' => $this->GetKey()));
+ }
}
- }
- $sDeletionDate = $oDeletionDate->Format('Y-m-d H:i:s');
- $aTraces[] = "sDeletionDate: $sDeletionDate";
- $sSelectToDelete = "SELECT SynchroReplica WHERE sync_source_id = :source_id AND status IN ('obsolete') AND status_last_seen < :last_import";
- $oSetToDelete = new DBObjectSet(DBObjectSearch::FromOQL($sSelectToDelete), array() /* order by*/, array('source_id' => $this->GetKey(), 'last_import' => $sDeletionDate));
- while($oReplica = $oSetToDelete->Fetch())
- {
- $sUpdateOnObsolete = $this->Get('delete_policy');
- if ( ($sUpdateOnObsolete == 'delete') || ($sUpdateOnObsolete == 'update_then_delete') )
+ $sDeletionDate = $oDeletionDate->Format('Y-m-d H:i:s');
+ $aTraces[] = "Deletion date: $sDeletionDate";
+ $sSelectToDelete = "SELECT SynchroReplica WHERE sync_source_id = :source_id AND status IN ('obsolete') AND status_last_seen < :last_import";
+ $oSetToDelete = new DBObjectSet(DBObjectSearch::FromOQL($sSelectToDelete), array() /* order by*/, array('source_id' => $this->GetKey(), 'last_import' => $sDeletionDate));
+ while($oReplica = $oSetToDelete->Fetch())
{
$aTraces[] = "Destination object: (dest_id:".$oReplica->Get('dest_id').") to be DELETED";
$oReplica->DeleteDestObject($oMyChange, $oStatLog, $aTraces);
}
- $aTraces[] = "Replica id:".$oReplica->GetKey()." (dest_id:".$oReplica->Get('dest_id').") to be deleted";
- $oReplica->DBDeleteTracked($oMyChange);
}
}
@@ -924,6 +933,8 @@ class SynchroLog extends cmdbAbstractObject
MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_obj_updated_errors", array("allowed_values"=>null, "sql"=>"stats_nb_obj_updated_errors", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
// MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_replica_reconciled", array("allowed_values"=>null, "sql"=>"stats_nb_replica_reconciled", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_replica_reconciled_errors", array("allowed_values"=>null, "sql"=>"stats_nb_replica_reconciled_errors", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
+ MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_replica_disappeared_no_action", array("allowed_values"=>null, "sql"=>"stats_nb_replica_disappeared_no_action", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
+
MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_obj_new_updated", array("allowed_values"=>null, "sql"=>"stats_nb_obj_new_updated", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_obj_new_unchanged", array("allowed_values"=>null, "sql"=>"stats_nb_obj_new_unchanged", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
@@ -931,7 +942,7 @@ class SynchroLog extends cmdbAbstractObject
// Display lists
MetaModel::Init_SetZListItems('details', array('sync_source_id', 'start_date', 'end_date', 'status', 'stats_nb_replica_total', 'stats_nb_replica_seen', 'stats_nb_obj_created', /*'stats_nb_replica_reconciled',*/ 'stats_nb_obj_updated', 'stats_nb_obj_obsoleted', 'stats_nb_obj_deleted',
- 'stats_nb_obj_created_errors', 'stats_nb_replica_reconciled_errors', 'stats_nb_obj_updated_errors', 'stats_nb_obj_obsoleted_errors', 'stats_nb_obj_deleted_errors', 'stats_nb_obj_new_unchanged', 'stats_nb_obj_new_updated')); // Attributes to be displayed for the complete details
+ 'stats_nb_obj_created_errors', 'stats_nb_replica_reconciled_errors', 'stats_nb_replica_disappeared_no_action', 'stats_nb_obj_updated_errors', 'stats_nb_obj_obsoleted_errors', 'stats_nb_obj_deleted_errors', 'stats_nb_obj_new_unchanged', 'stats_nb_obj_new_updated')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('sync_source_id', 'start_date', 'end_date', 'status', 'stats_nb_replica_seen')); // Attributes to be displayed for a list
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
@@ -1032,6 +1043,7 @@ class SynchroReplica extends DBObject
switch($this->Get('status'))
{
case 'new':
+ $this->Set('status_dest_creator', false);
// If needed, construct the query used for the reconciliation
if (!isset(self::$aSearches[$oDataSource->GetKey()]))
{
@@ -1092,10 +1104,7 @@ class SynchroReplica extends DBObject
$oDestObj = $oDestSet->Fetch();
$this->UpdateObjectFromReplica($oDestObj, $aAttributes, $oChange, $oStatLog, $aTraces, 'stats_nb_obj_new', 'stats_nb_replica_reconciled_errors');
$this->Set('dest_id', $oDestObj->GetKey());
- $this->Set('status_dest_creator', false);
$this->Set('dest_class', get_class($oDestObj));
-
- $oStatLog->Inc('stats_nb_replica_reconciled'); //@@@
}
else
{
@@ -1124,7 +1133,6 @@ class SynchroReplica extends DBObject
$oDestObj = $oDestSet->Fetch();
$this->UpdateObjectFromReplica($oDestObj, $aAttributes, $oChange, $oStatLog, $aTraces, 'stats_nb_obj_new', 'stats_nb_replica_reconciled_errors');
$this->Set('dest_id', $oDestObj->GetKey());
- $this->Set('status_dest_creator', false);
$this->Set('dest_class', get_class($oDestObj));
}
}
@@ -1230,23 +1238,31 @@ class SynchroReplica extends DBObject
/**
* Update the destination object with given values
*/
- public function UpdateDestObject($aValues, $oChange, &$oStatLog, &$aTraces, $sStatCode)
+ public function UpdateDestObject($aValues, $oChange, &$oStatLog, &$aTraces)
{
try
{
- $oDestObj = MetaModel::GetObject($this->Get('dest_class'), $this->Get('dest_id'));
- foreach($aValues as $sAttCode => $value)
+ if ($this->Get('dest_class') == '')
{
- $oDestObj->Set($sAttCode, $value);
+ $this->SetLastError('No destination object to update');
+ $oStatLog->Inc('stats_nb_obj_obsoleted_errors');
+ }
+ else
+ {
+ $oDestObj = MetaModel::GetObject($this->Get('dest_class'), $this->Get('dest_id'));
+ foreach($aValues as $sAttCode => $value)
+ {
+ $oDestObj->Set($sAttCode, $value);
+ }
+ $oDestObj->DBUpdateTracked($oChange);
+ $aTraces[] = "Replica id:".$this->GetKey()." (dest_id:".$this->Get('dest_id').") marked as obsolete";
+ $oStatLog->Inc('stats_nb_obj_obsoleted');
}
- $oDestObj->DBUpdateTracked($oChange);
- $aTraces[] = "Replica id:".$this->GetKey()." (dest_id:".$this->Get('dest_id').") marked as obsolete";
- $oStatLog->Inc($sStatCode);
}
catch(Exception $e)
{
$this->SetLastError('Unable to update the destination object: ', $e);
- $oStatLog->Inc($sStatCode.'_errors');
+ $oStatLog->Inc('stats_nb_obj_obsoleted_errors');
}
}
@@ -1257,18 +1273,26 @@ class SynchroReplica extends DBObject
{
if($this->Get('status_dest_creator'))
{
- $oDestObj = MetaModel::GetObject($this->Get('dest_class'), $this->Get('dest_id'));
try
{
+ $oDestObj = MetaModel::GetObject($this->Get('dest_class'), $this->Get('dest_id'));
$oDestObj->DBDeleteTracked($oChange);
+ $this->DBDeleteTracked($oChange);
$oStatLog->Inc('stats_nb_obj_deleted');
}
catch(Exception $e)
{
$this->SetLastError('Unable to delete the destination object: ', $e);
+ $this->Set('status', 'obsolete');
+ $this->DBUpdateTracked($oChange);
$oStatLog->Inc('stats_nb_obj_deleted_errors');
}
}
+ else
+ {
+ $this->DBDeleteTracked($oChange);
+ $oStatLog->Inc('stats_nb_replica_disappeared_no_action');
+ }
}
/**