Kind of makes sense.. If it makes a better product, I don't think that anyone will object. :-) Thanks, Luis -----Original Message----- From: racktables-users-bounce@xxxxxxxxxxxxx [mailto:racktables-users-bounce@xxxxxxxxxxxxx] On Behalf Of Tutton, James Sent: Friday, March 05, 2010 10:39 AM To: racktables-users@xxxxxxxxxxxxx Subject: [racktables-users] Addon Functionality and Dynamic function calls Hi All, I am currently working to extend the rack tables functionality by adding the ability to use plugins/addons. This is currently only a proof of concept but would like to share it with the community and ask the changes required in the base code are considered for admission into the tree. And also get feedback on the concept as whole. Must say this is currently a proof of concept and should not be consider security validated of bug free. To achieve this we have created a new folder called addons. We have then added the following to inc/local.php ###### APPEND TO inc/local.php foreach (glob("/FULL_PATH_TO_RACK_TABLES/addons/*.php") as $filename) { include($filename); } ###### END APPEND TO inc/local.php To allow the use of classes within our addons we need to change the way racktables calls functions by reference. The main benefit here is we can build our addons as tight classes. Without this change we have to ensure all our addons have unique function names and this proved to be very problematic very quickly for our needs. ###### Amend index.php aprrox line 81 showMessageOrError(); // Added call_user_func Method to allow Class Based Invocations call_user_func($tabhandler[$pageno][$tabno], $_REQUEST[$page[$pageno]['bypass']]); //$tabhandler[$pageno][$tabno] ($_REQUEST[$page[$pageno]['bypass']]); } else { showMessageOrError(); // Added call_user_func Method to allow Class Based Invocations call_user_func($tabhandler[$pageno][$tabno]); //$tabhandler[$pageno][$tabno] (); ###### End Amend index.php Addons will also work with callbacks but working on KISS principle for this example. For reference though if anyone wants to go further using callbacks as well then make similar changes in process.php line 32 Then we simply add our addons into the "addons" folder and they are loaded into memory for later use. An Example Addon is Below. This addon will list all your objects based on Racktables type and then group them by hardware type. New Tab is added to Reports -> Object Types ######################################################################## ####### <?php // RMS Reports Object Types // by James Tutton // Version 0.1 // Installation: // 1) Add include to rms_addons folder; // 2) Make sure rms_addons folder is included in inc/local.php // foreach (glob("/home/1user/public_html/rms_addons/*.php") as $filename) { // include($filename); // } // Which Tab Section should we render on what should we Name the Tab $tab['reports']['rmsobjecttypes'] = 'Object Types'; // What Function should render the tab content // Add The New tab to appropriate page and set entry function options as array('CLASSNAME', 'FUNCTIONNAME'); // IMPORTANT FUNCTIONAME must be a static function as we have not initialised the class as would be waste of memory to have class loaded all the time $tabhandler['reports']['rmsobjecttypes'] = array('RMSObjectTypeReport', 'getContent'); // Which Should we Call to handle post back // View only Report so post not required // $ophandler['reports'][ 'rmsobjecttypes']['addObjectlog'] = 'addObjectlog'; class RMSObjectTypeReport { static public function getContent () { $obj = new RMSObjectTypeReport(); $obj->rmsGetObjectsTypes(); } function rmsGetObjectsTypes () { echo "<link rel=stylesheet type='text/css' href=/rms_addons/style.css />"; echo "<div id=\"rms_addonWrapper\">"; echo "<br/>"; $output = ""; $objecttypes= "SELECT * FROM Dictionary WHERE chapter_id = 1"; $obtyperesult = useSelectBlade ($objecttypes, __FUNCTION__); $obtyperesult = $obtyperesult->fetchall(); foreach ($obtyperesult as $objtyperow) { $objtype_id = $objtyperow['dict_key']; $objectdetials = $this->rmsGetObjectsByType($objtype_id); if ($objectdetials <> "") { $output .= "<div class=\"rmsobjecttypes\"> ".$objtyperow['dict_value']."</div>\n"; $output .= $objectdetials; } } echo $output; echo "</div>"; } function rmsGetObjectsByType ($objtype_id) { $output = ""; $objquery ="SELECT RackObject.* , Dictionary.dict_value as HWType FROM RackObject LEFT OUTER JOIN AttributeValue ON AttributeValue.object_id = RackObject.id AND attr_id = 2 LEFT OUTER JOIN Dictionary ON AttributeValue.uint_value = Dictionary.dict_key WHERE`objtype_id` =$objtype_id ORDER BY Dictionary.dict_value"; $objresult = useSelectBlade ($objquery, __FUNCTION__); $objresult = $objresult->fetchall(); if (count($objresult) > 0 ) { $output .= "<TABLE id=\"rmsobjects\">\n"; $output .= "<TR><TH class=\"ObjectHWType\">HW Type</TH><TH class=\"ObjectName\">Name</TH><TH class=\"ObjectLabel\">Device Label</TH></TR>\n"; $class = "even"; foreach ($objresult as $object) { $class = ($class=='even') ? 'odd' : 'even'; $output .= "<TR class=\"$class\">"; $output .= "<TD class=\"ObjectHWType\">".execGMarker(parseWikiLink($object['HWType'],'o' ))."</TD>"; $output .= "<TD class=\"ObjectName\"><a href=\"index.php?page=object&object_id=".$object['id']. "\">".$object['name']."</a></TD>"; $output .= "<TD class=\"ObjectLabel\">".$object['label']."</TD>"; $output .= "</TR>\n"; } $output .= "</TABLE>\n"; } return $output; } } ?> ######################################################################## #######. Other addons I am working on include a RIPE update addon for using with the IP4 addresses. A helpdesk lookup based on the device name and Sql connection to third party system. There is a style sheet that goes with all this to neaten things up but don't want to provide to much if people not interested. James Tutton