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']);
16 $res = array();
17 $tmp = array();
19 if(!is_release_department($Current_DN)) {
20 return($res);
21 }
23 /* Collect some basic informations and initialize some variables */
24 $base_release = get_release_dn($Current_DN);
25 $previous_releases = array_reverse(get_previous_releases_of_this_release($base_release,true));
27 /* We must also include the given release dn */
28 $previous_releases[] = $base_release;
30 /* Walk through all releases */
31 foreach($previous_releases as $release){
33 /* Get fai departments */
34 $deps_to_search = get_FAI_departments($release);
36 /* For every single department (ou=hoos,ou ..) */
37 foreach($deps_to_search as $fai_base){
39 /* Ldap search for fai classes specified in this release */
40 $attributes = array("dn","objectClass","FAIstate","cn");
41 $res_tmp = get_list($filter,"fai",$fai_base,$attributes,GL_SUBSEARCH | GL_SIZELIMIT);
43 /* check the returned objects, and add/replace them in our return variable */
44 foreach($res_tmp as $attr){
46 $buffer = array();
47 $name = preg_replace("/".normalizePreg($release)."/i","",$attr['dn']);
49 if(isset($attr['FAIstate'][0])){
50 if(preg_match("/removed$/",$attr['FAIstate'][0])){
51 if(isset($res[$name])){
52 unset($res[$name]);
53 }
54 continue;
55 }
56 }
58 /* In detailed mode are some additonal informations visible */
59 if($detailed){
61 /* Create list of parents */
62 if(isset($res[$name])){
63 $buffer = $res[$name];
64 $buffer['parents'][] = $res[$name]['dn'];
65 }else{
66 $buffer['parents'] = array();
67 }
69 /* Append objectClass to resulsts */
70 foreach($attributes as $val){
71 if(isset($attr[$val])){
72 $buffer[$val] = $attr[$val];
73 }
74 }
75 unset($buffer['objectClass']['count']);
76 }
78 /* Add this object to our list */
79 $buffer['dn'] = $attr['dn'];
80 $res[$name] = $buffer;
81 }
82 }
83 }
84 return($res);
85 }
88 /* Return all relevant FAI departments */
89 function get_FAI_departments($suffix = "")
90 {
91 $arr = array("hooks","scripts","disk","packages","profiles","templates","variables");
92 $tmp = array();
93 if(preg_match("/^,/",$suffix)){
94 $suffix = preg_replace("/^,/","",$suffix);
95 }
96 foreach($arr as $name){
97 if(empty($suffix)){
98 $tmp[$name] = "ou=".$name;
99 }else{
100 $tmp[$name] = "ou=".$name.",".$suffix;
101 }
102 }
103 return($tmp);
104 }
107 /* Return all releases within the given base */
108 function get_all_releases_from_base($dn,$appendedName=false)
109 {
110 global $config;
112 if(!preg_match("/".normalizePreg(get_ou('faiou'))."/",$dn)){
113 $base = get_ou('faiou').$dn;
114 }else{
115 $base = $dn;
116 }
117 $res = array();
119 $ldap = $config->get_ldap_link();
120 $ldap->cd($base);
121 $ldap->search("(objectClass=FAIbranch)",array("ou","dn"));
122 while($attrs = $ldap->fetch()){
123 if($appendedName){
124 $res[$attrs['dn']] = convert_department_dn(preg_replace("/,".normalizePreg(get_ou('faiou')).".*$/","",$attrs['dn']));
125 }else{
126 $res[$attrs['dn']] = $attrs['ou'][0];
127 }
128 }
129 return($res);
130 }
133 /* Add this object to list of objects, that must be checked for release saving */
134 function prepare_to_save_FAI_object($Current_DN,$objectAttrs,$removed = false)
135 {
136 /* Get ldap object */
137 global $config;
138 $addObj['Current_DN'] = $Current_DN;
139 $addObj['objectAttrs']= $objectAttrs;
140 $addObj['removed'] = $removed;
141 $addObj['diff'] = TRUE;
143 if(!$removed){
144 $ldap = $config->get_ldap_link();
145 $ldap->cd($config->current['BASE']);
147 /* Get some basic informations */
148 $parent_obj = get_parent_release_object($Current_DN);
149 if(!empty($parent_obj)){
150 $ldap->cat($parent_obj,array("*"));
151 $attrs = prepare_ldap_fetch_to_be_saved($ldap->fetch());
153 if(!array_diff_FAI( $attrs,$objectAttrs)){
154 $addObj['diff'] = FALSE;
155 }
156 }
157 }
158 $FAI_objects_to_save = session::get('FAI_objects_to_save') ;
159 $FAI_objects_to_save[$Current_DN] = $addObj;
160 session::set('FAI_objects_to_save',$FAI_objects_to_save);
161 }
164 /* Detect differences in attribute arrays */
165 function array_diff_FAI($ar1,$ar2)
166 {
168 if((!isset($ar1['description'])) || (isset($ar1['description']) && (count($ar1['description']) == 0))){
169 $ar1['description'] = "";
170 }
171 if((!isset($ar2['description'])) || (isset($ar2['description']) && (count($ar2['description']) == 0))){
172 $ar2['description'] = "";
173 }
175 if(count($ar1) != count($ar2)) {
176 return (true);
177 }
179 foreach($ar1 as $key1 => $val1){
181 if((is_array($val1)) && (count($val1)==1)){
182 $ar1[$key1] = $val1[0];
183 }
185 if((is_array($ar2[$key1])) && (count($ar2[$key1])==1)){
186 $val1 = $val1[0];
187 $ar2[$key1] = $ar2[$key1][0];
188 }
189 }
190 ksort($ar1);
191 ksort($ar2);
192 if(count( array_diff($ar1,$ar2)) || arr_diff($ar1,$ar2)){
193 return(true);
194 }else{
195 return(false);
196 }
197 }
200 function arr_diff($ar1,$ar2)
201 {
202 foreach($ar1 as $ak1 => $av1){
203 if(!isset($ar2[$ak1]) || (!($av1 === $ar2[$ak1]))){
204 return(true);
205 }elseif(is_array($av1)){
206 return(arr_diff($av1,$ar2[$ak1]));
207 }
208 }
209 return(FALSE);
210 }
215 /* check which objects must be saved, and save them */
216 function save_release_changes_now()
217 {
218 /* Variable init*/
219 $to_save = array();
221 /* check which objects must be saved */
222 $FAI_objects_to_save = session::get('FAI_objects_to_save');
223 foreach($FAI_objects_to_save as $Current_DN => $object){
224 if($object['diff']){
225 $sub_name = $Current_DN;
226 while(isset($FAI_objects_to_save[$sub_name])){
227 $to_save[strlen($sub_name)][$sub_name] = $FAI_objects_to_save[$sub_name];
228 unset($FAI_objects_to_save[$sub_name]);
229 $sub_name = preg_replace('/^[^,]+,/', '', $sub_name);
230 }
231 }
232 }
233 session::set('FAI_objects_to_save',$FAI_objects_to_save);
235 /* Sort list of objects that must be saved, and ensure that
236 container objects are safed, before their childs are saved */
237 ksort($to_save);
238 $tmp = array();
239 foreach($to_save as $SubObjects){
240 foreach($SubObjects as $object){
241 $tmp[] = $object;
242 }
243 }
244 $to_save = $tmp;
246 /* Save objects and manage the correct release behavior*/
247 foreach($to_save as $save){
249 $Current_DN = $save['Current_DN'];
250 $removed = $save['removed'];
251 $objectAttrs= $save['objectAttrs'];
253 /* Get ldap object */
254 global $config;
255 $ldap = $config->get_ldap_link();
256 $ldap->cd($config->current['BASE']);
258 /* Get some basic informations */
259 $base_release = get_release_dn($Current_DN);
260 $sub_releases = get_sub_releases_of_this_release($base_release,true);
261 $parent_obj = get_parent_release_object($Current_DN);
262 $following_releases = get_sub_releases_of_this_release($base_release,true);
264 /* Check if given dn exists or if is a new entry */
265 $ldap->cat($Current_DN);
266 if(!$ldap->count()){
267 $is_new = true;
268 }else{
269 $is_new = false;
270 }
272 /* if parameter removed is true, we have to add FAIstate to the current attrs
273 FAIstate should end with ...|removed after this operation */
274 if($removed ){
275 $ldap->cat($Current_DN);
277 /* Get current object, because we must add the FAIstate ...|removed */
278 if((!$ldap->count()) && !empty($parent_obj)){
279 $ldap->cat($parent_obj);
280 }
282 /* Check if we have found a suiteable object */
283 if(!$ldap->count()){
284 echo "Error can't remove this object ".$Current_DN;
285 return;
286 }else{
288 /* Set FAIstate to current objectAttrs */
289 $objectAttrs = prepare_ldap_fetch_to_be_saved($ldap->fetch());
290 if(isset($objectAttrs['FAIstate'][0])){
291 if(!preg_match("/removed$/",$objectAttrs['FAIstate'][0])){
292 $objectAttrs['FAIstate'][0] .= "|removed";
293 }
294 }else{
295 $objectAttrs['FAIstate'][0] = "|removed";
296 }
297 }
298 }
300 /* Check if this a leaf release or not */
301 if(count($following_releases) == 0 ){
303 /* This is a leaf object. It isn't inherited by any other object */
304 if(DEBUG_FAI_FUNC) {
305 echo "<b>Saving directly, is a leaf object</b><br> ".$Current_DN;
306 print_a($objectAttrs);
307 }
308 save_FAI_object($Current_DN,$objectAttrs);
309 }else{
311 /* This object is inherited by some sub releases */
313 /* Get all releases, that inherit this object */
314 $r = get_following_releases_that_inherit_this_object($Current_DN);
316 /* Get parent object */
317 $ldap->cat($parent_obj);
318 $parent_attrs = prepare_ldap_fetch_to_be_saved($ldap->fetch());
320 /* New objects require special handling */
321 if($is_new){
323 /* check if there is already an entry named like this,
324 in one of our parent releases */
325 if(!empty($parent_obj)){
326 if(DEBUG_FAI_FUNC) {
327 echo "There is already an entry named like this.</b><br>";
329 echo "<b>Saving main object</b>".$Current_DN;
330 print_a($objectAttrs);
331 }
332 save_FAI_object($Current_DN,$objectAttrs);
334 foreach($r as $key){
335 if(DEBUG_FAI_FUNC) {
336 echo "<b>Saving parent to following release</b> ".$key;
337 print_a($parent_attrs);
338 }
339 save_FAI_object($key,$parent_attrs);
340 }
341 }else{
343 if(DEBUG_FAI_FUNC) {
344 echo "<b>Saving main object</b>".$Current_DN;
345 print_a($objectAttrs);
346 }
347 save_FAI_object($Current_DN,$objectAttrs);
349 if(isset($objectAttrs['FAIstate'])){
350 $objectAttrs['FAIstate'] .= "|removed";
351 }else{
352 $objectAttrs['FAIstate'] = "|removed";
353 }
355 foreach($r as $key ){
356 if(DEBUG_FAI_FUNC) {
357 echo "<b>Create an empty placeholder in follwing release</b> ".$key;
358 print_a($objectAttrs);
359 }
360 save_FAI_object($key,$objectAttrs);
361 }
362 }
363 }else{
365 /* check if we must patch the follwing release */
366 if(!empty($r)){
367 foreach($r as $key ){
368 if(DEBUG_FAI_FUNC) {
369 echo "<b>Copy current objects original attributes to next release</b> ".$key;
370 print_a($parent_attrs);
371 }
372 save_FAI_object($key,$parent_attrs);
373 }
374 }
376 if(DEBUG_FAI_FUNC) {
377 echo "<b>Saving current object</b>".$parent_obj;
378 print_a($objectAttrs);
379 }
380 save_FAI_object($parent_obj,$objectAttrs);
382 if(($parent_obj != $Current_DN)){
383 msg_dialog::display(_("Error"), sprintf(_("Error, following objects should be equal '%s' and '%s'"),$parent_obj,$Current_DN), ERROR_DIALOG);
384 }
385 }
386 }
387 }
388 session::set('FAI_objects_to_save',array());
389 }
392 /* this function will remove all unused (deleted) objects,
393 that have no parent object */
394 function clean_up_releases($Current_DN)
395 {
396 global $config;
397 $ldap = $config->get_ldap_link();
398 $ldap->cd($config->current['BASE']);
400 /* Collect some basic informations and initialize some variables */
401 $base_release = get_release_dn($Current_DN);
402 $previous_releases = array_reverse(get_previous_releases_of_this_release($base_release,true));
403 $Kill = array();
404 $Skip = array();
406 /* We must also include the given release dn */
407 $previous_releases[] = $base_release;
409 /* Walk through all releases */
410 foreach($previous_releases as $release){
412 /* Get fai departments */
413 $deps_to_search = get_FAI_departments($release);
415 /* For every single department (ou=hoos,ou ..) */
416 foreach($deps_to_search as $fai_base){
418 /* Ldap search for fai classes specified in this release */
419 $ldap->cd($fai_base);
420 $ldap->search("(objectClass=FAIclass)",array("dn","objectClass","FAIstate"));
422 /* check the returned objects, and add/replace them in our return variable */
423 while($attr = $ldap->fetch()){
425 $buffer = array();
426 # $name = str_ireplace($release,"",$attr['dn']);
427 $name = preg_replace("/".normalizePreg($release)."/i","",$attr['dn']);
429 if(isset($attr['FAIstate'][0])&&(preg_match("/removed$/",$attr['FAIstate'][0]))){
431 /* Check if this object is required somehow */
432 if(!isset($Skip[$name])){
433 $Kill[$attr['dn']] = $attr['dn'];
434 }
435 }else{
437 /* This object is required (not removed), so do not
438 delete any following sub releases of this object */
439 $Skip[$name] = $attr['dn'];
440 }
441 }
442 }
443 }
444 return($Kill);
445 }
448 /* Remove numeric index and 'count' from ldap->fetch result */
449 function prepare_ldap_fetch_to_be_saved($attrs)
450 {
451 foreach($attrs as $key => $value){
452 if(is_numeric($key) || ($key == "count") || ($key == "dn")){
453 unset($attrs[$key]);
454 }
455 if(is_array($value) && isset($value['count'])){
456 unset($attrs[$key]['count']);
457 }
458 }
459 return($attrs);
460 }
463 /* Save given attrs to specified dn*/
464 function save_FAI_object($dn,$attrs)
465 {
466 global $config;
467 $ldap = $config->get_ldap_link();
468 $ldap->cd($config->current['BASE']);
469 $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dn));
470 $ldap->cd($dn);
472 $ldap->cat($dn,array("dn"));
473 if($ldap->count()){
475 /* Remove FAIstate*/
476 if(!isset($attrs['FAIstate'])){
477 $attrs['FAIstate'] = array();
478 }
480 $ldap->modify($attrs);
481 }else{
483 /* Unset description if empty */
484 if(empty($attrs['description'])){
485 unset($attrs['description']);
486 }
488 $ldap->add($attrs);
489 }
490 show_ldap_error($ldap->get_error(),sprintf(_("Release management failed, can't save '%s'"),$dn));
491 }
494 /* Return FAIstate freeze branch or "" for specified release department */
495 function get_release_tag($dn)
496 {
497 global $config;
498 $ldap = $config->get_ldap_link();
499 $ldap->cd($dn);
500 $ldap->cat($dn,array("FAIstate"));
502 if($ldap->count()){
504 $attr = $ldap->fetch();
505 if(isset($attr['FAIstate'][0])){
506 if(preg_match("/freeze/",$attr['FAIstate'][0])){
507 return("freeze");
508 }elseif(preg_match("/branch/",$attr['FAIstate'][0])){
509 return("branch");
510 }
511 }
512 }
513 return("");
514 }
517 function get_following_releases_that_inherit_this_object($dn)
518 {
519 global $config;
520 $ldap = $config->get_ldap_link();
521 $ldap->cd($config->current['BASE']);
523 $ret = array();
525 /* Get base release */
526 $base_release = get_release_dn($dn);
528 /* Get previous release dns */
529 $sub_releases = get_sub_releases_of_this_release($base_release);
531 /* Get dn suffix. Example "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
532 # $dn_suffix = str_ireplace($base_release,"",$dn);
533 $dn_suffix = preg_replace("/".normalizePreg($base_release)."/i","",$dn);
535 /* Check if given object also exists whitin one of these releases */
536 foreach($sub_releases as $p_release => $name){
538 $check_dn = $dn_suffix.$p_release;
540 $ldap->cat($check_dn,array("dn","objectClass"));
542 if($ldap->count()){
543 //return($ret);
544 }else{
545 $ret[$check_dn]=$check_dn;
546 }
547 }
548 return($ret);
549 }
552 /* Get previous version of the object dn */
553 function get_parent_release_object($dn,$include_myself=true)
554 {
555 global $config;
556 $ldap = $config->get_ldap_link();
557 $ldap->cd($config->current['BASE']);
558 $previous_releases= array();
560 /* Get base release */
561 $base_release = get_release_dn($dn);
562 if($include_myself){
563 $previous_releases[] = $base_release;
564 }
566 /* Get previous release dns */
567 $tmp = get_previous_releases_of_this_release($base_release,true);
568 foreach($tmp as $release){
569 $previous_releases[] = $release;
570 }
572 /* Get dn suffix. Example "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
573 # $dn_suffix = str_ireplace($base_release,"",$dn);
574 $dn_suffix = preg_replace("/".normalizePreg($base_release)."/i","",$dn);
576 /* Check if given object also exists whitin one of these releases */
577 foreach($previous_releases as $p_release){
578 $check_dn = $dn_suffix.$p_release;
579 $ldap->cat($check_dn,array("dn","objectClass"));
581 if($ldap->count()){
582 return($check_dn);
583 }
584 }
585 return("");
586 }
589 /* return release names of all parent releases */
590 function get_previous_releases_of_this_release($dn,$flat)
591 {
592 global $config;
593 $ldap = $config->get_ldap_link();
594 $ldap->cd($config->current['BASE']);
595 $ret = array();
597 /* Explode dns into pieces, to be able to build parent dns */
598 $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".normalizePreg(",".$config->current['BASE'])."/i","",$dn));
600 if(!is_array($dns_to_check)){
601 return;
602 }
604 /* Unset first entry which represents the given dn */
605 unset($dns_to_check['count']);
606 unset($dns_to_check[key($dns_to_check)]);
608 /* Create dns addresses and check if this dn is a release dn */
609 $id = 0;
610 while(count($dns_to_check)){
612 /* build parent dn */
613 $new_dn = "";
614 foreach($dns_to_check as $part){
615 $new_dn .= $part.",";
616 }
617 $new_dn .= $config->current['BASE'];
619 /* check if this dn is a release */
620 if(is_release_department($new_dn)){
621 if($flat){
622 $ret[$id] = $new_dn;
623 }else{
624 $ret = array($new_dn=>$ret);
625 }
626 $id ++;
627 }else{
628 return($ret);
629 }
630 reset($dns_to_check);
631 unset($dns_to_check[key($dns_to_check)]);
632 }
633 return($ret);
634 }
637 /* This function returns all sub release names, recursivly */
638 function get_sub_releases_of_this_release($dn,$flat = false)
639 {
640 global $config;
641 $res = array();
642 $ldap = $config->get_ldap_link();
643 $ldap->cd($config->current['BASE']);
644 $ldap->ls("(objectClass=FAIbranch)",$dn,array("objectClass","dn","ou"));
645 while($attr = $ldap->fetch()){
647 /* Append department name */
648 if($flat){
649 $res[$attr['dn']] = $attr['ou'][0];
650 }else{
651 $res[$attr['dn']] = array();
652 }
654 /* Get sub release departments of this department */
655 if(in_array("FAIbranch",$attr['objectClass'])) {
656 if($flat){
657 $tmp = get_sub_releases_of_this_release($attr['dn'],$flat);
658 foreach($tmp as $dn => $value){
659 $res[$dn]=$value;
660 }
661 }else{
662 $res[$attr['dn']] = get_sub_releases_of_this_release($attr['dn']);
663 }
664 }
665 }
666 return($res);
667 }
670 /* Check if the given department is a release department */
671 function is_release_department($dn)
672 {
673 global $config;
674 $ldap = $config->get_ldap_link();
675 $ldap->cd($config->current['BASE']);
676 $ldap->cat($dn,array("objectClass","ou"));
678 /* Check objectClasses and name to check if this is a release department */
679 if($ldap->count()){
680 $attrs = $ldap->fetch();
682 $ou = "";
683 if(isset($attrs['ou'][0])){
684 $ou = $attrs['ou'][0];
685 }
687 if((in_array("FAIbranch",$attrs['objectClass'])) || ($ou == "fai")){
688 return($attrs['dn']);
689 }
690 }
691 return(false);
692 }
695 /* This function returns the dn of the object release */
696 function get_release_dn($Current_DN)
697 {
698 global $config;
699 $ldap = $config->get_ldap_link();
700 $ldap->cd($config->current['BASE']);
702 /* Split dn into pices */
703 $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".normalizePreg(",".$config->current['BASE'])."/i","",$Current_DN));
705 if(!is_array($dns_to_check)){
706 return;
707 }
709 /* Use dn pieces, to create sub dns like
710 ou=test,ou=1,ou=0...
711 ou=1,ou=0...
712 ou=0...
713 To check which dn is our release container.
714 */
715 unset($dns_to_check['count']);
716 while(count($dns_to_check)){
718 /* Create dn */
719 $new_dn = "";
720 foreach($dns_to_check as $part){
721 $new_dn .= $part.",";
722 }
723 $new_dn .= $config->current['BASE'];
725 /* Check if this dn is a release dn */
726 if(is_release_department($new_dn)){
727 return($new_dn);
728 }
730 /* Remove first element of dn pieces */
731 reset($dns_to_check);
732 unset($dns_to_check[key($dns_to_check)]);
733 }
734 return("");
735 }
737 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
738 ?>