From 8687769b63fcb90be3f73bfb06266936b4a24a99 Mon Sep 17 00:00:00 2001 From: alban Date: Tue, 8 Jul 2014 22:36:09 +0200 Subject: [PATCH] [enh] diagnostic commands working --- lib/Alternc/Diagnostic/Diff.php | 124 +++++++++++++- lib/Alternc/Diagnostic/Directory.php | 75 +++++++- lib/Alternc/Diagnostic/Manager.php | 146 +++++++++++++++- lib/Alternc/Diagnostic/Report.php | 13 ++ lib/Alternc/Diagnostic/Service/Panel.php | 31 ++++ src/diagnostic.php | 209 ++++++----------------- 6 files changed, 423 insertions(+), 175 deletions(-) create mode 100644 lib/Alternc/Diagnostic/Report.php diff --git a/lib/Alternc/Diagnostic/Diff.php b/lib/Alternc/Diagnostic/Diff.php index 788c2edd..dc8dc0e7 100644 --- a/lib/Alternc/Diagnostic/Diff.php +++ b/lib/Alternc/Diagnostic/Diff.php @@ -2,27 +2,135 @@ class Alternc_Diagnostic_Diff{ + + /** @var Alternc_Diagnostic_Manager */ + public $manager; + + public function __construct(Alternc_Diagnostic_Manager $manager) { + $this->manager = $manager; + } /** * - * @param type $file_reference_1 + * @param mixed $file_1 * Either a number or a string refering to the file * Default = Last file - * @param type $file_reference_2 + * @param mixed $file_2 * Either a number or a string refering to the file * Default = pre-last file + * @return Alternc_Diagnostic_Report */ - function compare($file_reference_1, $file_reference_2){ - + function compare($file_1, $file_2){ + + // Instanciates a resolver able to convert int/string to Data instance + $resolverInstance = new Alternc_Diagnostic_Format_Resolver($this->manager->getDirectoryInstance()); + // Builds instance #1 + $data1Instance = $resolverInstance->getDataInstance($file_1); + // Builds instance #2 + $data2Instance = $resolverInstance->getDataInstance($file_2); + // Atttemps to compare 2 instances + return $this->getDiff($data1Instance,$data2Instance); } + + + /** - * Finds a file by reference or name + * Compares recursively two Data objects * - * @param string $file_reference - * @return Alternc_Diagnostic_Data Resulting data + * @param Alternc_Diagnostic_Data $data1Instance + * @param Alternc_Diagnostic_Data $data2Instance */ - function resolve( $file_reference){ + function getDiff( Alternc_Diagnostic_Data $data1Instance, Alternc_Diagnostic_Data $data2Instance ){ + + $reportInstance = new Alternc_Diagnostic_Report(); + $data1Data = $data1Instance->getData(); + $data2Data = $data2Instance->getData(); + // Searches non present data keys + $arrayDiff1 = array_diff_key($data1Data, $data2Data); + $arrayDiff2 = array_diff_key($data2Data, $data1Data); + + if( count($arrayDiff1)){ + $reportInstance->missingList = array_keys($arrayDiff1); + } + if(count($arrayDiff2)){ + $reportInstance->addedList = array_keys($arrayDiff2); + } + + // Compares present data kays + $arrayIntersect = array_intersect_key($data1Data, $data2Data); + $searchKeys = array_keys($arrayIntersect); + foreach ($searchKeys as $key ){ + // Compares objects + if(is_object($data2Data[$key])){ + $result = $this->getDiff($data1Data[$key], $data2Data[$key]); + if( $result ){ + $reportInstance->modifiedData[$key] = $result; + } + } + // Compares arrays + else if(is_array($data2Data[$key])) { + $result = $this->compareArrays($data1Data[$key], $data2Data[$key]); + if( $result ){ + $reportInstance->modifiedData[$key] = $result; + } + }else{ + if ( $data1Data[$key] != $data2Data[$key]){ + $reportInstance->modifiedData[$key] = array($data1Data[$key] != $data2Data[$key]); + + } + } + } + + // Returns null if no difference + if( ( ! $reportInstance->addedList ) && ( ! $reportInstance->missingList ) && ( ! $reportInstance->modifiedData ) ) { + return null; + } + + // Returns a Report object + return $reportInstance; + } + + function compareArrays( $array1, $array2){ + + $reportInstance = new Alternc_Diagnostic_Report(); + natcasesort($array1); + natcasesort($array2); + + // Searches non present data keys + $arrayDiff1 = array_diff_key($array1, $array2); + $arrayDiff2 = array_diff_key($array2, $array1); + + if( count($arrayDiff1)){ + $reportInstance->missingList = array_keys($arrayDiff1); + } + if(count($arrayDiff2)){ + $reportInstance->addedList = array_keys($arrayDiff2); + } + + // Compares present data kays + $arrayIntersect = array_intersect_key($array1, $array2); + if( count($arrayIntersect)){ + $searchKeys = array_keys($arrayIntersect); + $diffArray = array(); + foreach ($searchKeys as $key) { + if ($array1[$key] != $array2[$key]) { + if( !array_search($array1[$key], $array2)){ + $diffArray[$key] = array($array1[$key], $array2[$key]); + } + } + if (count($diffArray)) { + $reportInstance->modifiedData = $diffArray; + } + } + } + // Returns null if no difference + if( ( ! $reportInstance->addedList ) && ( ! $reportInstance->missingList ) && ( ! $reportInstance->modifiedData ) ) { + return null; + } + + // Returns a Report object + return $reportInstance; } } diff --git a/lib/Alternc/Diagnostic/Directory.php b/lib/Alternc/Diagnostic/Directory.php index c89c7e84..fb481db1 100644 --- a/lib/Alternc/Diagnostic/Directory.php +++ b/lib/Alternc/Diagnostic/Directory.php @@ -9,25 +9,86 @@ class Alternc_Diagnostic_Directory { */ protected $file_path; - public function __construct( $file_path) { - if( null == $file_path){ + + /** + * id => name (date) list + * + * @var array + */ + protected $filesList; + + + /** + * + * @param string $dir_path + * @throws \Exception + */ + public function __construct( $dir_path) { + if( null == $dir_path){ throw new \Exception("Empty file_path in Diagnostic Format handler"); } - if( !file_exists($file_path)){ - if( !mkdir($file_path, 0774, true)){ - throw new \Exception("Could not access path $file_path in Diagnostic Format handler"); + if( !file_exists($dir_path)){ + if( !mkdir($dir_path, 0774, true)){ + throw new \Exception("Could not crate storage directory $dir_path in Diagnostic Format handler"); } } - $this->file_path = $file_path; + $this->file_path = $dir_path; } + /** + * + * @param int $max + * @return array + */ function getList( $max = null){ - $dir = new DirectoryIterator($this->file_path); + if( ! is_null( $this->filesList)){ + return $this->filesList; + } + $resultArray = array(); + $dir = new DirectoryIterator($this->file_path); + foreach( $dir as $file){ + if( $file->isDot()){ + continue; + } + $resultArray[] = $file->getFilename(); + } + $this->filesList = $resultArray; + return $resultArray; + } + /** + * + * @param int $max + * @return array + */ + function getListWithDates( $max = null){ + + $this->getList(); + $resultArray = array(); + foreach( $this->filesList as $id => $filename){ + $date = "?"; + if( preg_match(":(\S*)\..*:", $filename,$matches) ){ + $date = date("Y-m-d H:i:s", $matches[1]); + } + $resultArray[$id] = "$filename ($date)"; + } + return $resultArray; } + public function unlink( $file_name ){ + $file_path = $this->file_path . DIRECTORY_SEPARATOR . $file_name; + if( !is_file( $file_path )){ + throw new \Exception("Invalid file deletion requested : $file_path does not exist."); + } + if( !unlink( $file_path )){ + throw new \Exception("Failed to delete: $file_path."); + } + return true; + + } + /** * @param string file_path */ diff --git a/lib/Alternc/Diagnostic/Manager.php b/lib/Alternc/Diagnostic/Manager.php index e75c03d8..aa331f29 100644 --- a/lib/Alternc/Diagnostic/Manager.php +++ b/lib/Alternc/Diagnostic/Manager.php @@ -11,7 +11,7 @@ class Alternc_Diagnostic_Manager{ public $formatInstance; /** - * @var Alternc_Diagnost_Directory + * @var Alternc_Diagnostic_Directory */ public $directoryInstance; @@ -54,6 +54,7 @@ class Alternc_Diagnostic_Manager{ * * @param Console_CommandLine_Result $options * @throws \Exception + * @return string */ function create(Console_CommandLine_Result $options){ @@ -73,14 +74,145 @@ class Alternc_Diagnostic_Manager{ // Runs the service agent and store the results $diagnosticData->addData($serviceAgent->name, $serviceAgent->run()); } - $this->formatInstance->setData($diagnosticData)->write(); + $file_name = $this->formatInstance->setData($diagnosticData)->write(); + return "Wrote diagnostic file $file_name"; + } + + function compare( $options ){ + + $args = $options->args; + // Attempts to retrieve file_1 + if (isset($args["file_1"])) { + $file_1 = $args["file_1"]; + } else { + $file_1 = 0; + } + // Attempts to retrieve file_2 + if (isset($args["file_2"])) { + $file_2 = $args["file_2"]; + } else { + $file_2 = 1; + } + $diffInstance = new Alternc_Diagnostic_Diff($this); + + $report = $diffInstance->compare($file_1,$file_2); + + if( null == $report){ + return new Alternc_Diagnostic_Report; + } + return $report; + + } + /** + * + * @param array $options + * @return array + */ + function index( $options ){ + + return $this->directoryInstance->getListWithDates(); + + } + + /** + * + * @param array $options + * @return string + * + */ + function show( $options ){ + + $args = $options->args; + $options = $options->options; + + // Attempts to retrieve file_1 + if (isset($args["file"])) { + $file_reference = $args["file"]; + } else { + $file_reference = 0; + } + + // Attempts to retrieve format + if (isset($options["format"])) { + $format = $options["format"]; + } else { + $format = "json"; + } + + // Retrieves a resolver + $resolverInstance = new Alternc_Diagnostic_Format_Resolver($this->getDirectoryInstance()); + + // Retrieves data instance + $dataInstance = $resolverInstance->getDataInstance($file_reference); + + // Converts to string according to format requested + if( "var_dump" == $format){ + var_dump($dataInstance); + $return = ""; + }else{ + $return = json_encode($dataInstance); + } + return $return; + } + + /** + * Deletes one or more files + * + * @param array $options + * @return string + */ + function delete( $options ){ + + $args = $options->args; + + // Attempts to retrieve filesList + if (isset($args["filesList"]) && count($args["filesList"])) { + $filesList = $args["filesList"]; + } else { + $filesList = array(0); + } + // Retrieves a resolver + $resolverInstance = new Alternc_Diagnostic_Format_Resolver($this->getDirectoryInstance()); + $removedList = array(); + foreach ($filesList as $file_reference) { + $file_name = $resolverInstance->resolve($file_reference); + if( $this->directoryInstance->unlink( $file_name ) ){ + $removedList[] = $file_name; + } + } + return "Successfully removed files : ".implode(", ", $removedList)."\n"; } - function compare( $options ){} - function index( $options ){} - function show( $options ){} - function delete( $options ){} - + /** + * @param Alternc_Diagnostic_Directory directoryInstance + */ + public function setDirectoryInstance($directoryInstance) { + $this->directoryInstance = $directoryInstance; + return $this; + } + + /** + * @return Alternc_Diagnostic_Directory + */ + public function getDirectoryInstance() { + return $this->directoryInstance; + } + + /** + * @param Alternc_Format_Abstract formatInstance + */ + public function setFormatInstance($formatInstance) { + $this->formatInstance = $formatInstance; + return $this; + } + + /** + * @return Alternc_Format_Abstract + */ + public function getFormatInstance() { + return $this->formatInstance; + } + } diff --git a/lib/Alternc/Diagnostic/Report.php b/lib/Alternc/Diagnostic/Report.php new file mode 100644 index 00000000..256b38d3 --- /dev/null +++ b/lib/Alternc/Diagnostic/Report.php @@ -0,0 +1,13 @@ +membersList = $this->getMembersList(); + + // Writes the members list + $this->writeSectionData(self::SECTION_MEMBERS_LIST, $this->membersList); + return $this->data; } + + function getMembersList(){ + $returnArray = array(); + $this->db->query("SELECT uid,login,enabled,su,mail,creator,db_server_id,created FROM alternc.membres;"); + if ($this->db->num_rows()) { + while ($this->db->next_record()) { + $returnArray[$this->db->f("uid")] = array( + "uid" => $this->db->f("uid"), + "login" => $this->db->f("login"), + "enabled" => $this->db->f("enabled"), + "su" => $this->db->f("su"), + "mail" => $this->db->f("mail"), + "creator" => $this->db->f("creator"), + "db_server_id" => $this->db->f("db_server_id"), + "created" => $this->db->f("created"), + ); + } + } + return $returnArray; + } } \ No newline at end of file diff --git a/src/diagnostic.php b/src/diagnostic.php index 69ea41f9..479121d3 100644 --- a/src/diagnostic.php +++ b/src/diagnostic.php @@ -112,6 +112,8 @@ function __autoload($class_name) // ================================================================== // ================================================================== +chdir(__DIR__); + $version = "3.2"; // alternc 1.0 @@ -124,9 +126,7 @@ if(is_file("/usr/share/alternc/panel/class/config_nochk.php")){ } - - -$directoryInstance = new Alternc_Diagnostic_Directory("/tmp/diagnostic"); +$directoryInstance = new Alternc_Diagnostic_Directory("/var/lib/alternc/diagnostics"); // instanciation of the diagnosticManager service @@ -169,10 +169,47 @@ $createCommmand->addOption('format', array( )); $indexCommmand = $consoleParser->addCommand('index', array('multiple'=>false,"alias"=>"i","description" => "Shows all available diagnostics")); -$compareCommmand = $consoleParser->addCommand('compare', array('multiple'=>false,"alias"=>"x","description" => "Removes one or more diagnotics")); -$compareCommmand = $consoleParser->addCommand('show', array('multiple'=>false,"alias"=>"s","description" => "Prints a diagnotic content")); +$compareCommmand = $consoleParser->addCommand('compare', array('multiple'=>false,"alias"=>"x","description" => "Compares file_1 to file_2. Accepts names or number reference.")); + +$compareCommmand->addArgument('file1', array( + 'description' => 'File name or reference (1..x)', + 'help_name' => 'file_1', + "optional" => true + )); + +$compareCommmand->addArgument('file2', array( + 'description' => 'File name or reference of file (1..x)', + 'help_name' => 'file_2', + "optional" => true + )); + +$showCommmand = $consoleParser->addCommand('show', array('multiple'=>false,"alias"=>"s","description" => "Prints a diagnotic content")); +$showCommmand->addArgument('file', array( + 'description' => 'File name or reference (1..x)', + 'help_name' => 'file', + "optional" => true + )); +$showCommmand->addOption('format', array( + 'short_name' => '-f', + 'long_name' => '--format', + 'action' => 'StoreString', + 'default' => 'json', + 'description' => 'Sets the format of the output : +* json (default) +* var_dump +', + 'help_name' => 'format', + 'choices' => array("jso","var_dump") + )); + $deleteCommmand = $consoleParser->addCommand('delete', array('multiple'=>false,"alias"=>"d","description" => "Deletes diagnostic files")); +$deleteCommmand->addArgument('filesList', array( + 'description' => 'Single or multiple files names or references (1..x)', + 'help_name' => 'file', + "optional" => true, + "multiple" => true + )); // Attempts to parse command line @@ -187,153 +224,19 @@ try { if( !method_exists($diagnosticManager, $command_name)){ throw new \Exception("Invalid command : $command"); } - $diagnosticManager->$command_name($command); + $response = $diagnosticManager->$command_name($command); + if( is_a($response, "Alternc_Diagnostic_Report")){ + var_dump($response); + }else if( is_array($response)){ + foreach ($response as $key => $value) { + echo "$key : $value \n"; + } + }else if( is_string($response)){ + echo $response; + }else if (is_null($response)){ + echo ("Empty response"); + } + echo ("\n"); } catch (\Exception $exc) { $consoleParser->displayError($exc->getMessage()); -} -/* -// Put this var to 1 if you want to enable debug prints - - -$admin->stop_if_jobs_locked(); - -$LOCK_FIL E= '/var/run/alternc/do_actions_cron.lock'; -$SCRIP T= '/usr/bin/php do_actions.php'; -$MY_PI D= getmypid(); -$FIXPER M= '/usr/lib/alternc/fixperms.sh'; - -// Check if script isn't already running -if (file_exists($LOCK_FILE) !== false){ - d("Lock file already exists. "); - // Check if file is in process list - $PI D= file_get_contents($LOCK_FILE); - d("My PID is $MY_PID, PID in the lock file is $PID"); - if ($PID == exec("pidof $SCRIPT | tr ' ' '\n' | grep -v $MY_PID")){ - // Previous cron is not finished yet, just exit - d("Previous cron is already running, we just exit and let it finish :-)"); - exit(0); - }else{ - // Previous cron failed! - $error_raise .= "Lock file already exists. No process with PID $PID found! Previous cron failed...\n"; - d("Removing lock file and trying to process the failed action..."); - // Delete the lock and continue to the next action - unlink($LOCK_FILE); - - // Lock with the current script's PID - if (file_put_contents($LOCK_FILE,$MY_PID) === false){ - $error_raise .= "Cannot open/write $LOCK_FILE\n"; - mail_it(); - exit(1); - } - - // Get the action(s) that was processing when previous script failed - // (Normally, there will be at most 1 job pending... but who know?) - while($cc=$action->get_job()){ - $ c= $cc[0]; - $param s= unserialize($c["parameters"]); - // We can resume these types of action, so we reset the job to process it later - d("Previous job was the n°".$c["id"]." : '".$c["type"]."'"); - if($c["type"] == "CREATE_FILE" && is_dir(dirname($params["file"])) || $c["type"] == "CREATE_DIR" || $c["type"] == "DELETE" || $c["type"] == "FIXDIR" || $c["type"] == "FIXFILE"){ - d("Reset of the job! So it will be resumed..."); - $action->reset_job($c["id"]); - }else{ - // We can't resume the others types, notify the fail and finish this action - $error_raise .= "Can't resume the job n°".$c["id"]." action '".$c["type"]."', finishing it with a fail status.\n"; - if(!$action->finish($c["id"],"Fail: Previous script crashed while processing this action, cannot resume it.")){ - $error_raise .= "Cannot finish the action! Error while inserting the error value in the DB for action n°".$c["id"]." : action '".$c["type"]."'\n"; - break; // Else we go into an infinite loop... AAAAHHHHHH - } - } - } - } -}else{ - // Lock with the current script's PID - if (file_put_contents($LOCK_FILE,$MY_PID) === false){ - $error_raise .= "Cannot open/write $LOCK_FILE\n"; - mail_it(); - exit(1); - } -} - -//We get the next action to do -while ($rr=$action->get_action()){ - $ r= $rr[0]; - $retur n= "OK"; - // Do we have to do this action with a specific user? - if($r["user"] != "root") - $S U= "su ".$r["user"]." 2>&1 ;"; - else - $S U= ""; - unset($output); - // We lock the action - d("-----------\nBeginning action n°".$r["id"]); - $action->begin($r["id"]); - // We process it - $param s= @unserialize($r["parameters"]); - // We exec with the specified user - d("Executing action '".$r["type"]."' with user '".$r["user"]."'"); - switch ($r["type"]){ - case "FIX_USER" : - // Create the directory and make parent directories as needed - @exec("$FIXPERM -u ".$params["uid"]." 2>&1", $trash, $code); - break; - case "CREATE_FILE" : - if(!file_exists($params["file"])) - @exec("$SU touch ".$params["file"]." 2>&1 ; echo '".$params["content"]."' > '".$params["file"]."' 2>&1", $output); - else - $outpu t= array("Fail: file already exists"); - break; - case "CREATE_DIR" : - // Create the directory and make parent directories as needed - @exec("$SU mkdir -p ".$params["dir"]." 2>&1",$output); - break; - case "DELETE" : - // Delete file/directory and its contents recursively - @exec("$SU rm -rf ".$params["dir"]." 2>&1", $output); - break; - case "MOVE" : - // If destination dir does not exists, create it - if(!is_dir($params["dst"])) - @exec("$SU mkdir -p ".$params["dst"]." 2>&1",$output); - if(!isset($output[0])) - @exec("$SU mv -f ".$params["src"]." ".$params["dst"]." 2>&1", $output); - break; - case "FIXDIR" : - @exec("$FIXPERM -d ".$params["dir"]." 2>&1", $trash, $code); - if($code!=0) - $output[0]="Fixperms.sh failed, returned error code : $code"; - break; - case "FIXFILE" : - @exec("$FIXPERM -f ".$params["file"]." 2>&1", $trash, $code); - if($code!=0) - $output[0]="Fixperms.sh failed, returned error code : $code"; - break; - default : - $outpu t= array("Fail: Sorry dude, i do not know this type of action"); - break; - } - // Get the error (if exists). - if(isset($output[0])){ - $retur n= $output[0]; - $error_raise .= "Action n°".$r["id"]." '".$r["type"]."' failed! With user: ".$r["user"]."\nHere is the complete output:\n".print_r($output); - } - // We finished the action, notify the DB. - d("Finishing... return value is : $return\n"); - if(!$action->finish($r["id"],addslashes($return))){ - $error_raise .= "Cannot finish the action! Error while inserting the error value in the DB for action n°".$c["id"]." : action '".$c["type"]."'\nReturn value: ".addslashes($return)."\n"; - break; // Else we go into an infinite loop... AAAAHHHHHH - } -} - -// If something have failed, notify it to the admin -if($error_raise !== '') - mail_it(); - -// Unlock the script -unlink($LOCK_FILE); - -// Exit this script -exit(0); -?> - -*/ +} \ No newline at end of file