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 }
81 /* Return all relevant FAI departments */
82 function get_FAI_departments($suffix = "")
83 {
84 $arr = array("hooks","scripts","disk","packages","profiles","templates","variables");
85 $tmp = array();
86 if(preg_match("/^,/",$suffix)){
87 $suffix = preg_replace("/^,/","",$suffix);
88 }
89 foreach($arr as $name){
90 if(empty($suffix)){
91 $tmp[$name] = "ou=".$name;
92 }else{
93 $tmp[$name] = "ou=".$name.",".$suffix;
94 }
95 }
96 return($tmp);
97 }
100 /* Return all releases within the given base */
101 function get_all_releases_from_base($dn,$appendedName=false)
102 {
103 global $config;
105 if(!preg_match("/ou=fai,ou=configs,ou=systems,/",$dn)){
106 $base = "ou=fai,ou=configs,ou=systems,".$dn;
107 }else{
108 $base = $dn;
109 }
110 $res = array();
112 $ldap = $config->get_ldap_link();
113 $ldap->cd($base);
114 $ldap->search("(objectClass=FAIbranch)",array("ou","dn"));
115 while($attrs = $ldap->fetch()){
116 if($appendedName){
117 $res[$attrs['dn']] = convert_department_dn(preg_replace("/,ou=fai,ou=configs,ou=system.*$/","",$attrs['dn']));
118 }else{
119 $res[$attrs['dn']] = $attrs['ou'][0];
120 }
121 }
122 return($res);
123 }
126 /* Add this object to list of objects, that must be checked for release saving */
127 function prepare_to_save_FAI_object($Current_DN,$objectAttrs,$removed = false)
128 {
129 /* Get ldap object */
130 global $config;
131 $addObj['Current_DN'] = $Current_DN;
132 $addObj['objectAttrs']= $objectAttrs;
133 $addObj['removed'] = $removed;
134 $addObj['diff'] = TRUE;
136 if(!$removed){
137 $ldap = $config->get_ldap_link();
138 $ldap->cd($config->current['BASE']);
140 /* Get some basic informations */
141 $parent_obj = get_parent_release_object($Current_DN);
142 if(!empty($parent_obj)){
143 $ldap->cat($parent_obj,array("*"));
144 $attrs = prepare_ldap_fetch_to_be_saved($ldap->fetch());
146 if(!array_diff_FAI( $attrs,$objectAttrs)){
147 $addObj['diff'] = FALSE;
148 }
149 }
150 }
152 $_SESSION['FAI_objects_to_save'][$Current_DN] = $addObj;
153 }
156 /* Detect differences in attribute arrays */
157 function array_diff_FAI($ar1,$ar2)
158 {
160 if((!isset($ar1['description'])) || (isset($ar1['description']) && (count($ar1['description']) == 0))){
161 $ar1['description'] = "";
162 }
163 if((!isset($ar2['description'])) || (isset($ar2['description']) && (count($ar2['description']) == 0))){
164 $ar2['description'] = "";
165 }
167 if(count($ar1) != count($ar2)) {
168 return (true);
169 }
171 foreach($ar1 as $key1 => $val1){
173 if((is_array($val1)) && (count($val1)==1)){
174 $ar1[$key1] = $val1[0];
175 }
177 if((is_array($ar2[$key1])) && (count($ar2[$key1])==1)){
178 $val1 = $val1[0];
179 $ar2[$key1] = $ar2[$key1][0];
180 }
181 }
182 ksort($ar1);
183 ksort($ar2);
184 if(count( array_diff($ar1,$ar2))){
185 return(true);
186 }else{
187 return(false);
188 }
189 }
192 /* check which objects must be saved, and save them */
193 function save_release_changes_now()
194 {
195 /* Variable init*/
196 $to_save = array();
198 /* check which objects must be saved */
199 foreach($_SESSION['FAI_objects_to_save'] as $Current_DN => $object){
200 if($object['diff']){
201 $sub_name = $Current_DN;
202 while(isset($_SESSION['FAI_objects_to_save'][$sub_name])){
203 $to_save[strlen($sub_name)][$sub_name] = $_SESSION['FAI_objects_to_save'][$sub_name];
204 unset($_SESSION['FAI_objects_to_save'][$sub_name]);
205 $sub_name = preg_replace('/^[^,]+,/', '', $sub_name);
206 }
207 }
208 }
210 /* Sort list of objects that must be saved, and ensure that
211 container objects are safed, before their childs are saved */
212 ksort($to_save);
213 $tmp = array();
214 foreach($to_save as $SubObjects){
215 foreach($SubObjects as $object){
216 $tmp[] = $object;
217 }
218 }
219 $to_save = $tmp;
221 /* Save objects and manage the correct release behavior*/
222 foreach($to_save as $save){
224 $Current_DN = $save['Current_DN'];
225 $removed = $save['removed'];
226 $objectAttrs= $save['objectAttrs'];
228 /* Get ldap object */
229 global $config;
230 $ldap = $config->get_ldap_link();
231 $ldap->cd($config->current['BASE']);
233 /* Get some basic informations */
234 $base_release = get_release_dn($Current_DN);
235 $sub_releases = get_sub_releases_of_this_release($base_release,true);
236 $parent_obj = get_parent_release_object($Current_DN);
237 $following_releases = get_sub_releases_of_this_release($base_release,true);
239 /* Check if given dn exists or if is a new entry */
240 $ldap->cat($Current_DN);
241 if(!$ldap->count()){
242 $is_new = true;
243 }else{
244 $is_new = false;
245 }
247 /* if parameter removed is true, we have to add FAIstate to the current attrs
248 FAIstate should end with ...|removed after this operation */
249 if($removed ){
250 $ldap->cat($Current_DN);
252 /* Get current object, because we must add the FAIstate ...|removed */
253 if((!$ldap->count()) && !empty($parent_obj)){
254 $ldap->cat($parent_obj);
255 }
257 /* Check if we have found a suiteable object */
258 if(!$ldap->count()){
259 echo "Error can't remove this object ".$Current_DN;
260 return;
261 }else{
263 /* Set FAIstate to current objectAttrs */
264 $objectAttrs = prepare_ldap_fetch_to_be_saved($ldap->fetch());
265 if(isset($objectAttrs['FAIstate'][0])){
266 if(!preg_match("/removed$/",$objectAttrs['FAIstate'][0])){
267 $objectAttrs['FAIstate'][0] .= "|removed";
268 }
269 }else{
270 $objectAttrs['FAIstate'][0] = "|removed";
271 }
272 }
273 }
275 /* Check if this a leaf release or not */
276 if(count($following_releases) == 0 ){
278 /* This is a leaf object. It isn't unherited by any other object */
279 if(DEBUG_FAI_FUNC) {
280 echo "<b>Saving directly, is a leaf object</b><br> ".$Current_DN;
281 print_a($objectAttrs);
282 }
283 save_FAI_object($Current_DN,$objectAttrs);
284 }else{
286 /* This object is inherited by some sub releases */
288 /* Get all releases, that inherit this object */
289 $r = get_following_releases_that_inherit_this_object($Current_DN);
291 /* Get parent object */
292 $ldap->cat($parent_obj);
293 $parent_attrs = prepare_ldap_fetch_to_be_saved($ldap->fetch());
295 /* New objects require special handling */
296 if($is_new){
298 /* check if there is already an entry named like this,
299 in one of our parent releases */
300 if(!empty($parent_obj)){
301 if(DEBUG_FAI_FUNC) {
302 echo "There is already an entry named like this.</b><br>";
304 echo "<b>Saving main object</b>".$Current_DN;
305 print_a($objectAttrs);
306 }
307 save_FAI_object($Current_DN,$objectAttrs);
309 foreach($r as $key){
310 if(DEBUG_FAI_FUNC) {
311 echo "<b>Saving parent to following release</b> ".$key;
312 print_a($parent_attrs);
313 }
314 save_FAI_object($key,$parent_attrs);
315 }
316 }else{
318 if(DEBUG_FAI_FUNC) {
319 echo "<b>Saving main object</b>".$Current_DN;
320 print_a($objectAttrs);
321 }
322 save_FAI_object($Current_DN,$objectAttrs);
324 if(isset($objectAttrs['FAIstate'])){
325 $objectAttrs['FAIstate'] .= "|removed";
326 }else{
327 $objectAttrs['FAIstate'] = "|removed";
328 }
330 foreach($r as $key ){
331 if(DEBUG_FAI_FUNC) {
332 echo "<b>Create an empty placeholder in follwing release</b> ".$key;
333 print_a($objectAttrs);
334 }
335 save_FAI_object($key,$objectAttrs);
336 }
337 }
338 }else{
340 /* check if we must patch the follwing release */
341 if(!empty($r)){
342 foreach($r as $key ){
343 if(DEBUG_FAI_FUNC) {
344 echo "<b>Copy current objects original attributes to next release</b> ".$key;
345 print_a($parent_attrs);
346 }
347 save_FAI_object($key,$parent_attrs);
348 }
349 }
351 if(DEBUG_FAI_FUNC) {
352 echo "<b>Saving current object</b>".$parent_obj;
353 print_a($objectAttrs);
354 }
355 save_FAI_object($parent_obj,$objectAttrs);
357 if(($parent_obj != $Current_DN)){
358 print_red(sprintf(_("Error, following objects should be equal '%s' and '%s'"),$parent_obj,$Current_DN));
359 }
360 }
361 }
362 }
363 $_SESSION['FAI_objects_to_save'] = array();
364 }
367 /* this function will remove all unused (deleted) objects,
368 that have no parent object */
369 function clean_up_releases($Current_DN)
370 {
371 global $config;
372 $ldap = $config->get_ldap_link();
373 $ldap->cd($config->current['BASE']);
375 /* Collect some basic informations and initialize some variables */
376 $base_release = get_release_dn($Current_DN);
377 $previous_releases = array_reverse(get_previous_releases_of_this_release($base_release,true));
378 $Kill = array();
379 $Skip = array();
381 /* We must also include the given release dn */
382 $previous_releases[] = $base_release;
384 /* Walk through all releases */
385 foreach($previous_releases as $release){
387 /* Get fai departments */
388 $deps_to_search = get_FAI_departments($release);
390 /* For every single department (ou=hoos,ou ..) */
391 foreach($deps_to_search as $fai_base){
393 /* Ldap search for fai classes specified in this release */
394 $ldap->cd($fai_base);
395 $ldap->search("(objectClass=FAIclass)",array("dn","objectClass","FAIstate"));
397 /* check the returned objects, and add/replace them in our return variable */
398 while($attr = $ldap->fetch()){
400 $buffer = array();
401 $name = str_ireplace($release,"",$attr['dn']);
403 if(isset($attr['FAIstate'][0])&&(preg_match("/removed$/",$attr['FAIstate'][0]))){
405 /* Check if this object is required somehow */
406 if(!isset($Skip[$name])){
407 $Kill[$attr['dn']] = $attr['dn'];
408 }
409 }else{
411 /* This object is required (not removed), so do not
412 delete any following sub releases of this object */
413 $Skip[$name] = $attr['dn'];
414 }
415 }
416 }
417 }
418 return($Kill);
419 }
422 /* Remove numeric index and 'count' from ldap->fetch result */
423 function prepare_ldap_fetch_to_be_saved($attrs)
424 {
425 foreach($attrs as $key => $value){
426 if(is_numeric($key) || ($key == "count") || ($key == "dn")){
427 unset($attrs[$key]);
428 }
429 if(is_array($value) && isset($value['count'])){
430 unset($attrs[$key]['count']);
431 }
432 }
433 return($attrs);
434 }
437 /* Save given attrs to specified dn*/
438 function save_FAI_object($dn,$attrs)
439 {
440 global $config;
441 $ldap = $config->get_ldap_link();
442 $ldap->cd($config->current['BASE']);
443 $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dn));
444 $ldap->cd($dn);
446 $ldap->cat($dn,array("dn"));
447 if($ldap->count()){
449 /* Remove FAIstate*/
450 if(!isset($attrs['FAIstate'])){
451 $attrs['FAIstate'] = array();
452 }
454 $ldap->modify($attrs);
455 }else{
457 /* Unset description if empty */
458 if(empty($attrs['description'])){
459 unset($attrs['description']);
460 }
462 $ldap->add($attrs);
463 }
464 show_ldap_error($ldap->get_error(),sprintf(_("Release management failed, can't save '%s'"),$dn));
465 }
468 /* Return FAIstate freeze branch or "" for specified release department */
469 function get_release_tag($dn)
470 {
471 global $config;
472 $ldap = $config->get_ldap_link();
473 $ldap->cd($dn);
474 $ldap->cat($dn,array("FAIstate"));
476 if($ldap->count()){
478 $attr = $ldap->fetch();
479 if(isset($attr['FAIstate'][0])){
480 if(preg_match("/freeze/",$attr['FAIstate'][0])){
481 return("freeze");
482 }elseif(preg_match("/branch/",$attr['FAIstate'][0])){
483 return("branch");
484 }
485 }
486 }
487 return("");
488 }
491 function get_following_releases_that_inherit_this_object($dn)
492 {
493 global $config;
494 $ldap = $config->get_ldap_link();
495 $ldap->cd($config->current['BASE']);
497 $ret = array();
499 /* Get base release */
500 $base_release = get_release_dn($dn);
502 /* Get previous release dns */
503 $sub_releases = get_sub_releases_of_this_release($base_release);
505 /* Get dn suffix. Example "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
506 $dn_suffix = str_ireplace($base_release,"",$dn);
508 /* Check if given object also exists whitin one of these releases */
509 foreach($sub_releases as $p_release => $name){
511 $check_dn = $dn_suffix.$p_release;
513 $ldap->cat($check_dn,array("dn","objectClass"));
515 if($ldap->count()){
516 //return($ret);
517 }else{
518 $ret[$check_dn]=$check_dn;
519 }
520 }
521 return($ret);
522 }
525 /* Get previous version of the object dn */
526 function get_parent_release_object($dn,$include_myself=true)
527 {
528 global $config;
529 $ldap = $config->get_ldap_link();
530 $ldap->cd($config->current['BASE']);
531 $previous_releases= array();
533 /* Get base release */
534 $base_release = get_release_dn($dn);
535 if($include_myself){
536 $previous_releases[] = $base_release;
537 }
539 /* Get previous release dns */
540 $tmp = get_previous_releases_of_this_release($base_release,true);
541 foreach($tmp as $release){
542 $previous_releases[] = $release;
543 }
545 /* Get dn suffix. Example "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
546 $dn_suffix = str_ireplace($base_release,"",$dn);
548 /* Check if given object also exists whitin one of these releases */
549 foreach($previous_releases as $p_release){
550 $check_dn = $dn_suffix.$p_release;
551 $ldap->cat($check_dn,array("dn","objectClass"));
553 if($ldap->count()){
554 return($check_dn);
555 }
556 }
557 return("");
558 }
561 /* return release names of all parent releases */
562 function get_previous_releases_of_this_release($dn,$flat)
563 {
564 global $config;
565 $ldap = $config->get_ldap_link();
566 $ldap->cd($config->current['BASE']);
567 $ret = array();
569 /* Explode dns into pieces, to be able to build parent dns */
570 $dns_to_check = ldap_explode_dn(str_ireplace(",".$config->current['BASE'],"",$dn),0);
571 if(!is_array($dns_to_check)){
572 return;
573 }
575 /* Unset first entry which represents the given dn */
576 unset($dns_to_check['count']);
577 unset($dns_to_check[key($dns_to_check)]);
579 /* Create dns addresses and check if this dn is a release dn */
580 $id = 0;
581 while(count($dns_to_check)){
583 /* build parent dn */
584 $new_dn = "";
585 foreach($dns_to_check as $part){
586 $new_dn .= $part.",";
587 }
588 $new_dn .= $config->current['BASE'];
590 /* check if this dn is a release */
591 if(is_release_department($new_dn)){
592 if($flat){
593 $ret[$id] = $new_dn;
594 }else{
595 $ret = array($new_dn=>$ret);
596 }
597 $id ++;
598 }else{
599 return($ret);
600 }
601 reset($dns_to_check);
602 unset($dns_to_check[key($dns_to_check)]);
603 }
604 return($ret);
605 }
608 /* This function returns all sub release names, recursivly */
609 function get_sub_releases_of_this_release($dn,$flat = false)
610 {
611 global $config;
612 $res = array();
613 $ldap = $config->get_ldap_link();
614 $ldap->cd($config->current['BASE']);
615 $ldap->ls("(objectClass=FAIbranch)",$dn,array("objectClass","dn","ou"));
616 while($attr = $ldap->fetch()){
618 /* Append department name */
619 if($flat){
620 $res[$attr['dn']] = $attr['ou'][0];
621 }else{
622 $res[$attr['dn']] = array();
623 }
625 /* Get sub release departments of this department */
626 if(in_array("FAIbranch",$attr['objectClass'])) {
627 if($flat){
628 $tmp = get_sub_releases_of_this_release($attr['dn'],$flat);
629 foreach($tmp as $dn => $value){
630 $res[$dn]=$value;
631 }
632 }else{
633 $res[$attr['dn']] = get_sub_releases_of_this_release($attr['dn']);
634 }
635 }
636 }
637 return($res);
638 }
641 /* Check if the given department is a release department */
642 function is_release_department($dn)
643 {
644 global $config;
645 $ldap = $config->get_ldap_link();
646 $ldap->cd($config->current['BASE']);
647 $ldap->cat($dn,array("objectClass","ou"));
649 /* Check objectClasses and name to check if this is a release department */
650 if($ldap->count()){
651 $attrs = $ldap->fetch();
653 $ou = "";
654 if(isset($attrs['ou'][0])){
655 $ou = $attrs['ou'][0];
656 }
658 if((in_array("FAIbranch",$attrs['objectClass'])) || ($ou == "fai")){
659 return($attrs['dn']);
660 }
661 }
662 return(false);
663 }
666 /* This function returns the dn of the object release */
667 function get_release_dn($Current_DN)
668 {
669 global $config;
670 $ldap = $config->get_ldap_link();
671 $ldap->cd($config->current['BASE']);
673 /* Split dn into pices */
674 $dns_to_check = ldap_explode_dn(str_ireplace(",".$config->current['BASE'],"",$Current_DN),0);
675 if(!is_array($dns_to_check)){
676 return;
677 }
679 /* Use dn pieces, to create sub dns like
680 ou=test,ou=1,ou=0...
681 ou=1,ou=0...
682 ou=0...
683 To check which dn is our release container.
684 */
685 unset($dns_to_check['count']);
686 while(count($dns_to_check)){
688 /* Create dn */
689 $new_dn = "";
690 foreach($dns_to_check as $part){
691 $new_dn .= $part.",";
692 }
693 $new_dn .= $config->current['BASE'];
695 /* Check if this dn is a release dn */
696 if(is_release_department($new_dn)){
697 return($new_dn);
698 }
700 /* Remove first element of dn pieces */
701 reset($dns_to_check);
702 unset($dns_to_check[key($dns_to_check)]);
703 }
704 return("");
705 }
707 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
708 ?>