1 <?php
3 define("DEBUG_FAI_FUNC",FALSE);
5 /* TEST PHASE .... */
7 /* Returns all object for the given release.
8 This function resolves the releases
9 from base up to the given dn.
10 */
11 function get_all_objects_for_given_base($Current_DN,$filter,$detailed = false)
12 {
13 global $config;
14 $ldap = $config->get_ldap_link();
15 $ldap->cd($config->current['BASE']);
17 /* Collect some basic informations and initialize some variables */
18 $base_release = get_release_dn($Current_DN);
19 $previous_releases = array_reverse(get_previous_releases_of_this_release($base_release,true));
20 $res = array();
21 $tmp = array();
23 /* We must also include the given release dn */
24 $previous_releases[] = $base_release;
26 /* Walk through all releases */
27 foreach($previous_releases as $release){
29 /* Get fai departments */
30 $deps_to_search = get_FAI_departments($release);
32 /* For every single department (ou=hoos,ou ..) */
33 foreach($deps_to_search as $fai_base){
35 /* Ldap search for fai classes specified in this release */
36 $ldap->cd($fai_base);
37 $ldap->search($filter,array("dn","objectClass","FAIstate"));
39 /* check the returned objects, and add/replace them in our return variable */
40 while($attr = $ldap->fetch()){
42 $buffer = array();
43 $name = str_ireplace($release,"",$attr['dn']);
45 if(isset($attr['FAIstate'][0])){
46 if(preg_match("/removed$/",$attr['FAIstate'][0])){
47 if(isset($res[$name])){
48 unset($res[$name]);
49 }
50 continue;
51 }
52 }
55 /* In detailed mode are some additonal informations visible */
56 if($detailed){
58 /* Create list of parents */
59 if(isset($res[$name])){
60 $buffer = $res[$name];
61 $buffer['parents'][] = $res[$name]['dn'];
62 }else{
63 $buffer['parents'] = array();
64 }
66 /* Append objectClass to resulsts */
67 $buffer['objectClass'] = $attr['objectClass'];
68 unset($buffer['objectClass'][0]);
69 }
71 /* Add this object to our list */
72 $buffer['dn'] = $attr['dn'];
73 $res[$name] = $buffer;
74 }
75 }
76 }
77 return($res);
78 }
82 /* Return the object defining ObjectClass e.g. FAIscriptEntry */
83 function get_FAI_type($attr)
84 {
85 $arr = array( "FAIprofile","FAIpartitionTable", "FAIpartitionDisk","FAIpartitionEntry","FAIhook","FAIhookEntry",
86 "FAIscriptEntry","FAIscript","FAIvariable","FAIvariableEntry","FAIpackageList","FAItemplate",
87 "FAItemplateEntry","FAIdebconfInfo","FAIrepository","FAIrepositoryServer","FAIbranch","FAIreleaseTag");
88 foreach($arr as $name){
89 if(in_array($name,$attr['objectClass'])){
90 preg_match("");
91 return($name);
92 }
93 }
94 if(DEBUG_FAI_FUNC) { echo "Not found"; }
95 return("");
96 }
99 /* Return all relevant FAI departments */
100 function get_FAI_departments($suffix = "")
101 {
102 $arr = array("hooks","scripts","disk","packages","profiles","templates","variables");
103 $tmp = array();
104 if(preg_match("/^,/",$suffix)){
105 $suffix = preg_replace("/^,/","",$suffix);
106 }
107 foreach($arr as $name){
108 if(empty($suffix)){
109 $tmp[$name] = "ou=".$name;
110 }else{
111 $tmp[$name] = "ou=".$name.",".$suffix;
112 }
113 }
114 return($tmp);
115 }
118 /* Return all releases within the given base */
119 function get_all_releases_from_base($dn)
120 {
121 global $config;
122 $base = "ou=fai,ou=configs,ou=systems,".$dn;
123 $res = array();
125 $ldap = $config->get_ldap_link();
126 $ldap->cd($base);
127 $ldap->search("(objectClass=FAIbranch)",array("ou","dn"));
128 while($attrs = $ldap->fetch()){
129 $res[$attrs['dn']] = $attrs['ou'][0];
130 }
131 return($res);
132 }
135 /* Add this object to list of objects, that must be checked for release saving */
136 function prepare_to_save_FAI_object($Current_DN,$objectAttrs,$removed = false)
137 {
138 /* Get ldap object */
139 global $config;
140 $addObj['Current_DN'] = $Current_DN;
141 $addObj['objectAttrs']= $objectAttrs;
142 $addObj['removed'] = $removed;
143 $addObj['diff'] = TRUE;
145 if(!$removed){
146 $ldap = $config->get_ldap_link();
147 $ldap->cd($config->current['BASE']);
149 /* Get some basic informations */
150 $parent_obj = get_parent_release_object($Current_DN);
151 $ldap->cat($parent_obj,array("*"));
152 $attrs = prepare_ldap_fetch_to_be_saved($ldap->fetch());
154 if(!array_diff_FAI( $attrs,$objectAttrs)){
155 $addObj['diff'] = FALSE;
156 }
157 }
159 $_SESSION['FAI_objects_to_save'][$Current_DN] = $addObj;
160 }
163 /* Detect differences in attribute arrays */
164 function array_diff_FAI($ar1,$ar2)
165 {
166 foreach($ar1 as $key1 => $val1){
168 if((is_array($val1)) && (count($val1)==1)){
169 $ar1[$key1] = $val1[0];
170 }
172 if((is_array($ar2[$key1])) && (count($ar2[$key1])==1)){
173 $val1 = $val1[0];
174 $ar2[$key1] = $ar2[$key1][0];
175 }
176 }
177 if(count( array_diff($ar1,$ar2))){
178 return(true);
179 }else{
180 return(false);
181 }
182 }
185 /* check which objects must be saved, and save them */
186 function save_release_changes_now()
187 {
188 /* Variable init*/
189 $to_save = array();
191 /* check which attributes must realy be saved */
192 foreach($_SESSION['FAI_objects_to_save'] as $Current_DN => $object){
193 if($object['diff']){
194 $sub_name = $Current_DN;
195 while(isset($_SESSION['FAI_objects_to_save'][$sub_name])){
197 $to_save[strlen($sub_name)] = $_SESSION['FAI_objects_to_save'][$sub_name];
198 unset($_SESSION['FAI_objects_to_save'][$sub_name]);
199 $sub_name = preg_replace('/^[^,]+,/', '', $sub_name);
200 }
201 }
202 }
204 /* Sort list of objects that must be saved, and ensure that
205 container objects are safed, before their childs are saved */
206 ksort($to_save);
208 /* Save objects and manage the correct release behavior*/
209 foreach($to_save as $save){
211 $Current_DN = $save['Current_DN'];
212 $removed = $save['removed'];
213 $objectAttrs= $save['objectAttrs'];
215 /* Get ldap object */
216 global $config;
217 $ldap = $config->get_ldap_link();
218 $ldap->cd($config->current['BASE']);
220 /* Get some basic informations */
221 $base_release = get_release_dn($Current_DN);
222 $sub_releases = get_sub_releases_of_this_release($base_release,true);
223 $parent_obj = get_parent_release_object($Current_DN);
224 $following_releases = get_sub_releases_of_this_release($base_release,true);
226 /* Check if given dn exists or if is a new entry */
227 $ldap->cat($Current_DN);
228 if(!$ldap->count()){
229 $is_new = true;
230 }else{
231 $is_new = false;
232 }
234 /* if parameter removed is true, we have to add FAIstate to the current attrs
235 FAIstate should end with ...|removed after this operation */
236 if($removed ){
237 $ldap->cat($Current_DN);
239 /* Get current object, because we must add the FAIstate ...|removed */
240 if((!$ldap->count()) && !empty($parent_obj)){
241 $ldap->cat($parent_obj);
242 }
244 /* Check if we have found a suiteable object */
245 if(!$ldap->count()){
246 echo "Error can't remove this object ".$Current_DN;
247 return;
248 }else{
250 /* Set FAIstate to current objectAttrs */
251 $objectAttrs = prepare_ldap_fetch_to_be_saved($ldap->fetch());
252 if(isset($objectAttrs['FAIstate'][0])){
253 if(!preg_match("/removed$/",$objectAttrs['FAIstate'][0])){
254 $objectAttrs['FAIstate'][0] .= "|removed";
255 }
256 }else{
257 $objectAttrs['FAIstate'][0] = "|removed";
258 }
259 }
260 }
263 /* Check if this a leaf release or not */
264 if(count($following_releases) == 0 ){
266 /* This is a leaf object. It isn't unherited by any other object */
267 if(DEBUG_FAI_FUNC) {
268 echo "<b>Saving directly, is a leaf object</b><br> ".$Current_DN;
269 print_a($objectAttrs);
270 }
271 save_FAI_object($Current_DN,$objectAttrs);
272 }else{
274 /* This object is inherited by some sub releases */
276 /* Get all releases, that inherit this object */
277 $r = get_following_releases_that_inherit_this_object($Current_DN);
279 /* Get parent object */
280 $ldap->cat($parent_obj);
281 $parent_attrs = prepare_ldap_fetch_to_be_saved($ldap->fetch());
283 /* New objects require special handling */
284 if($is_new){
286 /* check if there is already an entry named like this,
287 in one of our parent releases */
288 if(!empty($parent_obj)){
289 if(DEBUG_FAI_FUNC) {
290 echo "There is already an entry named like this.</b><br>";
292 echo "<b>Saving main object</b>".$Current_DN;
293 print_a($objectAttrs);
294 }
295 save_FAI_object($Current_DN,$objectAttrs);
297 foreach($r as $key){
298 if(DEBUG_FAI_FUNC) {
299 echo "<b>Saving parent to following release</b> ".$key;
300 print_a($parent_attrs);
301 }
302 save_FAI_object($key,$parent_attrs);
303 }
304 }else{
306 if(DEBUG_FAI_FUNC) {
307 echo "<b>Saving main object</b>".$Current_DN;
308 print_a($objectAttrs);
309 }
310 save_FAI_object($Current_DN,$objectAttrs);
312 if(isset($objectAttrs['FAIstate'])){
313 $objectAttrs['FAIstate'] .= "|removed";
314 }else{
315 $objectAttrs['FAIstate'] = "|removed";
316 }
318 foreach($r as $key ){
319 if(DEBUG_FAI_FUNC) {
320 echo "<b>Create an empty placeholder in follwing release</b> ".$key;
321 print_a($objectAttrs);
322 }
323 save_FAI_object($key,$objectAttrs);
324 }
325 }
326 }else{
328 /* check if we must patch the follwing release */
329 if(!empty($r)){
330 foreach($r as $key ){
331 if(DEBUG_FAI_FUNC) {
332 echo "<b>Copy current objects original attributes to next release</b> ".$key;
333 print_a($parent_attrs);
334 }
335 save_FAI_object($key,$parent_attrs);
336 }
337 }
339 if(DEBUG_FAI_FUNC) {
340 echo "<b>Saving current object</b>".$parent_obj;
341 print_a($objectAttrs);
342 }
343 save_FAI_object($parent_obj,$objectAttrs);
345 if(($parent_obj != $Current_DN)){
346 print_red(sprintf(_("Error, following objects should be equal '%s' and '%s'"),$parent_obj,$Current_DN));
347 }
348 }
349 }
350 }
351 $_SESSION['FAI_objects_to_save'] = array();
352 }
355 /* this function will remove all unused (deleted) objects,
356 that have no parent object */
357 function clean_up_releases($Current_DN)
358 {
359 global $config;
360 $ldap = $config->get_ldap_link();
361 $ldap->cd($config->current['BASE']);
363 /* Collect some basic informations and initialize some variables */
364 $base_release = get_release_dn($Current_DN);
365 $previous_releases = array_reverse(get_previous_releases_of_this_release($base_release,true));
366 $Kill = array();
367 $Skip = array();
369 /* We must also include the given release dn */
370 $previous_releases[] = $base_release;
372 /* Walk through all releases */
373 foreach($previous_releases as $release){
375 /* Get fai departments */
376 $deps_to_search = get_FAI_departments($release);
378 /* For every single department (ou=hoos,ou ..) */
379 foreach($deps_to_search as $fai_base){
381 /* Ldap search for fai classes specified in this release */
382 $ldap->cd($fai_base);
383 $ldap->search("(objectClass=FAIclass)",array("dn","objectClass","FAIstate"));
385 /* check the returned objects, and add/replace them in our return variable */
386 while($attr = $ldap->fetch()){
388 $buffer = array();
389 $name = str_ireplace($release,"",$attr['dn']);
391 if(isset($attr['FAIstate'][0])&&(preg_match("/removed$/",$attr['FAIstate'][0]))){
393 /* Check if this object is required somehow */
394 if(!isset($Skip[$name])){
395 $Kill[$attr['dn']] = $attr['dn'];
396 }
397 }else{
399 /* This object is required (not removed), so do not
400 delete any following sub releases of this object */
401 $Skip[$name] = $attr['dn'];
402 }
403 }
404 }
405 }
406 return($Kill);
407 }
410 function prepare_ldap_fetch_to_be_saved($attrs)
411 {
412 foreach($attrs as $key => $value){
413 if(is_numeric($key) || ($key == "count") || ($key == "dn")){
414 unset($attrs[$key]);
415 }
416 if(is_array($value) && isset($value['count'])){
417 unset($attrs[$key]['count']);
418 }
419 }
420 return($attrs);
421 }
424 function save_FAI_object($dn,$attrs)
425 {
426 print_a(array($dn,$attrs));
427 global $config;
428 $ldap = $config->get_ldap_link();
429 $ldap->cd($config->current['BASE']);
430 $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dn));
431 $ldap->cd($dn);
433 $ldap->cat($dn,array("dn"));
434 if($ldap->count()){
435 $ldap->modify($attrs);
436 }else{
437 $ldap->add($attrs);
438 }
439 show_ldap_error($ldap->get_error(),sprintf(_("Release management failed, can't save '%s'"),$dn));
440 }
443 function get_following_releases_that_inherit_this_object($dn)
444 {
445 global $config;
446 $ldap = $config->get_ldap_link();
447 $ldap->cd($config->current['BASE']);
449 $ret = array();
451 /* Get base release */
452 $base_release = get_release_dn($dn);
454 /* Get previous release dns */
455 $sub_releases = get_sub_releases_of_this_release($base_release);
457 /* Get dn suffix. Example "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
458 $dn_suffix = str_ireplace($base_release,"",$dn);
460 /* Check if given object also exists whitin one of these releases */
461 foreach($sub_releases as $p_release => $name){
463 $check_dn = $dn_suffix.$p_release;
465 $ldap->cat($check_dn,array("dn","objectClass"));
467 if($ldap->count()){
468 //return($ret);
469 }else{
470 $ret[$check_dn]=$check_dn;
471 }
472 }
473 return($ret);
474 }
477 /* Get previous version of the object dn */
478 function get_parent_release_object($dn,$include_myself=true)
479 {
480 global $config;
481 $ldap = $config->get_ldap_link();
482 $ldap->cd($config->current['BASE']);
483 $previous_releases= array();
485 /* Get base release */
486 $base_release = get_release_dn($dn);
487 if($include_myself){
488 $previous_releases[] = $base_release;
489 }
491 /* Get previous release dns */
492 $tmp = get_previous_releases_of_this_release($base_release,true);
493 foreach($tmp as $release){
494 $previous_releases[] = $release;
495 }
497 /* Get dn suffix. Example "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
498 $dn_suffix = str_ireplace($base_release,"",$dn);
500 /* Check if given object also exists whitin one of these releases */
501 foreach($previous_releases as $p_release){
502 $check_dn = $dn_suffix.$p_release;
503 $ldap->cat($check_dn,array("dn","objectClass"));
505 if($ldap->count()){
506 return($check_dn);
507 }
508 }
509 return("");
510 }
513 /* return release names of all parent releases */
514 function get_previous_releases_of_this_release($dn,$flat)
515 {
516 global $config;
517 $ldap = $config->get_ldap_link();
518 $ldap->cd($config->current['BASE']);
519 $ret = array();
521 /* Explode dns into pieces, to be able to build parent dns */
522 $dns_to_check = ldap_explode_dn(str_ireplace(",".$config->current['BASE'],"",$dn),0);
523 if(!is_array($dns_to_check)){
524 return;
525 }
527 /* Unset first entry which represents the given dn */
528 unset($dns_to_check['count']);
529 unset($dns_to_check[key($dns_to_check)]);
531 /* Create dns addresses and check if this dn is a release dn */
532 $id = 0;
533 while(count($dns_to_check)){
535 /* build parent dn */
536 $new_dn = "";
537 foreach($dns_to_check as $part){
538 $new_dn .= $part.",";
539 }
540 $new_dn .= $config->current['BASE'];
542 /* check if this dn is a release */
543 if(is_release_department($new_dn)){
544 if($flat){
545 $ret[$id] = $new_dn;
546 }else{
547 $ret = array($new_dn=>$ret);
548 }
549 $id ++;
550 }else{
551 return($ret);
552 }
553 reset($dns_to_check);
554 unset($dns_to_check[key($dns_to_check)]);
555 }
556 return($ret);
557 }
560 /* This function returns all sub release names, recursivly */
561 function get_sub_releases_of_this_release($dn,$flat = false)
562 {
563 global $config;
564 $res = array();
565 $ldap = $config->get_ldap_link();
566 $ldap->cd($config->current['BASE']);
567 $ldap->ls("(objectClass=FAIbranch)",$dn,array("objectClass","dn","ou"));
568 while($attr = $ldap->fetch()){
570 /* Append department name */
571 if($flat){
572 $res[$attr['dn']] = $attr['ou'][0];
573 }else{
574 $res[$attr['dn']] = array();
575 }
577 /* Get sub release departments of this department */
578 if(in_array("FAIbranch",$attr['objectClass'])) {
579 if($flat){
580 $tmp = get_sub_releases_of_this_release($attr['dn'],$flat);
581 foreach($tmp as $dn => $value){
582 $res[$dn]=$value;
583 }
584 }else{
585 $res[$attr['dn']] = get_sub_releases_of_this_release($attr['dn']);
586 }
587 }
588 }
589 return($res);
590 }
593 /* Check if the given department is a release department */
594 function is_release_department($dn)
595 {
596 global $config;
597 $ldap = $config->get_ldap_link();
598 $ldap->cd($config->current['BASE']);
599 $ldap->cat($dn,array("objectClass","ou"));
601 /* Check objectClasses and name to check if this is a release department */
602 if($ldap->count()){
603 $attrs = $ldap->fetch();
605 $ou = "";
606 if(isset($attrs['ou'][0])){
607 $ou = $attrs['ou'][0];
608 }
610 if((in_array("FAIbranch",$attrs['objectClass'])) || ($ou == "fai")){
611 return($attrs['dn']);
612 }
613 }
614 return(false);
615 }
618 /* This function returns the dn of the object release */
619 function get_release_dn($Current_DN)
620 {
621 global $config;
622 $ldap = $config->get_ldap_link();
623 $ldap->cd($config->current['BASE']);
625 /* Split dn into pices */
626 $dns_to_check = ldap_explode_dn(str_ireplace(",".$config->current['BASE'],"",$Current_DN),0);
627 if(!is_array($dns_to_check)){
628 return;
629 }
631 /* Use dn pieces, to create sub dns like
632 ou=test,ou=1,ou=0...
633 ou=1,ou=0...
634 ou=0...
635 To check which dn is our release container.
636 */
637 unset($dns_to_check['count']);
638 while(count($dns_to_check)){
640 /* Create dn */
641 $new_dn = "";
642 foreach($dns_to_check as $part){
643 $new_dn .= $part.",";
644 }
645 $new_dn .= $config->current['BASE'];
647 /* Check if this dn is a release dn */
648 if(is_release_department($new_dn)){
649 return($new_dn);
650 }
652 /* Remove first element of dn pieces */
653 reset($dns_to_check);
654 unset($dns_to_check[key($dns_to_check)]);
655 }
656 return("");
657 }
659 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
660 ?>