1 ## @file
2 # @brief Implementation of a GOsa-SI event module.
3 # @details A GOsa-SI event module containing all functions to handle incoming messages from clients.
4 # @author Andreas Rettenberger <rettenberger@gonicus.de>
5 # @date 2008
6 # @version 1.0
8 package clMessages;
9 use Exporter;
10 @ISA = qw(Exporter);
11 my @events = (
12 "confirm_usr_msg",
13 "PROGRESS",
14 "FAIREBOOT",
15 "TASKSKIP",
16 "TASKBEGIN",
17 "TASKEND",
18 "TASKERROR",
19 "HOOK",
20 "GOTOACTIVATION",
21 "LOGIN",
22 "LOGOUT",
23 "CURRENTLY_LOGGED_IN",
24 "save_fai_log",
25 );
26 @EXPORT = @events;
28 use strict;
29 use warnings;
30 use Data::Dumper;
31 use GOSA::GosaSupportDaemon;
32 use MIME::Base64;
35 BEGIN {}
37 END {}
39 ### Start ######################################################################
41 # labled for deleting: rettenbe 20080730
42 #my $ldap_uri;
43 #my $ldap_base;
44 #my $ldap_admin_dn;
45 #my $ldap_admin_password;
46 #
47 #my %cfg_defaults = (
48 #"server" => {
49 # "ldap-uri" => [\$ldap_uri, ""],
50 # "ldap-base" => [\$ldap_base, ""],
51 # "ldap-admin-dn" => [\$ldap_admin_dn, ""],
52 # "ldap-admin-password" => [\$ldap_admin_password, ""],
53 # },
54 #);
55 #&read_configfile($main::cfg_file, %cfg_defaults);
56 #
59 ## @method get_events()
60 # @details A brief function returning a list of functions which are exported by importing the module.
61 # @return List of all provided functions
62 sub get_events {
63 return \@events;
64 }
67 sub confirm_usr_msg {
68 my ($msg, $msg_hash, $session_id) = @_;
69 my $message = @{$msg_hash->{'message'}}[0];
70 my $subject = @{$msg_hash->{'subject'}}[0];
71 my $usr = @{$msg_hash->{'usr'}}[0];
73 # set update for this message
74 my $sql = "UPDATE $main::messaging_tn SET flag='s' WHERE (message='$message' AND subject='$subject' AND message_to='$usr')";
75 &main::daemon_log("$session_id DEBUG: $sql", 7);
76 my $res = $main::messaging_db->exec_statement($sql);
79 return;
80 }
84 #sub read_configfile {
85 # my ($cfg_file, %cfg_defaults) = @_;
86 # my $cfg;
87 #
88 # if( defined( $cfg_file) && ( (-s $cfg_file) > 0 )) {
89 # if( -r $cfg_file ) {
90 # $cfg = Config::IniFiles->new( -file => $cfg_file );
91 # } else {
92 # &main::daemon_log("ERROR: clMessages.pm couldn't read config file!", 1);
93 # }
94 # } else {
95 # $cfg = Config::IniFiles->new() ;
96 # }
97 # foreach my $section (keys %cfg_defaults) {
98 # foreach my $param (keys %{$cfg_defaults{ $section }}) {
99 # my $pinfo = $cfg_defaults{ $section }{ $param };
100 # ${@$pinfo[0]} = $cfg->val( $section, $param, @$pinfo[1] );
101 # }
102 # }
103 #}
106 sub save_fai_log {
107 my ($msg, $msg_hash, $session_id) = @_;
108 my $header = @{$msg_hash->{'header'}}[0];
109 my $source = @{$msg_hash->{'source'}}[0];
110 my $macaddress = @{$msg_hash->{'macaddress'}}[0];
111 my $all_logs = @{$msg_hash->{$header}}[0];
113 # if there is nothing to log
114 if( ref($all_logs) eq "HASH" ) { return; }
116 my $client_fai_log_dir = $main::client_fai_log_dir;
117 if (not -d $client_fai_log_dir) {
118 mkdir($client_fai_log_dir, 0755)
119 }
121 $client_fai_log_dir = File::Spec->catfile( $client_fai_log_dir, $macaddress );
122 if (not -d $client_fai_log_dir) {
123 mkdir($client_fai_log_dir, 0755)
124 }
126 my $time = &get_time;
127 $time = substr($time, 0, 8)."_".substr($time, 8, 6);
128 $client_fai_log_dir = File::Spec->catfile( $client_fai_log_dir, "install_$time" );
129 mkdir($client_fai_log_dir, 0755);
131 my @all_logs = split(/log_file:/, $all_logs);
132 foreach my $log (@all_logs) {
133 if (length $log == 0) { next; };
134 my ($log_file, $log_string) = split(":", $log);
135 my $client_fai_log_file = File::Spec->catfile( $client_fai_log_dir, $log_file);
137 open(my $LOG_FILE, ">$client_fai_log_file");
138 print $LOG_FILE &decode_base64($log_string);
139 close($LOG_FILE);
141 }
142 return;
143 }
146 sub LOGIN {
147 my ($msg, $msg_hash, $session_id) = @_;
148 my $header = @{$msg_hash->{'header'}}[0];
149 my $source = @{$msg_hash->{'source'}}[0];
150 my $login = @{$msg_hash->{$header}}[0];
152 my %add_hash = ( table=>$main::login_users_tn,
153 primkey=> ['client', 'user'],
154 client=>$source,
155 user=>$login,
156 timestamp=>&get_time,
157 );
158 my ($res, $error_str) = $main::login_users_db->add_dbentry( \%add_hash );
159 if ($res != 0) {
160 &main::daemon_log("$session_id ERROR: cannot add entry to known_clients: $error_str");
161 return;
162 }
164 return;
165 }
168 sub LOGOUT {
169 my ($msg, $msg_hash, $session_id) = @_;
170 my $header = @{$msg_hash->{'header'}}[0];
171 my $source = @{$msg_hash->{'source'}}[0];
172 my $login = @{$msg_hash->{$header}}[0];
174 my $sql_statement = "DELETE FROM $main::login_users_tn WHERE (client='$source' AND user='$login')";
175 my $res = $main::login_users_db->del_dbentry($sql_statement);
176 &main::daemon_log("$session_id INFO: delete user '$login' at client '$source' from login_user_db", 5);
178 return;
179 }
182 sub CURRENTLY_LOGGED_IN {
183 my ($msg, $msg_hash, $session_id) = @_;
184 my ($sql_statement, $db_res);
185 my $header = @{$msg_hash->{'header'}}[0];
186 my $source = @{$msg_hash->{'source'}}[0];
187 my $login = @{$msg_hash->{$header}}[0];
189 if(ref $login eq "HASH") {
190 &main::daemon_log("$session_id INFO: no logged in users reported from host '$source'", 5);
191 return;
192 }
194 # fetch all user currently assigned to the client at login_users_db
195 my %currently_logged_in_user = ();
196 $sql_statement = "SELECT * FROM $main::login_users_tn WHERE client='$source'";
197 $db_res = $main::login_users_db->select_dbentry($sql_statement);
198 while( my($hit_id, $hit) = each(%{$db_res}) ) {
199 $currently_logged_in_user{$hit->{'user'}} = 1;
200 }
201 &main::daemon_log("$session_id DEBUG: logged in users from login_user_db: ".join(", ", keys(%currently_logged_in_user)), 7);
203 # update all reported users in login_user_db
204 my @logged_in_user = split(/\s+/, $login);
205 &main::daemon_log("$session_id DEBUG: logged in users reported from client: ".join(", ", @logged_in_user), 7);
206 foreach my $user (@logged_in_user) {
207 my %add_hash = ( table=>$main::login_users_tn,
208 primkey=> ['client', 'user'],
209 client=>$source,
210 user=>$user,
211 timestamp=>&get_time,
212 );
213 my ($res, $error_str) = $main::login_users_db->add_dbentry( \%add_hash );
214 if ($res != 0) {
215 &main::daemon_log("$session_id ERROR: cannot add entry to known_clients: $error_str");
216 return;
217 }
219 delete $currently_logged_in_user{$user};
220 }
222 # if there is still a user in %currently_logged_in_user
223 # although he is not reported by client
224 # then delete it from $login_user_db
225 foreach my $obsolete_user (keys(%currently_logged_in_user)) {
226 &main::daemon_log("$session_id WARNING: user '$obsolete_user' is currently not logged ".
227 "in at client '$source' but still found at login_user_db", 3);
228 my $sql_statement = "DELETE FROM $main::login_users_tn WHERE client='$source' AND user='$obsolete_user'";
229 my $res = $main::login_users_db->del_dbentry($sql_statement);
230 &main::daemon_log("$session_id WARNING: delete user '$obsolete_user' at client '$source' from login_user_db", 3);
231 }
233 return;
234 }
237 sub GOTOACTIVATION {
238 my ($msg, $msg_hash, $session_id) = @_;
239 my $header = @{$msg_hash->{'header'}}[0];
240 my $source = @{$msg_hash->{'source'}}[0];
241 my $macaddress = @{$msg_hash->{'macaddress'}}[0];
243 # test whether content is an empty hash or a string which is required
244 my $content = @{$msg_hash->{$header}}[0];
245 if(ref($content) eq "HASH") { $content = ""; }
247 # clean up header
248 $header =~ s/CLMSG_//g;
250 my $sql_statement = "UPDATE $main::job_queue_tn ".
251 "SET status='processing', progress='goto-activation', modified='1' ".
252 "WHERE status='processing' AND macaddress LIKE '$macaddress'";
253 &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
254 my $res = $main::job_db->update_dbentry($sql_statement);
255 &main::daemon_log("$session_id INFO: $header at '$macaddress'", 5);
256 return;
257 }
260 sub PROGRESS {
261 my ($msg, $msg_hash, $session_id) = @_;
262 my $header = @{$msg_hash->{'header'}}[0];
263 my $source = @{$msg_hash->{'source'}}[0];
264 my $macaddress = @{$msg_hash->{'macaddress'}}[0];
266 # test whether content is an empty hash or a string which is required
267 my $content = @{$msg_hash->{$header}}[0];
268 if(ref($content) eq "HASH") { $content = ""; }
270 # clean up header
271 $header =~ s/CLMSG_//g;
273 my $sql_statement = "UPDATE $main::job_queue_tn ".
274 "SET progress='$content', modified='1' ".
275 "WHERE status='processing' AND macaddress LIKE '$macaddress'";
276 &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
277 my $res = $main::job_db->update_dbentry($sql_statement);
278 &main::daemon_log("$session_id INFO: $header at '$macaddress' - $content%", 5);
280 return;
281 }
284 sub FAIREBOOT {
285 my ($msg, $msg_hash, $session_id) = @_;
286 my $header = @{$msg_hash->{'header'}}[0];
287 my $source = @{$msg_hash->{'source'}}[0];
288 my $macaddress = @{$msg_hash->{'macaddress'}}[0];
290 # test whether content is an empty hash or a string which is required
291 my $content = @{$msg_hash->{$header}}[0];
292 if(ref($content) eq "HASH") { $content = ""; }
294 # clean up header
295 $header =~ s/CLMSG_//g;
297 my $sql_statement = "UPDATE $main::job_queue_tn ".
298 "SET status='processing', result='$header "."$content', modified='1' ".
299 "WHERE status='processing' AND macaddress LIKE '$macaddress'";
300 &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
301 my $res = $main::job_db->update_dbentry($sql_statement);
302 &main::daemon_log("$session_id INFO: $header at '$macaddress' - '$content'", 5);
304 return;
305 }
308 sub TASKSKIP {
309 my ($msg, $msg_hash, $session_id) = @_;
310 my $header = @{$msg_hash->{'header'}}[0];
311 my $source = @{$msg_hash->{'source'}}[0];
312 my $macaddress = @{$msg_hash->{'macaddress'}}[0];
314 # test whether content is an empty hash or a string which is required
315 my $content = @{$msg_hash->{$header}}[0];
316 if(ref($content) eq "HASH") { $content = ""; }
318 # clean up header
319 $header =~ s/CLMSG_//g;
321 my $sql_statement = "UPDATE $main::job_queue_tn ".
322 "SET status='processing', result='$header "."$content', modified='1' ".
323 "WHERE status='processing' AND macaddress LIKE '$macaddress'";
324 &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
325 my $res = $main::job_db->update_dbentry($sql_statement);
326 &main::daemon_log("$session_id INFO: $header at '$macaddress' - '$content'", 5);
328 return;
329 }
332 sub TASKBEGIN {
333 my ($msg, $msg_hash, $session_id) = @_;
334 my $header = @{$msg_hash->{'header'}}[0];
335 my $source = @{$msg_hash->{'source'}}[0];
336 my $target = @{$msg_hash->{'target'}}[0];
337 my $macaddress = @{$msg_hash->{'macaddress'}}[0];
339 # test whether content is an empty hash or a string which is required
340 my $content = @{$msg_hash->{$header}}[0];
341 if(ref($content) eq "HASH") { $content = ""; }
343 # clean up header
344 $header =~ s/CLMSG_//g;
346 # TASKBEGIN eq finish or faiend
347 if (($content eq 'finish')
348 || ($content eq 'faiend')
349 || ($content eq 'savelog')
350 ) {
351 my $sql_statement = "UPDATE $main::job_queue_tn ".
352 "SET status='done', result='$header "."$content', modified='1' ".
353 "WHERE status='processing' AND macaddress LIKE '$macaddress'";
354 &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
355 my $res = $main::job_db->update_dbentry($sql_statement);
356 &main::daemon_log("$session_id INFO: $header at '$macaddress' - '$content'", 5);
358 # set fai_state to localboot
359 &main::change_fai_state('localboot', \@{$msg_hash->{'macaddress'}}, $session_id);
361 # TASKBEGIN eq chboot
362 } elsif (($content eq 'chboot')
363 || ($content eq 'test')
364 || ($content eq 'confdir')
365 ) {
366 # just ignor this client message
367 # do nothing
369 # other TASKBEGIN msgs
370 } else {
371 # select processing jobs for host
372 my $sql_statement = "SELECT * FROM $main::job_queue_tn WHERE status='processing' AND macaddress LIKE '$macaddress'";
373 &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
374 my $res = $main::job_db->select_dbentry($sql_statement);
376 # there is exactly one job entry in queue for this host
377 if (keys(%$res) == 1) {
378 &main::daemon_log("$session_id DEBUG: there is already one processing job in queue for host '$macaddress', run an update for this entry", 7);
379 my $sql_statement = "UPDATE $main::job_queue_tn ".
380 "SET result='$header $content', modified='1' ".
381 "WHERE status='processing' AND macaddress LIKE '$macaddress'";
382 my $err = $main::job_db->update_dbentry($sql_statement);
383 if (not defined $err) {
384 &main::daemon_log("$session_id ERROR: cannot update job_db entry: ".Dumper($err), 1);
385 }
387 # there is no entry or more than one enties
388 } else {
389 # in case of more than one running jobs in queue, delete all jobs
390 if (keys(%$res) > 1) {
391 &main::daemon_log("$session_id DEBUG: there are more than one processing job in queue for host '$macaddress', ".
392 "delete entries", 7);
394 # set job to status 'done', job will be deleted automatically
395 my $sql_statement = "UPDATE $main::job_queue_tn ".
396 "SET status='done', modified='1'".
397 "WHERE status='processing' AND macaddress LIKE '$macaddress'";
398 &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
399 my $res = $main::job_db->update_dbentry( $sql_statement );
401 }
403 # in case of no and more than one running jobs in queue, add one single job
404 # resolve plain name for host $macaddress
405 my $plain_name;
406 my $ldap_handle = &main::get_ldap_handle($session_id);
407 if( not defined $ldap_handle ) {
408 &main::daemon_log("$session_id ERROR: cannot connect to ldap", 1);
409 $plain_name = "none";
411 # try to fetch a 'real name'
412 } else {
413 my $mesg = $ldap_handle->search(
414 base => $main::ldap_base,
415 scope => 'sub',
416 attrs => ['cn'],
417 filter => "(macAddress=$macaddress)");
418 if($mesg->code) {
419 &main::daemon_log($mesg->error, 1);
420 $plain_name = "none";
421 } else {
422 my $entry= $mesg->entry(0);
423 $plain_name = $entry->get_value("cn");
424 }
425 }
428 &main::daemon_log("$session_id DEBUG: add job to queue for host '$macaddress'", 7);
429 my $func_dic = {table=>$main::job_queue_tn,
430 primkey=>['macaddress', 'headertag'],
431 timestamp=>&get_time,
432 status=>'processing',
433 result=>"$header $content",
434 progress=>'none',
435 headertag=>'trigger_action_reinstall',
436 targettag=>$target,
437 xmlmessage=>'none',
438 macaddress=>$macaddress,
439 plainname=>$plain_name,
440 modified=>'1',
441 siserver=>$source,
442 };
443 my ($err, $error_str) = $main::job_db->add_dbentry($func_dic);
444 if ($err != 0) {
445 &main::daemon_log("$session_id ERROR: cannot add entry to job_db: $error_str", 1);
446 }
447 }
448 }
450 return;
451 }
454 sub TASKEND {
455 my ($msg, $msg_hash, $session_id) = @_;
456 my $header = @{$msg_hash->{'header'}}[0];
457 my $target = @{$msg_hash->{'target'}}[0];
458 my $source = @{$msg_hash->{'source'}}[0];
459 my $macaddress = @{$msg_hash->{'macaddress'}}[0];
461 # test whether content is an empty hash or a string which is required
462 my $content = @{$msg_hash->{$header}}[0];
463 if(ref($content) eq "HASH") { $content = ""; }
465 # clean up header
466 $header =~ s/CLMSG_//g;
468 if ($content eq "savelog 0") {
469 &main::daemon_log("$session_id DEBUG: got savelog from host '$target' - job done", 7);
471 # set job to status 'done', job will be deleted automatically
472 my $sql_statement = "UPDATE $main::job_queue_tn ".
473 "SET status='done', modified='1'".
474 "WHERE status='processing' AND macaddress LIKE '$macaddress'";
475 &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
476 my $res = $main::job_db->update_dbentry( $sql_statement );
478 } else {
479 my $sql_statement = "UPDATE $main::job_queue_tn ".
480 "SET status='processing', result='$header "."$content', modified='1' ".
481 "WHERE status='processing' AND macaddress LIKE '$macaddress'";
482 &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
483 my $res = $main::job_db->update_dbentry($sql_statement);
484 &main::daemon_log("$session_id INFO: $header at '$macaddress' - '$content'", 5);
485 }
487 return;
488 }
491 sub TASKERROR {
492 my ($msg, $msg_hash, $session_id) = @_;
493 my $header = @{$msg_hash->{'header'}}[0];
494 my $source = @{$msg_hash->{'source'}}[0];
495 my $macaddress = @{$msg_hash->{'macaddress'}}[0];
497 # clean up header
498 $header =~ s/CLMSG_//g;
500 # test whether content is an empty hash or a string which is required
501 my $content = @{$msg_hash->{$header}}[0];
502 if(ref($content) eq "HASH") { $content = ""; }
504 # set fai_state to localboot
505 &main::change_fai_state('error', \@{$msg_hash->{'macaddress'}}, $session_id);
507 my $sql_statement = "UPDATE $main::job_queue_tn ".
508 "SET status='processing', result='$header "."$content', modified='1' ".
509 "WHERE status='processing' AND macaddress LIKE '$macaddress'";
510 &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
511 my $res = $main::job_db->update_dbentry($sql_statement);
512 &main::daemon_log("$session_id INFO: $header at '$macaddress' - '$content'", 5);
514 return;
515 }
518 sub HOOK {
519 my ($msg, $msg_hash, $session_id) = @_;
520 my $header = @{$msg_hash->{'header'}}[0];
521 my $source = @{$msg_hash->{'source'}}[0];
522 my $macaddress = @{$msg_hash->{'macaddress'}}[0];
524 # clean up header
525 $header =~ s/CLMSG_//g;
527 # test whether content is an empty hash or a string which is required
528 my $content = @{$msg_hash->{$header}}[0];
529 if(not ref($content) eq "STRING") { $content = ""; }
531 my $sql_statement = "UPDATE $main::job_queue_tn ".
532 "SET status='processing', result='$header "."$content', modified='1' ".
533 "WHERE status='processing' AND macaddress LIKE '$macaddress'";
534 &main::daemon_log("$session_id DEBUG: $sql_statement", 7);
535 my $res = $main::job_db->update_dbentry($sql_statement);
536 &main::daemon_log("$session_id INFO: $header at '$macaddress' - '$content'", 5);
538 return;
539 }
541 =pod
543 =head1 NAME
545 clMessages - Implementation of a GOsa-SI event module for GOsa-SI-server.
547 =head1 SYNOPSIS
549 use GOSA::GosaSupportDaemon;
550 use MIME::Base64;
552 =head1 DESCRIPTION
554 This GOsa-SI event module containing all functions to handle messages coming from GOsa-SI-clients.
556 This module will be automatically imported by GOsa-SI if it is under F</usr/lib/gosa-si/server/E<lt>PACKAGEMODULEE<gt>/> .
558 =head1 METHODS
560 =over 4
562 =item get_events ( )
564 =item confirm_usr_msg ( )
566 =item PROGRESS ( )
568 =item FAIREBOOT ( )
570 =item TASKSKIP ( )
572 =item TASKBEGIN ( )
574 =item TASKEND ( )
576 =item TASKERROR ( )
578 =item HOOK ( )
580 =item GOTOACTIVATION ( )
582 =item LOGIN ( )
584 =item LOGOUT ( )
586 =item CURRENTLY_LOGGED_IN ( )
588 =item save_fai_log ( )
590 =back
592 =head1 BUGS
594 Please report any bugs, or post any suggestions, to the GOsa mailing list E<lt>gosa-devel@oss.gonicus.deE<gt> or to L<https://oss.gonicus.de/labs/gosa>
596 =head1 COPYRIGHT
598 This code is part of GOsa (L<http://www.gosa-project.org>)
600 Copyright (C) 2003-2008 GONICUS GmbH
602 This program is distributed in the hope that it will be useful,
603 but WITHOUT ANY WARRANTY; without even the implied warranty of
604 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
605 GNU General Public License for more details.
607 =cut
610 1;