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 if(!empty($parent_obj)){
152 $ldap->cat($parent_obj,array("*"));
153 $attrs = prepare_ldap_fetch_to_be_saved($ldap->fetch());
155 if(!array_diff_FAI( $attrs,$objectAttrs)){
156 $addObj['diff'] = FALSE;
157 }
158 }
159 }
161 $_SESSION['FAI_objects_to_save'][$Current_DN] = $addObj;
162 }
165 /* Detect differences in attribute arrays */
166 function array_diff_FAI($ar1,$ar2)
167 {
168 foreach($ar1 as $key1 => $val1){
170 if((is_array($val1)) && (count($val1)==1)){
171 $ar1[$key1] = $val1[0];
172 }
174 if((is_array($ar2[$key1])) && (count($ar2[$key1])==1)){
175 $val1 = $val1[0];
176 $ar2[$key1] = $ar2[$key1][0];
177 }
178 }
179 if(count( array_diff($ar1,$ar2))){
180 return(true);
181 }else{
182 return(false);
183 }
184 }
187 /* check which objects must be saved, and save them */
188 function save_release_changes_now()
189 {
190 /* Variable init*/
191 $to_save = array();
194 /* check which attributes must realy be saved */
195 foreach($_SESSION['FAI_objects_to_save'] as $Current_DN => $object){
196 if($object['diff']){
197 $sub_name = $Current_DN;
198 while(isset($_SESSION['FAI_objects_to_save'][$sub_name])){
201 $to_save[strlen($sub_name)."-".$sub_name] = $_SESSION['FAI_objects_to_save'][$sub_name];
202 unset($_SESSION['FAI_objects_to_save'][$sub_name]);
203 $sub_name = preg_replace('/^[^,]+,/', '', $sub_name);
204 }
205 }
206 }
208 /* Sort list of objects that must be saved, and ensure that
209 container objects are safed, before their childs are saved */
210 ksort($to_save);
212 /* Save objects and manage the correct release behavior*/
213 foreach($to_save as $save){
215 $Current_DN = $save['Current_DN'];
216 $removed = $save['removed'];
217 $objectAttrs= $save['objectAttrs'];
219 /* Get ldap object */
220 global $config;
221 $ldap = $config->get_ldap_link();
222 $ldap->cd($config->current['BASE']);
224 /* Get some basic informations */
225 $base_release = get_release_dn($Current_DN);
226 $sub_releases = get_sub_releases_of_this_release($base_release,true);
227 $parent_obj = get_parent_release_object($Current_DN);
228 $following_releases = get_sub_releases_of_this_release($base_release,true);
230 /* Check if given dn exists or if is a new entry */
231 $ldap->cat($Current_DN);
232 if(!$ldap->count()){
233 $is_new = true;
234 }else{
235 $is_new = false;
236 }
238 /* if parameter removed is true, we have to add FAIstate to the current attrs
239 FAIstate should end with ...|removed after this operation */
240 if($removed ){
241 $ldap->cat($Current_DN);
243 /* Get current object, because we must add the FAIstate ...|removed */
244 if((!$ldap->count()) && !empty($parent_obj)){
245 $ldap->cat($parent_obj);
246 }
248 /* Check if we have found a suiteable object */
249 if(!$ldap->count()){
250 echo "Error can't remove this object ".$Current_DN;
251 return;
252 }else{
254 /* Set FAIstate to current objectAttrs */
255 $objectAttrs = prepare_ldap_fetch_to_be_saved($ldap->fetch());
256 if(isset($objectAttrs['FAIstate'][0])){
257 if(!preg_match("/removed$/",$objectAttrs['FAIstate'][0])){
258 $objectAttrs['FAIstate'][0] .= "|removed";
259 }
260 }else{
261 $objectAttrs['FAIstate'][0] = "|removed";
262 }
263 }
264 }
267 /* Check if this a leaf release or not */
268 if(count($following_releases) == 0 ){
270 /* This is a leaf object. It isn't unherited by any other object */
271 if(DEBUG_FAI_FUNC) {
272 echo "<b>Saving directly, is a leaf object</b><br> ".$Current_DN;
273 print_a($objectAttrs);
274 }
275 save_FAI_object($Current_DN,$objectAttrs);
276 }else{
278 /* This object is inherited by some sub releases */
280 /* Get all releases, that inherit this object */
281 $r = get_following_releases_that_inherit_this_object($Current_DN);
283 /* Get parent object */
284 $ldap->cat($parent_obj);
285 $parent_attrs = prepare_ldap_fetch_to_be_saved($ldap->fetch());
287 /* New objects require special handling */
288 if($is_new){
290 /* check if there is already an entry named like this,
291 in one of our parent releases */
292 if(!empty($parent_obj)){
293 if(DEBUG_FAI_FUNC) {
294 echo "There is already an entry named like this.</b><br>";
296 echo "<b>Saving main object</b>".$Current_DN;
297 print_a($objectAttrs);
298 }
299 save_FAI_object($Current_DN,$objectAttrs);
301 foreach($r as $key){
302 if(DEBUG_FAI_FUNC) {
303 echo "<b>Saving parent to following release</b> ".$key;
304 print_a($parent_attrs);
305 }
306 save_FAI_object($key,$parent_attrs);
307 }
308 }else{
310 if(DEBUG_FAI_FUNC) {
311 echo "<b>Saving main object</b>".$Current_DN;
312 print_a($objectAttrs);
313 }
314 save_FAI_object($Current_DN,$objectAttrs);
316 if(isset($objectAttrs['FAIstate'])){
317 $objectAttrs['FAIstate'] .= "|removed";
318 }else{
319 $objectAttrs['FAIstate'] = "|removed";
320 }
322 foreach($r as $key ){
323 if(DEBUG_FAI_FUNC) {
324 echo "<b>Create an empty placeholder in follwing release</b> ".$key;
325 print_a($objectAttrs);
326 }
327 save_FAI_object($key,$objectAttrs);
328 }
329 }
330 }else{
332 /* check if we must patch the follwing release */
333 if(!empty($r)){
334 foreach($r as $key ){
335 if(DEBUG_FAI_FUNC) {
336 echo "<b>Copy current objects original attributes to next release</b> ".$key;
337 print_a($parent_attrs);
338 }
339 save_FAI_object($key,$parent_attrs);
340 }
341 }
343 if(DEBUG_FAI_FUNC) {
344 echo "<b>Saving current object</b>".$parent_obj;
345 print_a($objectAttrs);
346 }
347 save_FAI_object($parent_obj,$objectAttrs);
349 if(($parent_obj != $Current_DN)){
350 print_red(sprintf(_("Error, following objects should be equal '%s' and '%s'"),$parent_obj,$Current_DN));
351 }
352 }
353 }
354 }
355 $_SESSION['FAI_objects_to_save'] = array();
356 }
359 /* this function will remove all unused (deleted) objects,
360 that have no parent object */
361 function clean_up_releases($Current_DN)
362 {
363 global $config;
364 $ldap = $config->get_ldap_link();
365 $ldap->cd($config->current['BASE']);
367 /* Collect some basic informations and initialize some variables */
368 $base_release = get_release_dn($Current_DN);
369 $previous_releases = array_reverse(get_previous_releases_of_this_release($base_release,true));
370 $Kill = array();
371 $Skip = array();
373 /* We must also include the given release dn */
374 $previous_releases[] = $base_release;
376 /* Walk through all releases */
377 foreach($previous_releases as $release){
379 /* Get fai departments */
380 $deps_to_search = get_FAI_departments($release);
382 /* For every single department (ou=hoos,ou ..) */
383 foreach($deps_to_search as $fai_base){
385 /* Ldap search for fai classes specified in this release */
386 $ldap->cd($fai_base);
387 $ldap->search("(objectClass=FAIclass)",array("dn","objectClass","FAIstate"));
389 /* check the returned objects, and add/replace them in our return variable */
390 while($attr = $ldap->fetch()){
392 $buffer = array();
393 $name = str_ireplace($release,"",$attr['dn']);
395 if(isset($attr['FAIstate'][0])&&(preg_match("/removed$/",$attr['FAIstate'][0]))){
397 /* Check if this object is required somehow */
398 if(!isset($Skip[$name])){
399 $Kill[$attr['dn']] = $attr['dn'];
400 }
401 }else{
403 /* This object is required (not removed), so do not
404 delete any following sub releases of this object */
405 $Skip[$name] = $attr['dn'];
406 }
407 }
408 }
409 }
410 return($Kill);
411 }
414 function prepare_ldap_fetch_to_be_saved($attrs)
415 {
416 foreach($attrs as $key => $value){
417 if(is_numeric($key) || ($key == "count") || ($key == "dn")){
418 unset($attrs[$key]);
419 }
420 if(is_array($value) && isset($value['count'])){
421 unset($attrs[$key]['count']);
422 }
423 }
424 return($attrs);
425 }
428 function save_FAI_object($dn,$attrs)
429 {
430 global $config;
431 $ldap = $config->get_ldap_link();
432 $ldap->cd($config->current['BASE']);
433 $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dn));
434 $ldap->cd($dn);
436 $ldap->cat($dn,array("dn"));
437 if($ldap->count()){
438 $ldap->modify($attrs);
439 }else{
440 $ldap->add($attrs);
441 }
442 show_ldap_error($ldap->get_error(),sprintf(_("Release management failed, can't save '%s'"),$dn));
443 }
446 function get_following_releases_that_inherit_this_object($dn)
447 {
448 global $config;
449 $ldap = $config->get_ldap_link();
450 $ldap->cd($config->current['BASE']);
452 $ret = array();
454 /* Get base release */
455 $base_release = get_release_dn($dn);
457 /* Get previous release dns */
458 $sub_releases = get_sub_releases_of_this_release($base_release);
460 /* Get dn suffix. Example "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
461 $dn_suffix = str_ireplace($base_release,"",$dn);
463 /* Check if given object also exists whitin one of these releases */
464 foreach($sub_releases as $p_release => $name){
466 $check_dn = $dn_suffix.$p_release;
468 $ldap->cat($check_dn,array("dn","objectClass"));
470 if($ldap->count()){
471 //return($ret);
472 }else{
473 $ret[$check_dn]=$check_dn;
474 }
475 }
476 return($ret);
477 }
480 /* Get previous version of the object dn */
481 function get_parent_release_object($dn,$include_myself=true)
482 {
483 global $config;
484 $ldap = $config->get_ldap_link();
485 $ldap->cd($config->current['BASE']);
486 $previous_releases= array();
488 /* Get base release */
489 $base_release = get_release_dn($dn);
490 if($include_myself){
491 $previous_releases[] = $base_release;
492 }
494 /* Get previous release dns */
495 $tmp = get_previous_releases_of_this_release($base_release,true);
496 foreach($tmp as $release){
497 $previous_releases[] = $release;
498 }
500 /* Get dn suffix. Example "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
501 $dn_suffix = str_ireplace($base_release,"",$dn);
503 /* Check if given object also exists whitin one of these releases */
504 foreach($previous_releases as $p_release){
505 $check_dn = $dn_suffix.$p_release;
506 $ldap->cat($check_dn,array("dn","objectClass"));
508 if($ldap->count()){
509 return($check_dn);
510 }
511 }
512 return("");
513 }
516 /* return release names of all parent releases */
517 function get_previous_releases_of_this_release($dn,$flat)
518 {
519 global $config;
520 $ldap = $config->get_ldap_link();
521 $ldap->cd($config->current['BASE']);
522 $ret = array();
524 /* Explode dns into pieces, to be able to build parent dns */
525 $dns_to_check = ldap_explode_dn(str_ireplace(",".$config->current['BASE'],"",$dn),0);
526 if(!is_array($dns_to_check)){
527 return;
528 }
530 /* Unset first entry which represents the given dn */
531 unset($dns_to_check['count']);
532 unset($dns_to_check[key($dns_to_check)]);
534 /* Create dns addresses and check if this dn is a release dn */
535 $id = 0;
536 while(count($dns_to_check)){
538 /* build parent dn */
539 $new_dn = "";
540 foreach($dns_to_check as $part){
541 $new_dn .= $part.",";
542 }
543 $new_dn .= $config->current['BASE'];
545 /* check if this dn is a release */
546 if(is_release_department($new_dn)){
547 if($flat){
548 $ret[$id] = $new_dn;
549 }else{
550 $ret = array($new_dn=>$ret);
551 }
552 $id ++;
553 }else{
554 return($ret);
555 }
556 reset($dns_to_check);
557 unset($dns_to_check[key($dns_to_check)]);
558 }
559 return($ret);
560 }
563 /* This function returns all sub release names, recursivly */
564 function get_sub_releases_of_this_release($dn,$flat = false)
565 {
566 global $config;
567 $res = array();
568 $ldap = $config->get_ldap_link();
569 $ldap->cd($config->current['BASE']);
570 $ldap->ls("(objectClass=FAIbranch)",$dn,array("objectClass","dn","ou"));
571 while($attr = $ldap->fetch()){
573 /* Append department name */
574 if($flat){
575 $res[$attr['dn']] = $attr['ou'][0];
576 }else{
577 $res[$attr['dn']] = array();
578 }
580 /* Get sub release departments of this department */
581 if(in_array("FAIbranch",$attr['objectClass'])) {
582 if($flat){
583 $tmp = get_sub_releases_of_this_release($attr['dn'],$flat);
584 foreach($tmp as $dn => $value){
585 $res[$dn]=$value;
586 }
587 }else{
588 $res[$attr['dn']] = get_sub_releases_of_this_release($attr['dn']);
589 }
590 }
591 }
592 return($res);
593 }
596 /* Check if the given department is a release department */
597 function is_release_department($dn)
598 {
599 global $config;
600 $ldap = $config->get_ldap_link();
601 $ldap->cd($config->current['BASE']);
602 $ldap->cat($dn,array("objectClass","ou"));
604 /* Check objectClasses and name to check if this is a release department */
605 if($ldap->count()){
606 $attrs = $ldap->fetch();
608 $ou = "";
609 if(isset($attrs['ou'][0])){
610 $ou = $attrs['ou'][0];
611 }
613 if((in_array("FAIbranch",$attrs['objectClass'])) || ($ou == "fai")){
614 return($attrs['dn']);
615 }
616 }
617 return(false);
618 }
621 /* This function returns the dn of the object release */
622 function get_release_dn($Current_DN)
623 {
624 global $config;
625 $ldap = $config->get_ldap_link();
626 $ldap->cd($config->current['BASE']);
628 /* Split dn into pices */
629 $dns_to_check = ldap_explode_dn(str_ireplace(",".$config->current['BASE'],"",$Current_DN),0);
630 if(!is_array($dns_to_check)){
631 return;
632 }
634 /* Use dn pieces, to create sub dns like
635 ou=test,ou=1,ou=0...
636 ou=1,ou=0...
637 ou=0...
638 To check which dn is our release container.
639 */
640 unset($dns_to_check['count']);
641 while(count($dns_to_check)){
643 /* Create dn */
644 $new_dn = "";
645 foreach($dns_to_check as $part){
646 $new_dn .= $part.",";
647 }
648 $new_dn .= $config->current['BASE'];
650 /* Check if this dn is a release dn */
651 if(is_release_department($new_dn)){
652 return($new_dn);
653 }
655 /* Remove first element of dn pieces */
656 reset($dns_to_check);
657 unset($dns_to_check[key($dns_to_check)]);
658 }
659 return("");
660 }
662 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
663 ?>