321ef0bb35dd218d8b08f741560e785d22b2a630
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 $cfgItemMap = NULL;
18 var $addableContainerItems = array();
19 var $currentObject = NULL;
20 var $itemsPerMethod = NULL;
22 /*! \brief Initialize the plugin and finally update the data model.
23 */
24 function __construct($config, $dn)
25 {
26 $this->config = &$config;
27 $this->listing = new ConfigManagementListing($this->config, get_userinfo(), $this);
29 // Load the template engine and tell her what template
30 // to use for the HTML it produces.
31 $this->TemplateEngine = new TemplateEngine($config);
33 // Preset item config - with Distribution and Release objects.
34 $items = array();
35 $items['root']['container'] = array('Distribution');
36 $items['root']['name'] = '/';
37 $items['root']['description'] = _('Root');
39 $items['Distribution']['container'] = array('Release');
40 $items['Distribution']['name'] = 'Distribution';
41 $items['Distribution']['description'] = _('Distribution');
42 $items['Distribution']['options']['name']['description'] = _("Name");
43 $items['Distribution']['options']['name']['default'] = "";
44 $items['Distribution']['options']['name']['value'] = "";
45 $items['Distribution']['options']['name']['required'] = true;
46 $items['Distribution']['options']['name']['type'] = 'string';
47 $items['Distribution']['options']['name']['display'] = _('Name');
48 $items['Distribution']['options']['type']['description'] = _("Distribution type");
49 $items['Distribution']['options']['type']['default'] = "deb";
50 $items['Distribution']['options']['type']['value'] = "deb";
51 $items['Distribution']['options']['type']['values'] = array("deb" => 'deb', "rpm" => 'rpm');
52 $items['Distribution']['options']['type']['required'] = true;
53 $items['Distribution']['options']['type']['type'] = 'combobox';
54 $items['Distribution']['options']['type']['display'] = _('Distribution type');
56 $items['Release']['container'] = array('Release', '__CFG_ITEMS__');
57 $items['Release']['name'] = 'Release';
58 $items['Release']['description'] = _('Release');
59 $items['Release']['options']['name']['description'] = _("Name");
60 $items['Release']['options']['name']['default'] = "";
61 $items['Release']['options']['name']['value'] = "";
62 $items['Release']['options']['name']['required'] = true;
63 $items['Release']['options']['name']['type'] = 'string';
64 $items['Release']['options']['name']['display'] = _('Name');
66 $this->installationMethods = array();
67 $this->installationMethods['root']['description'] = _('root');
68 $this->installationMethods['root']['name'] = 'root';
69 $this->installationMethods['root']['title'] = _('root');
70 $this->installationMethods['root']['items']['Distribution'] = &$items['Distribution'];
71 $this->installationMethods['root']['items']['Release'] = &$items['Release'];
72 $this->installationMethods['root']['items']['root'] = &$items['root'];
74 // Request an update of the data model
75 $this->loadInstallationMethods();
76 $this->updateDataModel();
77 $this->listing->setListingTypes($this->getListingTypes());
78 }
81 /*! \brief Intializes this plugin
82 * All available installation methods will be loaded
83 */
84 function loadInstallationMethods()
85 {
86 // Reset erros
87 $this->rpcError = $this->initFailed = FALSE;
89 // Load configuration via rpc.
90 $rpc = $this->config->getRpcHandle();
91 $res = $rpc->getSupportedInstallMethods();
92 if(!$rpc->success()){
93 $this->rpcError = TRUE;
94 $this->errorMessage = $rpc->get_error();;
95 return;
96 }
98 // Populate install methods on success.
99 if(!count($res)){
100 $this->errorMessage = _("No selectable install methods returned!");
101 msg_dialog::display(_("Setup"), $this->errorMessage , ERROR_DIALOG);
102 $this->initFailed = TRUE;
103 return;
104 }else{
106 // Merge result with hard coded methods
107 $this->installationMethods = array_merge($this->installationMethods, $res);
109 // Walk through entries and create useful mappings.
110 $this->cfgItemMap = array();
111 $this->itemConfig = array();
112 $this->itemsPerMethod = array();
113 $rootElements = array();
114 foreach($this->installationMethods as $method => $items){
115 foreach($items['items'] as $itemName => $item){
116 $this->itemsPerMethod[$method][] = $itemName;
117 $this->cfgItemMap[$itemName] = $method;
118 $this->itemConfig[$itemName] = &$this->installationMethods[$method]['items'][$itemName];
120 // This enables us to create the first level of config items when
121 // a release is selected.
122 if($item['name'] == "/" && $itemName != 'root'){
123 $rootElements = array_merge($rootElements, $item['container']);
124 }
125 }
126 }
128 // Merge in root elements to releases.
129 foreach($this->itemConfig as $item => $data){
130 if(in_array('__CFG_ITEMS__', $data['container'])){
131 $this->itemConfig[$item]['container'] = array_merge($this->itemConfig[$item]['container'], $rootElements );
132 }
133 }
134 }
135 }
138 /*! \brief Updates all distributions, releases, packages and items in the dataModel
139 * Load information from the backend.
140 */
141 function updateDataModel()
142 {
143 // Recreate the data model, to have a clean and fresh instance.
144 $this->dataModel = new ConfigManagementDataModel();
146 // Load distributions
147 $rpc = $this->config->getRpcHandle();
148 $res = $rpc->getDistributions();
149 if(!$rpc->success()){
150 msg_dialog::display(_("Error"), sprintf(_("Failed to load distributions: %s"), $rpc->get_error()),ERROR_DIALOG);
151 return(NULL);
152 }else{
153 foreach($res as $dist){
154 $this->dataModel->addItem('Distribution','/root', $dist['name'], $dist);
155 if(isset($dist['releases'])){
156 foreach($dist['releases'] as $release){
157 $distPath = "/root/{$dist['name']}";
158 $this->dataModel->addItem('Release',$distPath, $release['name'], $release);
159 }
160 }
161 }
162 }
163 }
166 /*! \brief Keep track of posted values and populate those
167 * which are interesting for us.
168 * Inspects the _POST and _GET values.
169 */
170 function save_object()
171 {
172 // Update the listing class, this is necessary to get post
173 // actions from it.
174 $this->listing->save_object();
176 // Get the selected distribution and release from the listing widget.
177 $cont = $this->listing->getSelectedContainer();
178 if(isset($_POST['ROOT'])){
179 $this->setCurrentContainer('/root');
180 }elseif(isset($_POST['BACK'])){
181 $path = $this->selectedContainer;
182 if($this->dataModel->itemExistsByPath($path)){
183 $data = $this->dataModel->getItemByPath($path);
184 if($data['parentPath']){
185 $this->setCurrentContainer($data['parentPath']);
186 }
187 }
188 }else{
189 $this->setCurrentContainer($cont);
190 }
191 }
194 /*! \brief Load extended sub-objecte like 'config items' or 'packages'
195 * for the given release path.
196 * @param String The release path to load sub-objects for.
197 * @return NULL
198 */
199 function updateItemList($path)
200 {
201 // Fist get Item and check if it is an release
202 if($this->dataModel->itemExistsByPath($path)){
203 $data = $this->dataModel->getItemByPath($path);
205 // Only releases can contain config-items.
206 if($data['type'] == 'Release' && $data['status'] != "fetched"){
209 // Request all config items for the selected release via rpc.
210 $rpc = $this->config->getRpcHandle();
211 $res = $rpc->listConfigItems($data['name']);
212 if(!$rpc->success()){
213 msg_dialog::display(_("Error"),sprintf(_("Failed to load distributions: %s"),$rpc->get_error()),ERROR_DIALOG);
214 }else{
216 // Sort entries by path length
217 $sLen = array();
218 foreach($res as $itemPath => $type){
219 $sLen[strlen($itemPath)."_".$itemPath] = $itemPath;
220 }
221 uksort($sLen, "strnatcasecmp");
223 // Walk through each entry and then try to add it to the model
224 foreach($sLen as $unused => $itemPath){
226 // Do not add the root element '/'
227 if($itemPath == "/") continue;
229 $type = $res[$itemPath];
231 // Append the items-path to the current path to create the
232 // effective item path in the data model.
233 $targetPath = trim($path."/".$itemPath);
235 // Remove trailing and duplicated slashes
236 $targetPath = rtrim($targetPath, '/');
237 $targetPath = preg_replace("/\/\/*/","/", $targetPath);
239 // Extract the items name
240 $name = preg_replace("/^.*\//","", $targetPath);
242 // Cleanup the path and then add the item.
243 $targetPath = preg_replace("/[^\/]*$/","", $targetPath);
244 $targetPath = rtrim($targetPath,'/');
245 $this->dataModel->addItem($type, $targetPath, $name,array(),'-' );
246 }
247 $this->dataModel->setItemStatus($path, 'fetched');
248 }
249 }
250 }
251 }
254 /*! \brief Sets the currently selected container and item path.
255 * @param String The path of the container to set.
256 * @param String The path of the item to set.
257 * @return
258 */
259 function setCurrentContainer($cont)
260 {
261 $this->selectedContainer = $cont;
263 // Update list of items within the selected container.
264 $this->updateItemList($this->selectedContainer);
266 // Transfer checked values back to the listing class.
267 $this->listing->setContainers($this->getContainerList());
268 $this->listing->setContainer($cont);
270 // Update the list of addable sub objects
271 $this->addableContainerItems = $this->getAddableContainersPerPath($cont);
272 }
275 function getAddableContainersPerPath($path)
276 {
277 $currentItem = $this->dataModel->getItemByPath($path);
278 $method = $this->getInstallationMethodPerPath($path);
280 // Get allowed items for the currently selected method
281 // merge in root elements, they are allowed everywhere.
282 $allowedItems = $this->itemsPerMethod[$method];
283 $allowedItems = array_merge($allowedItems, $this->itemsPerMethod['root']);
285 // Get addable items
286 $possibleItems = $this->itemConfig[$currentItem['type']]['container'];
287 return(array_unique(array_intersect($allowedItems, $possibleItems)));
288 }
291 function getInstallationMethodPerPath($path)
292 {
293 $path .= '/';
294 while(preg_match("/\//", $path)){
295 $path = preg_replace("/\/[^\/]*$/","",$path);
296 $item = $this->dataModel->getItemByPath($path);
297 if(isset($item['values']['installation_method'])){
298 return($item['values']['installation_method']);
299 }
300 }
301 return('root');
302 }
305 /*! \brief Generate the HTML content for this plugin.
306 * Actually renders the listing widget..
307 */
308 function execute()
309 {
310 // Get the selected release and store it in a session variable
311 // to allow the configFilter to access it and display the
312 // packages and items.
313 $res = $this->listing->execute();
314 $this->listing->setListingTypes($this->getListingTypes());
315 return($res);
316 }
319 /*! \brief Returns a list of items which will then be displayed
320 * in the management-list.
321 * (The management class calls this method from its execute())
322 * @return Array A list of items/objects for the listing.
323 */
324 function getItemsToBeDisplayed()
325 {
326 $path = $this->selectedContainer;
327 $item = $this->dataModel->getItemByPath($path);
328 return($item);
329 }
332 /*! \brief Returns a simply list of all distributions.
333 * This list will then be used to generate the entries of the
334 * ItemSelectors in the listing class.
335 */
336 function getContainerList()
337 {
338 $data = $this->dataModel->getItemByPath('/root');
339 $res = array();
340 $res["/root"] = array("name" => "/", "desc" => "");
341 $res = array_merge($res,$this->__recurseItem($data));
342 return($res);
343 }
346 /*! \brief Recursivly wlks through an item and collects all path and name info.
347 * The reult can then be used to fill the ItemSelector.
348 * @param Array The Item to recurse.
349 * @param Array The type of of objects to collect.
350 * @param String The parent path prefix which should be removed.
351 * @return Array An array containing Array[path] = name
352 */
353 function __recurseItem($item, $parent = "")
354 {
355 $res = array();
356 $path = preg_replace("/".preg_quote($parent,'/')."/","",$item['path']);
357 $res[$path] = array('name' => $item['name'],'desc'=>$item['type']);
358 if(count($item['children'])){
359 foreach($item['children'] as $child){
360 $res = array_merge($res, $this->__recurseItem($child, $parent));
361 }
362 }
363 return($res);
364 }
367 /*! \brief Returns a info list about all items we can manage,
368 * this used to fill the listings <objectType> settings.
369 * @return Array An array with item info.
370 */
371 function getListingTypes()
372 {
373 $types= array();
374 $types['Distribution']['objectClass'] = 'Distribution';
375 $types['Distribution']['label'] = _('Distribution');
376 $types['Distribution']['image'] = 'images/lists/edit.png';
377 $types['Distribution']['category'] = 'Device';
378 $types['Distribution']['class'] = 'Device';
380 $types['Release']['objectClass'] = 'Release';
381 $types['Release']['label'] = _('Release');
382 $types['Release']['image'] = 'images/lists/delete.png';
383 $types['Release']['category'] = 'Device';
384 $types['Release']['class'] = 'Device';
386 $types['Component']['objectClass'] = 'Component';
387 $types['Component']['label'] = _('Component');
388 $types['Component']['image'] = 'plugins/users/images/select_user.png';
389 $types['Component']['category'] = 'Device';
390 $types['Component']['class'] = 'Device';
392 foreach($this->installationMethods as $method => $items){
393 foreach($items['items'] as $itemName => $item){
394 $types[$itemName]['objectClass'] = $itemName;
395 $types[$itemName]['label'] = $item['name'];
396 $types[$itemName]['image'] = 'plugins/fai/images/fai_script.png';
397 $types[$itemName]['category'] = 'Device';
398 $types[$itemName]['class'] = 'Device';
399 }
400 }
402 return($types);
403 }
406 /*! \brief The plugins ACL and plugin-property definition.
407 * @return
408 */
409 public static function plInfo()
410 {
411 return (array(
412 "plShortName" => _("Config management"),
413 "plDescription" => _("Config management"),
414 "plSelfModify" => FALSE,
415 "plDepends" => array(),
416 "plPriority" => 0,
417 "plSection" => array("administration"),
418 "plCategory" => array(
419 "newConfigManagement" => array("description" => _("Config management"),
420 "objectClass" => "FAKE_OC_newConfigManagement")),
421 "plProvidedAcls"=> array()
422 ));
423 }
426 /*! \brief Acts on open requests.
427 * (This action is received from the ConfigManagementListing class.)
428 * @param Array The items ids. (May contain multiple ids)
429 * @return
430 */
431 function openEntry($ids)
432 {
433 $id = $ids[0];
434 $item = $this->dataModel->getItemById($id);
435 $this->setCurrentContainer($item['path']);
436 return;
437 }
441 /*! \brief Removes an entry from the listing.
442 */
443 function removeEntry($ids)
444 {
445 foreach($ids as $id){
446 $item = $this->dataModel->getItemById($id);
448 // Is an config item.
449 if($this->cfgItemMap[$item['type']] != 'root'){
450 $release = preg_replace("/^.*\//","", $this->getReleasePath($item['path']));
451 $path = $this->getItemPath($item['path']);
453 $rpc = $this->config->getRpcHandle();
454 $rpc->removeConfigItem($release, $path);
455 if(!$rpc->success()){
456 msg_dialog::display(_("Error"), sprintf(_("Failed to remove: %s"), $rpc->get_error()),ERROR_DIALOG);
457 return(NULL);
458 }else{
459 $this->dataModel->removeItem($item['path']);
460 }
461 }else{
462 echo $item['type']." - are not handled yet!";
463 }
464 }
465 }
468 /*! \brief Edits a selected list item.
469 */
470 function editEntry($ids)
471 {
472 $item = $this->dataModel->getItemById($ids[0]);
473 $release = preg_replace("/^.*\//","", $this->getReleasePath($item['path']));
474 $path = $this->getItemPath($item['path']);
475 $method = $this->cfgItemMap[$item['type']];
477 // Load item values on demand
478 if($this->cfgItemMap[$item['type']] != 'root'){
479 if($item['status'] == '-'){
480 $rpc = $this->config->getRpcHandle();
481 $item['values'] = $rpc->getConfigItem($release, $path);
482 $this->dataModel->setItemStatus($item['path'], 'fetched');
483 $this->dataModel->setItemValues($item['path'], $item['values']);
484 }
485 }
487 $this->TemplateEngine->load($this->itemConfig);
488 $this->TemplateEngine->setTemplate($method.".tpl");
489 $this->TemplateEngine->setValues($item['type'],$item['values']);
490 $this->listing->setDialogObject($this->TemplateEngine);
491 $this->currentObject = $item;
492 }
495 /*! \brief Initiates the creation of a new item
496 */
497 function newEntry($type)
498 {
499 // We've to add a config item
500 $this->TemplateEngine->load($this->itemConfig);
501 if($this->cfgItemMap[$type] != 'root'){
502 $method = $this->cfgItemMap[$type];
503 $this->TemplateEngine->setTemplate($method.".tpl");
504 $this->TemplateEngine->setValues($type,array());
505 $this->listing->setDialogObject($this->TemplateEngine);
506 $this->currentObject = NULL;
507 }else{
508 $this->TemplateEngine->setTemplate("root.tpl");
509 $this->TemplateEngine->setValues($type,array());
510 $this->listing->setDialogObject($this->TemplateEngine);
511 $this->currentObject = NULL;
512 }
513 }
516 /*! \brief Extracts the item-path out of a path.
517 * e.g. /debian/squeeze/test/module -> /test/module
518 */
519 function getItemPath($fullPath)
520 {
521 $fPath = $fullPath.'/';
522 while(preg_match("/\//", $fPath)){
523 $fPath = preg_replace("/\/[^\/]*$/","", $fPath);
524 $item = $this->dataModel->getItemByPath($fPath);
525 if(in_array($item['type'], array('Release', 'Distribution', 'root'))){
526 return(preg_replace("/".preg_quote($item['path'],'/')."/", "", $fullPath));
527 }
528 }
529 return(NULL);
530 }
533 /*! \brief Extracts the releaes path out of a path.
534 * e.g. /debian/squeeze/test/module -> /debian/squeeze
535 */
536 function getReleasePath($fullPath)
537 {
538 $fullPath.='/';
539 while(preg_match("/\//", $fullPath)){
540 $fullPath = preg_replace("/\/[^\/]*$/","", $fullPath);
541 $item = $this->dataModel->getItemByPath($fullPath);
542 if($item['type'] == 'Release'){
543 return($fullPath);
544 }
545 }
546 return(NULL);
547 }
550 function saveItemChanges()
551 {
552 $item = $this->currentObject;
553 $type = $this->TemplateEngine->getItemType();
554 if($this->cfgItemMap[$type] == 'root'){
555 echo "{$type} Cannot be saved yet";
556 $this->listing->clearDialogObject();
557 return;
558 }
560 if($this->cfgItemMap[$type] != 'root'){
562 // Save template engine modifications
563 $this->TemplateEngine->save_object();
564 $release = preg_replace("/^.*\//","", $this->getReleasePath($this->selectedContainer));
566 // Get values to be saved
567 $values = array();
568 foreach($this->TemplateEngine->getWidgets() as $w){
569 $values[$w->getName()] = $w->getValue();
570 }
572 // Get paths
573 $newPath = $this->selectedContainer."/".$values['name'];
574 $newItemPath = $this->getItemPath($this->selectedContainer)."/".$values['name'];
575 if($item){
576 $oldPath = $item['path'];
577 $oldItemPath = $this->getItemPath($item['path']);
578 }
580 // If this is a new item, then create it now.
581 if($item == NULL){
583 // Add the new item
584 $rpc = $this->config->getRpcHandle();
585 $res = $rpc->setConfigItem($release, $newItemPath, $type, $values);
586 if(!$rpc->success()){
587 msg_dialog::display(_("Error"), sprintf(_("Failed to load distributions: %s"), $rpc->get_error()),ERROR_DIALOG);
588 return(NULL);
589 }else{
591 // We've successfully added the item, now add it to the tree.
592 $this->dataModel->addItem($type, $this->selectedContainer, $values['name'],array(), '-' );
594 // Finally - close the dialog.
595 $this->listing->clearDialogObject();
596 }
597 }else{
599 // Write the modifications back to the server.
600 $rpc = $this->config->getRpcHandle();
601 $res = $rpc->setConfigItem($release, $oldItemPath, $type, $values);
602 if(!$rpc->success()){
603 msg_dialog::display(_("Error"), sprintf(_("Failed to load distributions: %s"), $rpc->get_error()),ERROR_DIALOG);
604 return(NULL);
605 }else{
607 // Update the data model
608 $item['values'] = $values;
610 $this->dataModel->setItemValues($item['path'], $item['values']);
611 $this->dataModel->moveItem($oldPath, $newPath);
613 print_a($this);
615 $this->listing->clearDialogObject();
616 }
617 }
618 }
619 }
620 function remove_lock() {}
621 }
624 ?>