2015-06-11 22:48:41 +02:00
< ? php
namespace Icinga\Module\Director\IcingaConfig ;
use Icinga\Data\Db\DbConnection ;
2015-06-23 14:37:23 +02:00
use Icinga\Module\Director\Util ;
2015-06-11 22:48:41 +02:00
use Icinga\Module\Director\Objects\IcingaCommand ;
use Icinga\Module\Director\Objects\IcingaHost ;
2015-06-23 16:03:56 +02:00
use Exception ;
2015-06-11 22:48:41 +02:00
class IcingaConfig
{
protected $files = array ();
2015-06-17 19:03:23 +02:00
protected $checksum ;
protected $lastActivityChecksum ;
/**
* @ var \Zend_Db_Adapter_Abstract
*/
protected $db ;
protected $connection ;
protected $generationTime ;
public static $table = 'director_generated_config' ;
protected function __construct ( DbConnection $connection )
{
$this -> connection = $connection ;
$this -> db = $connection -> getDbAdapter ();
}
public function getChecksum ()
{
return $this -> checksum ;
}
public function getHexChecksum ()
2015-06-11 22:48:41 +02:00
{
2015-06-23 14:37:23 +02:00
return Util :: binary2hex ( $this -> checksum );
2015-06-11 22:48:41 +02:00
}
public function getFiles ()
{
return $this -> files ;
}
2015-06-17 19:03:23 +02:00
public function getFileNames ()
{
return array_keys ( $this -> files );
}
public function getMissingFiles ( $missing )
{
$files = array ();
foreach ( $this -> files as $name => $file ) {
$files [] = $name . '=' . $file -> getChecksum ();
}
return $files ;
}
2015-06-18 10:54:44 +02:00
public static function fromDb ( $checksum , DbConnection $connection )
{
$config = new static ( $connection );
$config -> loadFromDb ( $checksum );
return $config ;
}
2015-06-17 19:03:23 +02:00
public static function generate ( DbConnection $connection )
{
$config = new static ( $connection );
return $config -> storeIfModified ();
}
protected function storeIfModified ()
{
$this -> generateFromDb ();
$checksum = $this -> calculateChecksum ();
$exists = $this -> db -> fetchOne (
2015-06-23 15:13:34 +02:00
$this -> db -> select () -> from ( self :: $table , 'COUNT(*)' ) -> where ( 'checksum = ?' , $this -> dbBin ( $checksum ))
2015-06-17 19:03:23 +02:00
);
if (( int ) $exists === 0 ) {
$this -> store ();
}
return $this ;
}
2015-06-23 15:13:34 +02:00
protected function dbBin ( $binary )
{
if ( $this -> connection -> getDbType () === 'pgsql' ) {
return Util :: pgBinEscape ( $binary );
} else {
return $binary ;
}
}
2015-06-17 19:03:23 +02:00
protected function calculateChecksum ()
{
$files = array ( $this -> getLastActivityHexChecksum ());
$sortedFiles = $this -> files ;
ksort ( $sortedFiles );
/** @var IcingaConfigFile $file */
foreach ( $sortedFiles as $name => $file ) {
$files [] = $name . '=' . $file -> getHexChecksum ();
}
$this -> checksum = sha1 ( implode ( ';' , $files ), true );
return $this -> checksum ;
}
public function getFilesChecksums ()
2015-06-11 22:48:41 +02:00
{
2015-06-17 19:03:23 +02:00
$checksums = array ();
/** @var IcingaConfigFile $file */
foreach ( $this -> files as $name => $file ) {
$checksums [] = $file -> getChecksum ();
}
return $checksums ;
}
protected function store ()
{
$fileTable = IcingaConfigFile :: $table ;
$fileKey = IcingaConfigFile :: $keyName ;
$this -> db -> beginTransaction ();
try {
$existingQuery = $this -> db -> select ()
-> from ( $fileTable , 'checksum' )
2015-06-23 15:13:34 +02:00
-> where ( 'checksum IN (?)' , array_map ( array ( $this , 'dbBin' ), $this -> getFilesChecksums ()));
2015-06-17 19:03:23 +02:00
$existing = $this -> db -> fetchCol ( $existingQuery );
$missing = array_diff ( $this -> getFilesChecksums (), $existing );
/** @var IcingaConfigFile $file */
foreach ( $this -> files as $name => $file ) {
$checksum = $file -> getChecksum ();
if ( ! in_array ( $checksum , $missing )) {
continue ;
}
$this -> db -> insert (
$fileTable ,
array (
$fileKey => $checksum ,
'content' => $file -> getContent ()
)
);
}
$this -> db -> insert (
self :: $table ,
array (
'duration' => $this -> generationTime ,
2015-06-23 16:03:56 +02:00
'last_activity_checksum' => $this -> dbBin ( $this -> getLastActivityChecksum ()),
'checksum' => $this -> dbBin ( $this -> getChecksum ()),
2015-06-17 19:03:23 +02:00
)
);
/** @var IcingaConfigFile $file */
foreach ( $this -> files as $name => $file ) {
$this -> db -> insert (
'director_generated_config_file' ,
array (
2015-06-23 16:03:56 +02:00
'config_checksum' => $this -> dbBin ( $this -> getChecksum ()),
'file_checksum' => $this -> dbBin ( $file -> getChecksum ()),
'file_path' => $name ,
2015-06-17 19:03:23 +02:00
)
);
}
$this -> db -> commit ();
2015-06-23 16:03:56 +02:00
} catch ( Exception $e ) {
2015-06-17 19:03:23 +02:00
$this -> db -> rollBack ();
var_dump ( $e -> getMessage ());
}
return $this ;
2015-06-11 22:48:41 +02:00
}
2015-06-17 19:03:23 +02:00
protected function generateFromDb ()
2015-06-11 22:48:41 +02:00
{
2015-06-17 19:03:23 +02:00
$start = microtime ( true );
2015-06-11 22:48:41 +02:00
$this
-> createFileFromDb ( 'zone' )
2015-06-17 10:53:41 +02:00
-> createFileFromDb ( 'endpoint' )
2015-06-11 22:48:41 +02:00
-> createFileFromDb ( 'command' )
2015-06-17 10:53:41 +02:00
-> createFileFromDb ( 'hostGroup' )
2015-06-11 22:48:41 +02:00
-> createFileFromDb ( 'host' )
2015-06-17 10:53:41 +02:00
-> createFileFromDb ( 'serviceGroup' )
2015-06-11 22:48:41 +02:00
-> createFileFromDb ( 'service' )
2015-06-17 10:53:41 +02:00
-> createFileFromDb ( 'userGroup' )
2015-06-12 13:41:38 +02:00
-> createFileFromDb ( 'user' )
2015-06-11 22:48:41 +02:00
;
2015-06-12 13:38:49 +02:00
2015-06-17 19:03:23 +02:00
$this -> generationTime = ( microtime ( true ) - $start ) * 1000 ;
2015-06-11 22:48:41 +02:00
return $this ;
}
2015-06-18 10:54:44 +02:00
protected function loadFromDb ( $checksum )
{
$query = $this -> db -> select () -> from (
self :: $table ,
array ( 'checksum' , 'last_activity_checksum' )
2015-06-23 15:13:34 +02:00
) -> where ( 'checksum = ?' , $this -> dbBin ( $checksum ));
2015-06-18 10:54:44 +02:00
$result = $this -> db -> fetchRow ( $query );
$this -> checksum = $result -> checksum ;
2015-06-18 11:01:45 +02:00
$this -> lastActivityChecksum = $result -> last_activity_checksum ;
2015-06-18 10:54:44 +02:00
$query = $this -> db -> select () -> from (
array ( 'cf' => 'director_generated_config_file' ),
array (
'file_path' => 'cf.file_path' ,
'checksum' => 'f.checksum' ,
'content' => 'f.content' ,
)
) -> join (
array ( 'f' => 'director_generated_file' ),
'cf.file_checksum = f.checksum' ,
array ()
2015-06-23 15:13:34 +02:00
) -> where ( 'cf.config_checksum = ?' , $this -> dbBin ( $checksum ));
2015-06-18 10:54:44 +02:00
foreach ( $this -> db -> fetchAll ( $query ) as $row ) {
$file = new IcingaConfigFile ();
$this -> files [ $row -> file_path ] = $file -> setContent ( $row -> content );
}
return $this ;
}
2015-06-11 22:48:41 +02:00
protected function createFileFromDb ( $type )
{
$class = 'Icinga\\Module\\Director\\Objects\\Icinga' . ucfirst ( $type );
2015-06-17 19:03:23 +02:00
$objects = $class :: loadAll ( $this -> connection );
2015-06-11 22:48:41 +02:00
if ( ! empty ( $objects )) {
2015-06-17 10:03:31 +02:00
$file = new IcingaConfigFile ();
if ( $type === 'command' ) {
$file -> prepend ( " library \" methods \" \n \n " );
}
2015-06-11 22:48:41 +02:00
$file -> addObjects ( $objects );
2015-06-17 10:53:41 +02:00
$this -> files [ strtolower ( $type ) . 's.conf' ] = $file ;
2015-06-11 22:48:41 +02:00
}
return $this ;
}
2015-06-17 19:03:23 +02:00
public function getLastActivityHexChecksum ()
{
2015-06-23 14:37:23 +02:00
return Util :: binary2hex ( $this -> getLastActivityChecksum ());
2015-06-17 19:03:23 +02:00
}
/**
* @ return mixed
*/
public function getLastActivityChecksum ()
{
if ( $this -> lastActivityChecksum === null ) {
$query = $this -> db -> select ()
-> from ( 'director_activity_log' , 'checksum' )
-> order ( 'change_time DESC' )
-> limit ( 1 );
$this -> lastActivityChecksum = $this -> db -> fetchOne ( $query );
2015-06-23 14:12:39 +02:00
// PgSQL workaround:
if ( is_resource ( $this -> lastActivityChecksum )) {
$this -> lastActivityChecksum = stream_get_contents ( $this -> lastActivityChecksum );
}
2015-06-17 19:03:23 +02:00
}
return $this -> lastActivityChecksum ;
}
// TODO: wipe unused files
// DELETE f FROM director_generated_file f left join director_generated_config_file cf ON f.checksum = cf.file_checksum WHERE cf.file_checksum IS NULL;
2015-06-11 22:48:41 +02:00
}