Code

Updated new config management
[gosa.git] / gosa-plugins / goto-ng / admin / newConfigManagement / class_newConfigManagement.inc
1 <?php
3 /*! \brief  This class allows to manage backend config items and packages.
4  */
5 class newConfigManagement extends plugin
6 {
7     var $initTime;
8     var $plHeadline = "Config management";
9     var $plDescription = "Config management";
11     var $selectedContainer;
13     var $dataModel = NULL;
14     var $listing = NULL;
16     var $cfgTypeMap = NULL;
17     var $cfgItemMap = NULL;
19     var $addableContainerItems = array();
20     var $currentObject = NULL;
23     /*! \brief  Initialize the plugin and finally update the data model.
24      */
25     function __construct($config, $dn)
26     {
27         $this->config = &$config;
28         $this->listing = new ConfigManagementListing($this->config, get_userinfo(), $this);
30         // Load the template engine and tell her what template
31         //  to use for the HTML it produces.
32         $this->TemplateEngine = new TemplateEngine($config);
34         // Request an update of the data model
35         $this->loadInstallationMethods();
36         $this->updateDataModel();
37         $this->listing->setListingTypes($this->getListingTypes());
38     }
41     /*! \brief  Sets the installation method to the given method.
42      *          Updates the template engine and adds the initial root
43      *           object for the selected method.
44      *  @param  The method to use.
45      *  @return TRUE on success else FALSE.
46      */
47     function setInstallMethod($str)
48     {
49         if(!isset($this->installationMethods[$str])){
50             $this->itemConfig = array();
51             $this->invalidInstallMethod =TRUE;
52             $this->errorMessage = sprintf(_("Invalid installation method %s selected!"), bold($str));
53             msg_dialog::display(_("Setup"), $this->errorMessage, ERROR_DIALOG);
54             return(FALSE);
55         }else{
56     
57             $this->TemplateEngine->setTemplate($str.".tpl");
58             $this->itemConfig = $this->installationMethods[$str]['items'];
59             $this->invalidInstallMethod =FALSE;
60             $this->TemplateEngine->load($this->itemConfig);
62             // Detect root item, its name is /
63             $root = NULL;
64             foreach($this->itemConfig as $key => $item){
65                 if($item['name'] == '/') {
66                     $root = $key;
67                     break;
68                 }
69             }
70             if(!$root){
71                 $this->errorMessage = sprintf(_("Installation method %s is invalid: no root object found!"), bold($str));
72                 msg_dialog::display(_("Setup"), $this->errorMessage , ERROR_DIALOG);
73                 $this->initFailed = TRUE;
74                 $this->itemConfig = array();
75                 return(FALSE);
76             }
77         }
78     }
81     /*! \brief  Updates all distributions, releases, packages and items in the dataModel
82      *          Load information from the backend.
83      */
84     function updateDataModel()
85     {
86         // Recreate the data model, to have a clean and fresh instance.
87         $this->dataModel = new ConfigManagementDataModel();
89         // Load distributions 
90         $rpc = $this->config->getRpcHandle();
91         $res = $rpc->getDistributions();
93         if(!$rpc->success()){
94             msg_dialog::display(_("Error"), sprintf(_("Failed to load distributions: %s"), $rpc->get_error()),ERROR_DIALOG);
95             return(NULL);
96         }else{
97             $this->cfgTypeMap = array();
98             foreach($res as $dist){
99                 $dist['__removeable'] = TRUE;
100                 $this->dataModel->addItem('Distribution','/root', $dist['name'], $dist);
101                 $this->cfgTypeMap['/root/'.$dist['name']] = $dist['installation_method'];
102                 foreach($dist['releases'] as $release){
103                     $distPath = "/root/{$dist['name']}";
104                     $release['__removeable'] = TRUE;
105                     $this->dataModel->addItem('Release',$distPath, $release['name'], $release);
106                 }
107             }
108         }
109     }
112     /*! \brief  Keep track of posted values and populate those 
113      *           which are interesting for us.
114      *          Inspects the _POST and _GET values.
115      */
116     function save_object()
117     {
118         // Update the listing class, this is necessary to get post
119         //  actions from it.
120         $this->listing->save_object();
122         // Get the selected distribution and release from the listing widget.
123         $cont = $this->listing->getSelectedContainer();
124         if(isset($_POST['ROOT'])){
125             $this->setCurrentContainer('/root');
126         }elseif(isset($_POST['BACK'])){
128             $path = $this->selectedContainer;
129             if($this->dataModel->itemExistsByPath($path)){
130                 $data = $this->dataModel->getItemByPath($path);
131                 if($data['parentPath']){
132                     $this->setCurrentContainer($data['parentPath']);
133                 }
134             }
135         }else{
136             $this->setCurrentContainer($cont);
137         }
138     }
141     /*! \brief  Load extended sub-objecte like 'config items' or 'packages'
142      *           for the given release path.
143      *  @param  String  The release path to load sub-objects for.
144      *  @return NULL 
145      */
146     function updateItemList($path)
147     {
148         // Fist get Item and check if it is an release 
149         if($this->dataModel->itemExistsByPath($path)){
150             $data = $this->dataModel->getItemByPath($path);
152             // Only releases can contain config-items.
153             if($data['type'] == 'Release' && $data['status'] != "fetched"){
155                 $rpc = $this->config->getRpcHandle();
156                 $res = $rpc->listConfigItems($data['name']);
157                 if(!$rpc->success()){
158                     msg_dialog::display(_("Error"), 
159                             sprintf(_("Failed to load distributions: %s"), 
160                                 $rpc->get_error()),ERROR_DIALOG);
161                 }else{
163                     // Sort entries by path length 
164                     $sLen = array();
165                     foreach($res as $itemPath => $type){
166                         $sLen[strlen($itemPath)."_".$itemPath] = $itemPath;
167                     }
168                     uksort($sLen, "strnatcasecmp");   
170                     // Walk through each entry and then try to add it to the model
171                     foreach($sLen as $unused => $itemPath){
173                         // Do not add the root element '/'
174                         if($itemPath == "/") continue;
176                         $type = $res[$itemPath];
177                 
178                         // Root installation objects do not have a name, so we use 'root' here.
179                         $targetPath = trim($path."/".$itemPath);
181                         // Remove trailing and duplicated slashes
182                         $targetPath = rtrim($targetPath, '/');
183                         $targetPath = preg_replace("/\/\/*/","/", $targetPath);
185                         // Extract the items name
186                         $name = preg_replace("/^.*\//","", $targetPath);
187     
188                         // Cleanup the path and then add the item.
189                         $targetPath = preg_replace("/[^\/]*$/","", $targetPath);
190                         $targetPath = rtrim($targetPath,'/');
191                         $this->dataModel->addItem($type, $targetPath, $name, 
192                                 array(    
193                                         '__editable' => TRUE,
194                                         '__removeable' => TRUE,
195                                         '__path' => $itemPath,
196                                         '__release' => $path
197                                     ),'-' ); 
198                     }
199                     $this->dataModel->setItemStatus($path, 'fetched');
200                 }
201             }
202         }
203     }
206     /*! \brief  Sets the currently selected container and item path. 
207      *  @param  String  The path of the container to set.
208      *  @param  String  The path of the item to set.
209      *  @return 
210      */
211     function setCurrentContainer($cont)
212     {
213         $this->selectedContainer = $cont;
215         // Update list of items within the selected container. 
216         $this->updateItemList($this->selectedContainer);
218         // Transfer checked values back to the listing class.
219         $this->listing->setContainers($this->getContainerList());
220         $this->listing->setContainer($cont);
222         // Set the correct installation method for the selected item
223         if(isset($this->cfgTypeMap[$cont])){
224             $method = $this->cfgTypeMap[$cont];
225             $this->setInstallMethod($method);
226         }
228         // Update the list of addable sub objects
229         $item = $this->dataModel->getItemByPath($cont);
230         if(isset($this->itemConfig[$item['type']]['container'])){
231             $this->addableContainerItems = $this->itemConfig[$item['type']]['container'];
232         }else{
233             $this->addableContainerItems = array();
234         }
235     }
238     /*! \brief  Generate the HTML content for this plugin.
239      *          Actually renders the listing widget..
240      */
241     function execute()
242     {
243         // Get the selected release and store it in a session variable
244         //  to allow the configFilter to access it and display the
245         //  packages and items.
246         $res = $this->listing->execute();
247         $this->listing->setListingTypes($this->getListingTypes());
248         return($res);
249     }
252     /*! \brief      Returns a list of items which will then be displayed 
253      *               in the management-list. 
254      *              (The management class calls this method from its execute())
255      *  @return     Array   A list of items/objects for the listing. 
256      */
257     function getItemsToBeDisplayed()
258     {
260         $path = $this->selectedContainer;
261         $item = $this->dataModel->getItemByPath($path);
262         return($item);
263     }
266     /*! \brief  Returns a simply list of all distributions.
267      *          This list will then be used to generate the entries of the 
268      *           ItemSelectors in the listing class.
269      */
270     function getContainerList()
271     {
272         $data = $this->dataModel->getItemByPath('/root');
273         $res = array();
274         $res["/root"] = array("name" => "/", "desc" => "");
275         $res = array_merge($res,$this->__recurseItem($data, array('Distribution','Release')));
276         return($res);
277     }
280     /*! \brief  Recursivly walks through an item and collects all path and name info.
281      *          The reult can then be used to fill the ItemSelector.
282      *  @param  Array   The Item to recurse. 
283      *  @param  Array   The type of of objects to collect. 
284      *  @param  String  The parent path prefix which should be removed.
285      *  @return Array   An array containing Array[path] = name
286      */
287     function __recurseItem($item, $types, $parent = "")
288     {
289         $res = array();
290         if(1 ||  in_array($item['type'], $types)){
291             $path = preg_replace("/".preg_quote($parent,'/')."/","",$item['path']);
292             $res[$path] = array('name' => $item['name'],'desc'=>$item['type']);
293         }
294         if(count($item['children'])){
295             foreach($item['children'] as $child){
296                 $res = array_merge($res, $this->__recurseItem($child, $types, $parent));
297             }
298         }
299         return($res);
300     }
303     /*! \brief  Intializes this plugin
304      *          All available installation methods will be loaded
305      */
306     function loadInstallationMethods()
307     {
308         // Reset erros
309         $this->rpcError = $this->initFailed = FALSE;
311         // Load configuration via rpc.
312         $rpc = $this->config->getRpcHandle();
314         // Populate install methods on success.
315         $res = $rpc->getSupportedInstallMethods();
316         if(!$rpc->success()){
317             $this->rpcError = TRUE;
318             $this->errorMessage = $rpc->get_error();;
319             return;
320         }
321         $this->installationMethods = $res;
323         if(!count($this->installationMethods)){
324             $this->errorMessage = _("No selectable install methods returned!");
325             msg_dialog::display(_("Setup"), $this->errorMessage , ERROR_DIALOG);
326             $this->initFailed = TRUE;
327             return;
328         }else{
329             $this->cfgItemMap = array();
330             foreach($this->installationMethods as $method => $items){
331                 foreach($items['items'] as $itemName => $item){
332                     $this->cfgItemMap[$itemName] = $method;
333         
334                     // This enables us to create the first level of config items when 
335                     //  a release is selected.
336                     if($item['name'] == "/"){
337                         $this->installationMethods[$method]['items']['Release'] = 
338                             &$this->installationMethods[$method]['items'][$itemName];
339                     }
340                 }
341             }
342         }
343     }
346     /*! \brief   Returns a info list about all items we can manage,
347      *            this used to fill the listings <objectType> settings.
348      *  @return Array   An array with item info.
349      */
350     function getListingTypes()
351     {
352         $types= array();
353         $types['Distribution']['objectClass'] = 'Distribution';
354         $types['Distribution']['label'] = _('Distribution');
355         $types['Distribution']['image'] = 'images/lists/edit.png';
356         $types['Distribution']['category'] = 'Device';
357         $types['Distribution']['class'] = 'Device';
359         $types['Release']['objectClass'] = 'Release';
360         $types['Release']['label'] = _('Release');
361         $types['Release']['image'] = 'images/lists/delete.png';
362         $types['Release']['category'] = 'Device';
363         $types['Release']['class'] = 'Device';
365         $types['Component']['objectClass'] = 'Component';
366         $types['Component']['label'] = _('Component');
367         $types['Component']['image'] = 'plugins/users/images/select_user.png';
368         $types['Component']['category'] = 'Device';
369         $types['Component']['class'] = 'Device';
371         foreach($this->installationMethods as $method => $items){
372             foreach($items['items'] as $itemName => $item){
373                 $types[$itemName]['objectClass'] = $itemName;
374                 $types[$itemName]['label'] = $item['name'];
375                 $types[$itemName]['image'] = 'plugins/fai/images/fai_script.png';
376                 $types[$itemName]['category'] = 'Device';
377                 $types[$itemName]['class'] = 'Device';
378             }
379         }
381         return($types);
382     }
385     /*! \brief      The plugins ACL and plugin-property definition. 
386      *  @return 
387      */
388     public static function plInfo()
389     {
390         return (array(
391                     "plShortName"   => _("Config management"),
392                     "plDescription" => _("Config management"),
393                     "plSelfModify"  => FALSE,
394                     "plDepends"     => array(),
395                     "plPriority"    => 0,
396                     "plSection"     => array("administration"),
397                     "plCategory"    => array(
398                         "newConfigManagement" => array("description"  => _("Config management"),
399                             "objectClass"  => "FAKE_OC_newConfigManagement")),
400                     "plProvidedAcls"=> array()
401                     ));
402     }
405     /*! \brief  Acts on open requests.
406      *          (This action is received from the ConfigManagementListing class.)
407      *  @param  Array   The items ids. (May contain multiple ids)
408      *  @return
409      */
410     function openEntry($ids)
411     {
412         $id = $ids[0];
413         $item = $this->dataModel->getItemById($id);
414         $this->setCurrentContainer($item['path']);
415         return;
416     }
420     /*! \brief  Removes an entry from the listing.
421      */
422     function removeEntry($ids)
423     {
425         $item = $this->dataModel->getItemById($ids[0]);
427         // Is an config item.
428         if(isset($this->cfgItemMap[$item['type']])){
429             $release = preg_replace("/^.*\//","",$item['values']['__release']);
430             $path = $item['values']['__path'];
431             $rpc = $this->config->getRpcHandle();
432             $rpc->removeConfigItem($release, $path);
433             if(!$rpc->success()){
434                 msg_dialog::display(_("Error"), sprintf(_("Failed to remove: %s"), $rpc->get_error()),ERROR_DIALOG);
435                 return(NULL);
436             }else{
437                 $this->dataModel->removeItem($item['path']);
438             }
439         }else{
440             echo $item['type']." - are not handled yet!";
441         }
442     }
445     /*! \brief      Edits a selected list item.
446      */
447     function editEntry($ids)
448     {
449         // Update the template engine to use another type of item and
450         //  some other values.
451         $item = $this->dataModel->getItemById($ids[0]);
452         if(isset($this->cfgItemMap[$item['type']])){
453             $release = preg_replace("/^.*\//","",$item['values']['__release']);
454             $path = $item['values']['__path'];
455             $method = $this->cfgItemMap[$item['type']];
457             // Load item values on demand
458             if($item['status'] == '-'){
459                 $rpc = $this->config->getRpcHandle();
460                 $item['values']['itemValues'] = $rpc->getConfigItem($release, $path);
461                 $this->dataModel->setItemStatus($item['path'], 'fetched');
462                 $this->dataModel->setItemValues($item['path'], $item['values']);
463             }
465             $this->setInstallMethod($method);
466             $this->TemplateEngine->setValues($item['type'],$item['values']['itemValues']);
467             $this->listing->setDialogObject($this->TemplateEngine);
468             $this->currentObject = $item;
469         }
470     }
473     /*! \brief  Initiates the creation of a new item
474      */
475     function newEntry($type)
476     {
477         $method = $this->cfgItemMap[$type];
478         $this->setInstallMethod($method);
479         $this->TemplateEngine->setValues($type,array());
480         $this->listing->setDialogObject($this->TemplateEngine);
481         $this->currentObject = NULL;
482     }
485     /*! \brief  Extracts the item-path out of a path.
486      *          e.g. /debian/squeeze/test/module -> /test/module
487      */
488     function getItemPath($fullPath)
489     {
490         $fPath = $fullPath.'/';
491         while(preg_match("/\//", $fPath)){
492             $fPath = preg_replace("/\/[^\/]*$/","", $fPath);
493             $item = $this->dataModel->getItemByPath($fPath);
494             if(isset($this->cfgItemMap[$item['type']])){
495                 return(preg_replace("/".preg_quote($item['parentPath'],'/')."/", "", $fullPath));
496             }
497         }
498         return(NULL);
499     }
502     /*! \brief  Extracts the releaes path out of a path.
503      *          e.g. /debian/squeeze/test/module -> /debian/squeeze
504      */
505     function getReleasePath($fullPath)
506     {
507         $fullPath.='/';
508         while(preg_match("/\//", $fullPath)){
509             $fullPath = preg_replace("/\/[^\/]*$/","", $fullPath);
510             $item = $this->dataModel->getItemByPath($fullPath);
511             if($item['type'] == 'Release'){
512                 return($fullPath);
513             }
514         }
515         return(NULL);
516     }
517    
518  
519     function saveItemChanges()
520     {
521         $item = $this->currentObject;
523         // Null means a new  object has to be added.        
524         if($item == NULL){
526             // Save template engine modifications
527             $this->TemplateEngine->save_object();
528             $release = preg_replace("/^.*\//","", $this->getReleasePath($this->selectedContainer));
529             $type = $this->TemplateEngine->getItemType();
531             // Collect modified values
532             $values = array();
533             foreach($this->TemplateEngine->getWidgets() as $w){
534                 $values[$w->getName()] = $w->getValue();
535             }
536            
537             // Create the elements target path  
538             $path = $this->getItemPath($this->selectedContainer)."/".$values['name'];
540             // Add the new item
541             $rpc = $this->config->getRpcHandle();
542             $res = $rpc->setConfigItem($release, $path, $type, $values);
543             if(!$rpc->success()){
544                 msg_dialog::display(_("Error"), sprintf(_("Failed to load distributions: %s"), $rpc->get_error()),ERROR_DIALOG);
545                 return(NULL);
546             }else{
548                 // We've successfully added the item, now add it to the tree.
549                 $this->dataModel->addItem($type, $this->selectedContainer, $values['name'], 
550                         array(    
551                             '__editable' => TRUE,
552                             '__removeable' => TRUE,
553                             '__path' => $path,
554                             '__release' => $this->getReleasePath($this->selectedContainer)
555                             ), '-' );
557                 // Finally - close the dialog. 
558                 $this->listing->clearDialogObject();
559             }
560         }else{
562             // Collect modified values.
563             $this->TemplateEngine->save_object();
564             $values = array();
565             foreach($this->TemplateEngine->getWidgets() as $w){
566                 $values[$w->getName()] = $w->getValue();
567             }
569             // Get the items release & path info
570             $release = preg_replace("/^.*\//","",$item['values']['__release']);
571             $path = $item['values']['__path'];
572     
573             // Write the modifications back to the server.
574             $rpc = $this->config->getRpcHandle();
575             $res = $rpc->setConfigItem($release, $path, $item['type'], $values);
576             if(!$rpc->success()){
577                 msg_dialog::display(_("Error"), sprintf(_("Failed to load distributions: %s"), $rpc->get_error()),ERROR_DIALOG);
578                 return(NULL);
579             }else{
580         
581                 // Update the data model
582                 $item['values']['itemValues'] = $values;
583                 $this->dataModel->setItemValues($item['path'], $item['values']);
584                 $this->listing->clearDialogObject();
585             }
586         }
587     }
588     function remove_lock() {}
592 ?>