Code

* new function 'opsi_getPool' for plugin opsi_com.pm
[gosa.git] / gosa-si / server / events / opsi_com.pm
1 ## @file
2 # @details A GOsa-SI-server event module containing all functions for message handling.
3 # @brief Implementation of an event module for GOsa-SI-server. 
6 package opsi_com;
7 use Exporter;
8 @ISA = qw(Exporter);
9 my @events = (
10     "get_events",
11     "opsi_install_client",
12     "opsi_get_netboot_products",  
13     "opsi_get_local_products",
14     "opsi_get_client_hardware",
15     "opsi_get_client_software",
16     "opsi_get_product_properties",
17     "opsi_set_product_properties",
18     "opsi_list_clients",
19     "opsi_del_client",
20     "opsi_add_client",
21     "opsi_modify_client",
22     "opsi_add_product_to_client",
23     "opsi_del_product_from_client",
24         "opsi_createLicensePool",
25         "opsi_deleteLicensePool",
26         "opsi_createLicense",
27         "opsi_assignSoftwareLicenseToHost",
28         "opsi_unassignSoftwareLicenseFromHost",
29         "opsi_unassignAllSoftwareLicensesFromHost",
30         "opsi_getSoftwareLicense_hash",
31         "opsi_getLicensePool_hash",
32         "opsi_getSoftwareLicenseUsages_listOfHashes",
33         "opsi_getLicensePools_listOfHashes",
34         "opsi_getLicenseInformationForProduct",
35         "opsi_getPool",
36         "opsi_test",
37    );
38 @EXPORT = @events;
40 use strict;
41 use warnings;
42 use GOSA::GosaSupportDaemon;
43 use Data::Dumper;
44 use XML::Quote qw(:all);
46 BEGIN {}
48 END {}
50 # ----------------------------------------------------------------------------
51 #                          D E C L A R A T I O N S
52 # ----------------------------------------------------------------------------
54 my $licenseTyp_hash = { 'OEM'=>'', 'VOLUME'=>'', 'RETAIL'=>''};
58 # ----------------------------------------------------------------------------
59 #                            S U B R O U T I N E S
60 # ----------------------------------------------------------------------------
63 ################################
64 #
65 # @brief A function returning a list of functions which are exported by importing the module.
66 # @return List of all provided functions
67 #
68 sub get_events {
69     return \@events;
70 }
72 ################################
73 #
74 # @brief Checks if there is a specified tag and if the the tag has a content.
75 # @return 0|1
76 #
77 sub _check_xml_tag_is_ok {
78         my ($msg_hash,$tag) = @_;
79         if (not defined $msg_hash->{$tag}) {
80                 $_ = "message contains no tag '$tag'";
81                 return 0;
82         }
83         if (ref @{$msg_hash->{$tag}}[0] eq 'HASH') {
84                 $_ = "message tag '$tag' has no content";
85                 return  0;
86         }
87         return 1;
88 }
90 ################################
91 #
92 # @brief Writes the log line and returns the error message for GOsa.
93 #
94 sub _give_feedback {
95         my ($msg, $msg_hash, $session_id, $error) = @_;
96         &main::daemon_log("$session_id ERROR: $error: ".$msg, 1);
97         my $out_hash = &main::create_xml_hash("error_".@{$msg_hash->{'header'}}[0], $main::server_address, @{$msg_hash->{'source'}}[0], $error);
98         return &create_xml_string($out_hash);
99 }
101 ## @method opsi_add_product_to_client
102 # Adds an Opsi product to an Opsi client.
103 # @param msg - STRING - xml message with tags hostId and productId
104 # @param msg_hash - HASHREF - message information parsed into a hash
105 # @param session_id - INTEGER - POE session id of the processing of this message
106 # @return out_msg - STRING - feedback to GOsa in success and error case
107 sub opsi_add_product_to_client {
108     my ($msg, $msg_hash, $session_id) = @_;
109     my $header = @{$msg_hash->{'header'}}[0];
110     my $source = @{$msg_hash->{'source'}}[0];
111     my $target = @{$msg_hash->{'target'}}[0];
112     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
113     my ($hostId, $productId);
114     my $error = 0;
116     # Build return message
117     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
118     if (defined $forward_to_gosa) {
119         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
120     }
122     # Sanity check of needed parameter
123     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
124         $error++;
125         &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
126         &add_content2xml_hash($out_hash, "error", "hostId");
127         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
129     }
130     if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
131         $error++;
132         &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
133         &add_content2xml_hash($out_hash, "error", "productId");
134         &main::daemon_log("$session_id ERROR: no productId specified or procutId tag invalid: $msg", 1); 
135     }
137     if (not $error) {
138         # Get hostId
139         $hostId = @{$msg_hash->{'hostId'}}[0];
140         &add_content2xml_hash($out_hash, "hostId", $hostId);
142         # Get productID
143         $productId = @{$msg_hash->{'productId'}}[0];
144         &add_content2xml_hash($out_hash, "productId", $productId);
146         # Do an action request for all these -> "setup".
147         my $callobj = {
148             method  => 'setProductActionRequest',
149             params  => [ $productId, $hostId, "setup" ],
150             id  => 1, }; 
152         my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
153         my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
154         if ($sres_err){
155             &main::daemon_log("$session_id ERROR: cannot add product: ".$sres_err_string, 1);
156             &add_content2xml_hash($out_hash, "error", $sres_err_string);
157         }
158     } 
160     # return message
161     return ( &create_xml_string($out_hash) );
164 ## @method opsi_del_product_from_client
165 # Deletes an Opsi-product from an Opsi-client. 
166 # @param msg - STRING - xml message with tags hostId and productId
167 # @param msg_hash - HASHREF - message information parsed into a hash
168 # @param session_id - INTEGER - POE session id of the processing of this message
169 # @return out_msg - STRING - feedback to GOsa in success and error case
170 sub opsi_del_product_from_client {
171     my ($msg, $msg_hash, $session_id) = @_;
172     my $header = @{$msg_hash->{'header'}}[0];
173     my $source = @{$msg_hash->{'source'}}[0];
174     my $target = @{$msg_hash->{'target'}}[0];
175     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
176     my ($hostId, $productId);
177     my $error = 0;
178     my ($sres, $sres_err, $sres_err_string);
180     # Build return message
181     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
182     if (defined $forward_to_gosa) {
183         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
184     }
186     # Sanity check of needed parameter
187     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
188         $error++;
189         &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
190         &add_content2xml_hash($out_hash, "error", "hostId");
191         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
193     }
194     if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
195         $error++;
196         &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
197         &add_content2xml_hash($out_hash, "error", "productId");
198         &main::daemon_log("$session_id ERROR: no productId specified or procutId tag invalid: $msg", 1); 
199     }
201     # All parameter available
202     if (not $error) {
203         # Get hostId
204         $hostId = @{$msg_hash->{'hostId'}}[0];
205         &add_content2xml_hash($out_hash, "hostId", $hostId);
207         # Get productID
208         $productId = @{$msg_hash->{'productId'}}[0];
209         &add_content2xml_hash($out_hash, "productId", $productId);
212 #TODO : check the results for more than one entry which is currently installed
213         #$callobj = {
214         #    method  => 'getProductDependencies_listOfHashes',
215         #    params  => [ $productId ],
216         #    id  => 1, };
217         #
218         #my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
219         #my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
220         #if ($sres_err){
221         #  &main::daemon_log("ERROR: cannot perform dependency check: ".$sres_err_string, 1);
222         #  &add_content2xml_hash($out_hash, "error", $sres_err_string);
223         #  return ( &create_xml_string($out_hash) );
224         #}
227         # Check to get product action list 
228         my $callobj = {
229             method  => 'getPossibleProductActions_list',
230             params  => [ $productId ],
231             id  => 1, };
232         $sres = $main::opsi_client->call($main::opsi_url, $callobj);
233         ($sres_err, $sres_err_string) = &check_opsi_res($sres);
234         if ($sres_err){
235             &main::daemon_log("$session_id ERROR: cannot get product action list: ".$sres_err_string, 1);
236             &add_content2xml_hash($out_hash, "error", $sres_err_string);
237             $error++;
238         }
239     }
241     # Check action uninstall of product
242     if (not $error) {
243         my $uninst_possible= 0;
244         foreach my $r (@{$sres->result}) {
245             if ($r eq 'uninstall') {
246                 $uninst_possible= 1;
247             }
248         }
249         if (!$uninst_possible){
250             &main::daemon_log("$session_id ERROR: cannot uninstall product '$productId', product do not has the action 'uninstall'", 1);
251             &add_content2xml_hash($out_hash, "error", "cannot uninstall product '$productId', product do not has the action 'uninstall'");
252             $error++;
253         }
254     }
256     # Set product state to "none"
257     # Do an action request for all these -> "setup".
258     if (not $error) {
259         my $callobj = {
260             method  => 'setProductActionRequest',
261             params  => [ $productId, $hostId, "none" ],
262             id  => 1, 
263         }; 
264         $sres = $main::opsi_client->call($main::opsi_url, $callobj);
265         ($sres_err, $sres_err_string) = &check_opsi_res($sres);
266         if ($sres_err){
267             &main::daemon_log("$session_id ERROR: cannot delete product: ".$sres_err_string, 1);
268             &add_content2xml_hash($out_hash, "error", $sres_err_string);
269         }
270     }
272     # Return message
273     return ( &create_xml_string($out_hash) );
276 ## @method opsi_add_client
277 # Adds an Opsi client to Opsi.
278 # @param msg - STRING - xml message with tags hostId and macaddress
279 # @param msg_hash - HASHREF - message information parsed into a hash
280 # @param session_id - INTEGER - POE session id of the processing of this message
281 # @return out_msg - STRING - feedback to GOsa in success and error case
282 sub opsi_add_client {
283     my ($msg, $msg_hash, $session_id) = @_;
284     my $header = @{$msg_hash->{'header'}}[0];
285     my $source = @{$msg_hash->{'source'}}[0];
286     my $target = @{$msg_hash->{'target'}}[0];
287     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
288     my ($hostId, $mac);
289     my $error = 0;
290     my ($sres, $sres_err, $sres_err_string);
292     # Build return message with twisted target and source
293     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
294     if (defined $forward_to_gosa) {
295         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
296     }
298     # Sanity check of needed parameter
299     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
300         $error++;
301         &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
302         &add_content2xml_hash($out_hash, "error", "hostId");
303         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
304     }
305     if ((not exists $msg_hash->{'macaddress'}) || (@{$msg_hash->{'macaddress'}} != 1) || (@{$msg_hash->{'macaddress'}}[0] eq ref 'HASH'))  {
306         $error++;
307         &add_content2xml_hash($out_hash, "error_string", "no macaddress specified or macaddress tag invalid");
308         &add_content2xml_hash($out_hash, "error", "macaddress");
309         &main::daemon_log("$session_id ERROR: no macaddress specified or macaddress tag invalid: $msg", 1); 
310     }
312     if (not $error) {
313         # Get hostId
314         $hostId = @{$msg_hash->{'hostId'}}[0];
315         &add_content2xml_hash($out_hash, "hostId", $hostId);
317         # Get macaddress
318         $mac = @{$msg_hash->{'macaddress'}}[0];
319         &add_content2xml_hash($out_hash, "macaddress", $mac);
321         my $name= $hostId;
322         $name=~ s/^([^.]+).*$/$1/;
323         my $domain= $hostId;
324         $domain=~ s/^[^.]+\.(.*)$/$1/;
325         my ($description, $notes, $ip);
327         if (defined @{$msg_hash->{'description'}}[0]){
328             $description = @{$msg_hash->{'description'}}[0];
329         }
330         if (defined @{$msg_hash->{'notes'}}[0]){
331             $notes = @{$msg_hash->{'notes'}}[0];
332         }
333         if (defined @{$msg_hash->{'ip'}}[0]){
334             $ip = @{$msg_hash->{'ip'}}[0];
335         }
337         my $callobj;
338         $callobj = {
339             method  => 'createClient',
340             params  => [ $name, $domain, $description, $notes, $ip, $mac ],
341             id  => 1,
342         };
344         $sres = $main::opsi_client->call($main::opsi_url, $callobj);
345         ($sres_err, $sres_err_string) = &check_opsi_res($sres);
346         if ($sres_err){
347             &main::daemon_log("$session_id ERROR: cannot create client: ".$sres_err_string, 1);
348             &add_content2xml_hash($out_hash, "error", $sres_err_string);
349         } else {
350             &main::daemon_log("$session_id INFO: add opsi client '$hostId' with mac '$mac'", 5); 
351         }
352     }
354     # Return message
355     return ( &create_xml_string($out_hash) );
358 ## @method opsi_modify_client
359 # Modifies the parameters description, mac or notes for an Opsi client if the corresponding message tags are given.
360 # @param msg - STRING - xml message with tag hostId and optional description, mac or notes
361 # @param msg_hash - HASHREF - message information parsed into a hash
362 # @param session_id - INTEGER - POE session id of the processing of this message    
363 # @return out_msg - STRING - feedback to GOsa in success and error case
364 sub opsi_modify_client {
365     my ($msg, $msg_hash, $session_id) = @_;
366     my $header = @{$msg_hash->{'header'}}[0];
367     my $source = @{$msg_hash->{'source'}}[0];
368     my $target = @{$msg_hash->{'target'}}[0];
369     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
370     my $hostId;
371     my $error = 0;
372     my ($sres, $sres_err, $sres_err_string);
374     # Build return message with twisted target and source
375     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
376     if (defined $forward_to_gosa) {
377         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
378     }
380     # Sanity check of needed parameter
381     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
382         $error++;
383         &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
384         &add_content2xml_hash($out_hash, "error", "hostId");
385         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
386     }
388     if (not $error) {
389         # Get hostId
390         $hostId = @{$msg_hash->{'hostId'}}[0];
391         &add_content2xml_hash($out_hash, "hostId", $hostId);
392         my $name= $hostId;
393         $name=~ s/^([^.]+).*$/$1/;
394         my $domain= $hostId;
395         $domain=~ s/^[^.]+(.*)$/$1/;
397         # Modify description, notes or mac if defined
398         my ($description, $notes, $mac);
399         my $callobj;
400         if ((exists $msg_hash->{'description'}) && (@{$msg_hash->{'description'}} == 1) ){
401             $description = @{$msg_hash->{'description'}}[0];
402             $callobj = {
403                 method  => 'setHostDescription',
404                 params  => [ $hostId, $description ],
405                 id  => 1,
406             };
407             my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
408             my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
409             if ($sres_err){
410                 &main::daemon_log("ERROR: cannot set description: ".$sres_err_string, 1);
411                 &add_content2xml_hash($out_hash, "error", $sres_err_string);
412             }
413         }
414         if ((exists $msg_hash->{'notes'}) && (@{$msg_hash->{'notes'}} == 1)) {
415             $notes = @{$msg_hash->{'notes'}}[0];
416             $callobj = {
417                 method  => 'setHostNotes',
418                 params  => [ $hostId, $notes ],
419                 id  => 1,
420             };
421             my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
422             my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
423             if ($sres_err){
424                 &main::daemon_log("ERROR: cannot set notes: ".$sres_err_string, 1);
425                 &add_content2xml_hash($out_hash, "error", $sres_err_string);
426             }
427         }
428         if ((exists $msg_hash->{'mac'}) && (@{$msg_hash->{'mac'}} == 1)){
429             $mac = @{$msg_hash->{'mac'}}[0];
430             $callobj = {
431                 method  => 'setMacAddress',
432                 params  => [ $hostId, $mac ],
433                 id  => 1,
434             };
435             my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
436             my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
437             if ($sres_err){
438                 &main::daemon_log("ERROR: cannot set mac address: ".$sres_err_string, 1);
439                 &add_content2xml_hash($out_hash, "error", $sres_err_string);
440             }
441         }
442     }
444     # Return message
445     return ( &create_xml_string($out_hash) );
448     
449 ## @method opsi_get_netboot_products
450 # Get netboot products for specific host.
451 # @param msg - STRING - xml message with tag hostId
452 # @param msg_hash - HASHREF - message information parsed into a hash
453 # @param session_id - INTEGER - POE session id of the processing of this message
454 # @return out_msg - STRING - feedback to GOsa in success and error case
455 sub opsi_get_netboot_products {
456     my ($msg, $msg_hash, $session_id) = @_;
457     my $header = @{$msg_hash->{'header'}}[0];
458     my $source = @{$msg_hash->{'source'}}[0];
459     my $target = @{$msg_hash->{'target'}}[0];
460     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
461     my $hostId;
462     my $xml_msg;
464     # Build return message with twisted target and source
465     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
466     if (defined $forward_to_gosa) {
467         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
468     }
470     # Get hostId if defined
471     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1))  {
472         $hostId = @{$msg_hash->{'hostId'}}[0];
473         &add_content2xml_hash($out_hash, "hostId", $hostId);
474     }
476     &add_content2xml_hash($out_hash, "xxx", "");
477     $xml_msg = &create_xml_string($out_hash);
478     # For hosts, only return the products that are or get installed
479     my $callobj;
480     $callobj = {
481         method  => 'getNetBootProductIds_list',
482         params  => [ ],
483         id  => 1,
484     };
485     &main::daemon_log("$session_id DEBUG: send callobj to opsi_client: ".&opsi_callobj2string($callobj), 7);
486     &main::daemon_log("$session_id DEBUG: opsi_url $main::opsi_url", 7);
487     &main::daemon_log("$session_id DEBUG: waiting for answer from opsi_client!", 7);
488     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
489     &main::daemon_log("$session_id DEBUG: get answer from opsi_client", 7);
490     my %r = ();
491     for (@{$res->result}) { $r{$_} = 1 }
493     if (not &check_opsi_res($res)){
495         if (defined $hostId){
497             $callobj = {
498                 method  => 'getProductStates_hash',
499                 params  => [ $hostId ],
500                 id  => 1,
501             };
503             my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
504             if (not &check_opsi_res($hres)){
505                 my $htmp= $hres->result->{$hostId};
507                 # check state != not_installed or action == setup -> load and add
508                 foreach my $product (@{$htmp}){
510                     if (!defined ($r{$product->{'productId'}})){
511                         next;
512                     }
514                     # Now we've a couple of hashes...
515                     if ($product->{'installationStatus'} ne "not_installed" or
516                             $product->{'actionRequest'} eq "setup"){
517                         my $state= "<state>".$product->{'installationStatus'}."</state><action>".$product->{'actionRequest'}."</action>";
519                         $callobj = {
520                             method  => 'getProduct_hash',
521                             params  => [ $product->{'productId'} ],
522                             id  => 1,
523                         };
525                         my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
526                         if (not &check_opsi_res($sres)){
527                             my $tres= $sres->result;
529                             my $name= xml_quote($tres->{'name'});
530                             my $r= $product->{'productId'};
531                             my $description= xml_quote($tres->{'description'});
532                             $name=~ s/\//\\\//;
533                             $description=~ s/\//\\\//;
534                             $xml_msg=~ s/<xxx><\/xxx>/\n<item><productId>$r<\/productId><name>$name<\/name><description>$description<\/description><\/item>$state<xxx><\/xxx>/;
535                         }
536                     }
537                 }
539             }
541         } else {
542             foreach my $r (@{$res->result}) {
543                 $callobj = {
544                     method  => 'getProduct_hash',
545                     params  => [ $r ],
546                     id  => 1,
547                 };
549                 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
550                 if (not &check_opsi_res($sres)){
551                     my $tres= $sres->result;
553                     my $name= xml_quote($tres->{'name'});
554                     my $description= xml_quote($tres->{'description'});
555                     $name=~ s/\//\\\//;
556                     $description=~ s/\//\\\//;
557                     $xml_msg=~ s/<xxx><\/xxx>/\n<item><productId>$r<\/productId><name>$name<\/name><description>$description<\/description><\/item><xxx><\/xxx>/;
558                 }
559             }
561         }
562     }
563     $xml_msg=~ s/<xxx><\/xxx>//;
565     # Return message
566     return ( $xml_msg );
570 ## @method opsi_get_product_properties
571 # Get product properties for a product and a specific host or gobally for a product.
572 # @param msg - STRING - xml message with tags productId and optional hostId
573 # @param msg_hash - HASHREF - message information parsed into a hash
574 # @param session_id - INTEGER - POE session id of the processing of this message
575 # @return out_msg - STRING - feedback to GOsa in success and error case
576 sub opsi_get_product_properties {
577     my ($msg, $msg_hash, $session_id) = @_;
578     my $header = @{$msg_hash->{'header'}}[0];
579     my $source = @{$msg_hash->{'source'}}[0];
580     my $target = @{$msg_hash->{'target'}}[0];
581     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
582     my ($hostId, $productId);
583     my $xml_msg;
585     # Build return message with twisted target and source
586     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
587     if (defined $forward_to_gosa) {
588         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
589     }
591     # Sanity check of needed parameter
592     if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH'))  {
593         &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
594         &add_content2xml_hash($out_hash, "error", "productId");
595         &main::daemon_log("$session_id ERROR: no productId specified or productId tag invalid: $msg", 1); 
597         # Return message
598         return ( &create_xml_string($out_hash) );
599     }
601     # Get productid
602     $productId = @{$msg_hash->{'productId'}}[0];
603     &add_content2xml_hash($out_hash, "producId", "$productId");
605     # Get hostId if defined
606     if (defined @{$msg_hash->{'hostId'}}[0]){
607       $hostId = @{$msg_hash->{'hostId'}}[0];
608       &add_content2xml_hash($out_hash, "hostId", $hostId);
609     }
611     # Load actions
612     my $callobj = {
613       method  => 'getPossibleProductActions_list',
614       params  => [ $productId ],
615       id  => 1,
616     };
617     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
618     if (not &check_opsi_res($res)){
619       foreach my $action (@{$res->result}){
620         &add_content2xml_hash($out_hash, "action", $action);
621       }
622     }
624     # Add place holder
625     &add_content2xml_hash($out_hash, "xxx", "");
627     # Move to XML string
628     $xml_msg= &create_xml_string($out_hash);
630     # JSON Query
631     if (defined $hostId){
632       $callobj = {
633           method  => 'getProductProperties_hash',
634           params  => [ $productId, $hostId ],
635           id  => 1,
636       };
637     } else {
638       $callobj = {
639           method  => 'getProductProperties_hash',
640           params  => [ $productId ],
641           id  => 1,
642       };
643     }
644     $res = $main::opsi_client->call($main::opsi_url, $callobj);
646     # JSON Query 2
647     $callobj = {
648       method  => 'getProductPropertyDefinitions_listOfHashes',
649       params  => [ $productId ],
650       id  => 1,
651     };
653     # Assemble options
654     my $res2 = $main::opsi_client->call($main::opsi_url, $callobj);
655     my $values = {};
656     my $descriptions = {};
657     if (not &check_opsi_res($res2)){
658         my $r= $res2->result;
660           foreach my $entr (@$r){
661             # Unroll values
662             my $cnv;
663             if (UNIVERSAL::isa( $entr->{'values'}, "ARRAY" )){
664               foreach my $v (@{$entr->{'values'}}){
665                 $cnv.= "<value>$v</value>";
666               }
667             } else {
668               $cnv= $entr->{'values'};
669             }
670             $values->{$entr->{'name'}}= $cnv;
671             $descriptions->{$entr->{'name'}}= "<description>".$entr->{'description'}."</description>";
672           }
673     }
675     if (not &check_opsi_res($res)){
676         my $r= $res->result;
677         foreach my $key (keys %{$r}) {
678             my $item= "\n<item>";
679             my $value= $r->{$key};
680             my $dsc= "";
681             my $vals= "";
682             if (defined $descriptions->{$key}){
683               $dsc= $descriptions->{$key};
684             }
685             if (defined $values->{$key}){
686               $vals= $values->{$key};
687             }
688             $item.= "<$key>$dsc<default>".xml_quote($value)."</default>$vals</$key>";
689             $item.= "</item>";
690             $xml_msg=~ s/<xxx><\/xxx>/$item<xxx><\/xxx>/;
691         }
692     }
694     $xml_msg=~ s/<xxx><\/xxx>//;
696     # Return message
697     return ( $xml_msg );
701 ## @method opsi_set_product_properties
702 # Set product properities for a specific host or globaly. Message needs one xml tag 'item' and within one xml tag 'name' and 'value'. The xml tags action and state are optional.
703 # @param msg - STRING - xml message with tags productId, action, state and optional hostId, action and state
704 # @param msg_hash - HASHREF - message information parsed into a hash
705 # @param session_id - INTEGER - POE session id of the processing of this message
706 # @return out_msg - STRING - feedback to GOsa in success and error case
707 sub opsi_set_product_properties {
708     my ($msg, $msg_hash, $session_id) = @_;
709     my $header = @{$msg_hash->{'header'}}[0];
710     my $source = @{$msg_hash->{'source'}}[0];
711     my $target = @{$msg_hash->{'target'}}[0];
712     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
713     my ($productId, $hostId);
715     # Build return message with twisted target and source
716     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
717     if (defined $forward_to_gosa) {
718         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
719     }
721     # Sanity check of needed parameter
722     if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH'))  {
723         &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
724         &add_content2xml_hash($out_hash, "error", "productId");
725         &main::daemon_log("$session_id ERROR: no productId specified or productId tag invalid: $msg", 1); 
726         return ( &create_xml_string($out_hash) );
727     }
728     if (not exists $msg_hash->{'item'}) {
729         &add_content2xml_hash($out_hash, "error_string", "message needs one xml-tag 'item' and within the xml-tags 'name' and 'value'");
730         &add_content2xml_hash($out_hash, "error", "item");
731         &main::daemon_log("$session_id ERROR: message needs one xml-tag 'item' and within the xml-tags 'name' and 'value': $msg", 1); 
732         return ( &create_xml_string($out_hash) );
733     } else {
734         if ((not exists @{$msg_hash->{'item'}}[0]->{'name'}) || (@{@{$msg_hash->{'item'}}[0]->{'name'}} != 1 )) {
735             &add_content2xml_hash($out_hash, "error_string", "message needs within the xml-tag 'item' one xml-tags 'name'");
736             &add_content2xml_hash($out_hash, "error", "name");
737             &main::daemon_log("$session_id ERROR: message needs within the xml-tag 'item' one xml-tags 'name': $msg", 1); 
738             return ( &create_xml_string($out_hash) );
739         }
740         if ((not exists @{$msg_hash->{'item'}}[0]->{'value'}) || (@{@{$msg_hash->{'item'}}[0]->{'value'}} != 1 )) {
741             &add_content2xml_hash($out_hash, "error_string", "message needs within the xml-tag 'item' one xml-tags 'value'");
742             &add_content2xml_hash($out_hash, "error", "value");
743             &main::daemon_log("$session_id ERROR: message needs within the xml-tag 'item' one xml-tags 'value': $msg", 1); 
744             return ( &create_xml_string($out_hash) );
745         }
746     }
747     # if no hostId is given, set_product_properties will act on globally
748     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} > 1))  {
749         &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
750         &add_content2xml_hash($out_hash, "error", "hostId");
751         &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1); 
752         return ( &create_xml_string($out_hash) );
753     }
755         
756     # Get productId
757     $productId =  @{$msg_hash->{'productId'}}[0];
758     &add_content2xml_hash($out_hash, "productId", $productId);
760     # Get hostId if defined
761     if (exists $msg_hash->{'hostId'}){
762         $hostId = @{$msg_hash->{'hostId'}}[0];
763         &add_content2xml_hash($out_hash, "hostId", $hostId);
764     }
766     # Set product states if requested
767     if (defined @{$msg_hash->{'action'}}[0]){
768         &_set_action($productId, @{$msg_hash->{'action'}}[0], $hostId);
769     }
770     if (defined @{$msg_hash->{'state'}}[0]){
771         &_set_state($productId, @{$msg_hash->{'state'}}[0], $hostId);
772     }
774     # Find properties
775     foreach my $item (@{$msg_hash->{'item'}}){
776         # JSON Query
777         my $callobj;
779         if (defined $hostId){
780             $callobj = {
781                 method  => 'setProductProperty',
782                 params  => [ $productId, $item->{'name'}[0], $item->{'value'}[0], $hostId ],
783                 id  => 1,
784             };
785         } else {
786             $callobj = {
787                 method  => 'setProductProperty',
788                 params  => [ $productId, $item->{'name'}[0], $item->{'value'}[0] ],
789                 id  => 1,
790             };
791         }
793         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
794         my ($res_err, $res_err_string) = &check_opsi_res($res);
796         if ($res_err){
797             &main::daemon_log("$session_id ERROR: communication failed while setting '".$item->{'name'}[0]."': ".$res_err_string, 1);
798             &add_content2xml_hash($out_hash, "error", $res_err_string);
799         }
800     }
803     # Return message
804     return ( &create_xml_string($out_hash) );
808 ## @method opsi_get_client_hardware
809 # Reports client hardware inventory.
810 # @param msg - STRING - xml message with tag hostId
811 # @param msg_hash - HASHREF - message information parsed into a hash
812 # @param session_id - INTEGER - POE session id of the processing of this message
813 # @return out_msg - STRING - feedback to GOsa in success and error case
814 sub opsi_get_client_hardware {
815     my ($msg, $msg_hash, $session_id) = @_;
816     my $header = @{$msg_hash->{'header'}}[0];
817     my $source = @{$msg_hash->{'source'}}[0];
818     my $target = @{$msg_hash->{'target'}}[0];
819     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
820     my $hostId;
821     my $error = 0;
822     my $xml_msg;
824     # Build return message with twisted target and source
825     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
826     if (defined $forward_to_gosa) {
827       &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
828     }
830     # Sanity check of needed parameter
831     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
832         $error++;
833         &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
834         &add_content2xml_hash($out_hash, "error", "hostId");
835         &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1); 
836     }
838     if (not $error) {
840     # Get hostId
841         $hostId = @{$msg_hash->{'hostId'}}[0];
842         &add_content2xml_hash($out_hash, "hostId", "$hostId");
843         &add_content2xml_hash($out_hash, "xxx", "");
844     }    
846     # Move to XML string
847     $xml_msg= &create_xml_string($out_hash);
848     
849     if (not $error) {
851     # JSON Query
852         my $callobj = {
853             method  => 'getHardwareInformation_hash',
854             params  => [ $hostId ],
855             id  => 1,
856         };
858         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
859         if (not &check_opsi_res($res)){
860             my $result= $res->result;
861             if (ref $result eq "HASH") {
862                 foreach my $r (keys %{$result}){
863                     my $item= "\n<item><id>".xml_quote($r)."</id>";
864                     my $value= $result->{$r};
865                     foreach my $sres (@{$value}){
867                         foreach my $dres (keys %{$sres}){
868                             if (defined $sres->{$dres}){
869                                 $item.= "<$dres>".xml_quote($sres->{$dres})."</$dres>";
870                             }
871                         }
873                     }
874                     $item.= "</item>";
875                     $xml_msg=~ s%<xxx></xxx>%$item<xxx></xxx>%;
877                 }
878             }
879         }
881         $xml_msg=~ s/<xxx><\/xxx>//;
883     }
885     # Return message
886     return ( $xml_msg );
890 ## @method opsi_list_clients
891 # Reports all Opsi clients. 
892 # @param msg - STRING - xml message 
893 # @param msg_hash - HASHREF - message information parsed into a hash
894 # @param session_id - INTEGER - POE session id of the processing of this message
895 # @return out_msg - STRING - feedback to GOsa in success and error case
896 sub opsi_list_clients {
897     my ($msg, $msg_hash, $session_id) = @_;
898     my $header = @{$msg_hash->{'header'}}[0];
899     my $source = @{$msg_hash->{'source'}}[0];
900     my $target = @{$msg_hash->{'target'}}[0];
901     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
903     # Build return message with twisted target and source
904     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
905     if (defined $forward_to_gosa) {
906       &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
907     }
908     &add_content2xml_hash($out_hash, "xxx", "");
910     # Move to XML string
911     my $xml_msg= &create_xml_string($out_hash);
913     # JSON Query
914     my $callobj = {
915         method  => 'getClients_listOfHashes',
916         params  => [ ],
917         id  => 1,
918     };
919     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
920     if (not &check_opsi_res($res)){
921         foreach my $host (@{$res->result}){
922             my $item= "\n<item><name>".$host->{'hostId'}."</name>";
923             if (defined($host->{'description'})){
924                 $item.= "<description>".xml_quote($host->{'description'})."</description>";
925             }
926             if (defined($host->{'notes'})){
927                 $item.= "<notes>".xml_quote($host->{'notes'})."</notes>";
928             }
929             if (defined($host->{'lastSeen'})){
930                 $item.= "<lastSeen>".xml_quote($host->{'lastSeen'})."</lastSeen>";
931             }
933             $callobj = {
934               method  => 'getIpAddress',
935               params  => [ $host->{'hostId'} ],
936               id  => 1,
937             };
938             my $sres= $main::opsi_client->call($main::opsi_url, $callobj);
939             if ( not &check_opsi_res($sres)){
940               $item.= "<ip>".xml_quote($sres->result)."</ip>";
941             }
943             $callobj = {
944               method  => 'getMacAddress',
945               params  => [ $host->{'hostId'} ],
946               id  => 1,
947             };
948             $sres= $main::opsi_client->call($main::opsi_url, $callobj);
949             if ( not &check_opsi_res($sres)){
950                 $item.= "<mac>".xml_quote($sres->result)."</mac>";
951             }
952             $item.= "</item>";
953             $xml_msg=~ s%<xxx></xxx>%$item<xxx></xxx>%;
954         }
955     }
957     $xml_msg=~ s/<xxx><\/xxx>//;
958     return ( $xml_msg );
963 ## @method opsi_get_client_software
964 # Reports client software inventory.
965 # @param msg - STRING - xml message with tag hostId
966 # @param msg_hash - HASHREF - message information parsed into a hash
967 # @param session_id - INTEGER - POE session id of the processing of this message
968 # @return out_msg - STRING - feedback to GOsa in success and error case
969 sub opsi_get_client_software {
970     my ($msg, $msg_hash, $session_id) = @_;
971     my $header = @{$msg_hash->{'header'}}[0];
972     my $source = @{$msg_hash->{'source'}}[0];
973     my $target = @{$msg_hash->{'target'}}[0];
974     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
975     my $error = 0;
976     my $hostId;
977     my $xml_msg;
979     # Build return message with twisted target and source
980     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
981     if (defined $forward_to_gosa) {
982       &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
983     }
985     # Sanity check of needed parameter
986     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
987         $error++;
988         &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
989         &add_content2xml_hash($out_hash, "error", "hostId");
990         &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1); 
991     }
993     if (not $error) {
995     # Get hostId
996         $hostId = @{$msg_hash->{'hostId'}}[0];
997         &add_content2xml_hash($out_hash, "hostId", "$hostId");
998         &add_content2xml_hash($out_hash, "xxx", "");
999     }
1001     $xml_msg= &create_xml_string($out_hash);
1003     if (not $error) {
1005     # JSON Query
1006         my $callobj = {
1007             method  => 'getSoftwareInformation_hash',
1008             params  => [ $hostId ],
1009             id  => 1,
1010         };
1012         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1013         if (not &check_opsi_res($res)){
1014             my $result= $res->result;
1015         }
1017         $xml_msg=~ s/<xxx><\/xxx>//;
1019     }
1021     # Return message
1022     return ( $xml_msg );
1026 ## @method opsi_get_local_products
1027 # Reports product for given hostId or globally.
1028 # @param msg - STRING - xml message with optional tag hostId
1029 # @param msg_hash - HASHREF - message information parsed into a hash
1030 # @param session_id - INTEGER - POE session id of the processing of this message
1031 # @return out_msg - STRING - feedback to GOsa in success and error case
1032 sub opsi_get_local_products {
1033     my ($msg, $msg_hash, $session_id) = @_;
1034     my $header = @{$msg_hash->{'header'}}[0];
1035     my $source = @{$msg_hash->{'source'}}[0];
1036     my $target = @{$msg_hash->{'target'}}[0];
1037     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1038     my $hostId;
1040     # Build return message with twisted target and source
1041     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1042     if (defined $forward_to_gosa) {
1043         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1044     }
1045     &add_content2xml_hash($out_hash, "xxx", "");
1047     # Get hostId if defined
1048     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1))  {
1049         $hostId = @{$msg_hash->{'hostId'}}[0];
1050         &add_content2xml_hash($out_hash, "hostId", $hostId);
1051     }
1053     # Move to XML string
1054     my $xml_msg= &create_xml_string($out_hash);
1056     # For hosts, only return the products that are or get installed
1057     my $callobj;
1058     $callobj = {
1059         method  => 'getLocalBootProductIds_list',
1060         params  => [ ],
1061         id  => 1,
1062     };
1064     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1065     my %r = ();
1066     for (@{$res->result}) { $r{$_} = 1 }
1068     if (not &check_opsi_res($res)){
1070         if (defined $hostId){
1071             $callobj = {
1072                 method  => 'getProductStates_hash',
1073                 params  => [ $hostId ],
1074                 id  => 1,
1075             };
1077             my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
1078             if (not &check_opsi_res($hres)){
1079                 my $htmp= $hres->result->{$hostId};
1081                 # Check state != not_installed or action == setup -> load and add
1082                 foreach my $product (@{$htmp}){
1084                     if (!defined ($r{$product->{'productId'}})){
1085                         next;
1086                     }
1088                     # Now we've a couple of hashes...
1089                     if ($product->{'installationStatus'} ne "not_installed" or
1090                             $product->{'actionRequest'} eq "setup"){
1091                         my $state= "<state>".$product->{'installationStatus'}."</state><action>".$product->{'actionRequest'}."</action>";
1093                         $callobj = {
1094                             method  => 'getProduct_hash',
1095                             params  => [ $product->{'productId'} ],
1096                             id  => 1,
1097                         };
1099                         my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
1100                         if (not &check_opsi_res($sres)){
1101                             my $tres= $sres->result;
1103                             my $name= xml_quote($tres->{'name'});
1104                             my $r= $product->{'productId'};
1105                             my $description= xml_quote($tres->{'description'});
1106                             $name=~ s/\//\\\//;
1107                             $description=~ s/\//\\\//;
1108                             $xml_msg=~ s/<xxx><\/xxx>/\n<item><productId>$r<\/productId><name>$name<\/name><description>$description<\/description><\/item>$state<xxx><\/xxx>/;
1109                         }
1111                     }
1112                 }
1114             }
1116         } else {
1117             foreach my $r (@{$res->result}) {
1118                 $callobj = {
1119                     method  => 'getProduct_hash',
1120                     params  => [ $r ],
1121                     id  => 1,
1122                 };
1124                 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
1125                 if (not &check_opsi_res($sres)){
1126                     my $tres= $sres->result;
1128                     my $name= xml_quote($tres->{'name'});
1129                     my $description= xml_quote($tres->{'description'});
1130                     $name=~ s/\//\\\//;
1131                     $description=~ s/\//\\\//;
1132                     $xml_msg=~ s/<xxx><\/xxx>/\n<item><productId>$r<\/productId><name>$name<\/name><description>$description<\/description><\/item><xxx><\/xxx>/;
1133                 }
1135             }
1137         }
1138     }
1140     $xml_msg=~ s/<xxx><\/xxx>//;
1142     # Retrun Message
1143     return ( $xml_msg );
1147 ## @method opsi_del_client
1148 # Deletes a client from Opsi.
1149 # @param msg - STRING - xml message with tag hostId
1150 # @param msg_hash - HASHREF - message information parsed into a hash
1151 # @param session_id - INTEGER - POE session id of the processing of this message
1152 # @return out_msg - STRING - feedback to GOsa in success and error case
1153 sub opsi_del_client {
1154     my ($msg, $msg_hash, $session_id) = @_;
1155     my $header = @{$msg_hash->{'header'}}[0];
1156     my $source = @{$msg_hash->{'source'}}[0];
1157     my $target = @{$msg_hash->{'target'}}[0];
1158     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1159     my $hostId;
1160     my $error = 0;
1162     # Build return message with twisted target and source
1163     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1164     if (defined $forward_to_gosa) {
1165       &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1166     }
1168     # Sanity check of needed parameter
1169     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
1170         $error++;
1171         &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
1172         &add_content2xml_hash($out_hash, "error", "hostId");
1173         &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1); 
1174     }
1176     if (not $error) {
1178     # Get hostId
1179         $hostId = @{$msg_hash->{'hostId'}}[0];
1180         &add_content2xml_hash($out_hash, "hostId", "$hostId");
1182     # JSON Query
1183         my $callobj = {
1184             method  => 'deleteClient',
1185             params  => [ $hostId ],
1186             id  => 1,
1187         };
1188         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1189     }
1191     # Move to XML string
1192     my $xml_msg= &create_xml_string($out_hash);
1194     # Return message
1195     return ( $xml_msg );
1199 ## @method opsi_install_client
1200 # Set a client in Opsi to install and trigger a wake on lan message (WOL).  
1201 # @param msg - STRING - xml message with tags hostId, macaddress
1202 # @param msg_hash - HASHREF - message information parsed into a hash
1203 # @param session_id - INTEGER - POE session id of the processing of this message
1204 # @return out_msg - STRING - feedback to GOsa in success and error case
1205 sub opsi_install_client {
1206     my ($msg, $msg_hash, $session_id) = @_;
1207     my $header = @{$msg_hash->{'header'}}[0];
1208     my $source = @{$msg_hash->{'source'}}[0];
1209     my $target = @{$msg_hash->{'target'}}[0];
1210     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1213     my ($hostId, $macaddress);
1215     my $error = 0;
1216     my @out_msg_l;
1218     # Build return message with twisted target and source
1219     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1220     if (defined $forward_to_gosa) {
1221         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1222     }
1224     # Sanity check of needed parameter
1225     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
1226         $error++;
1227         &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
1228         &add_content2xml_hash($out_hash, "error", "hostId");
1229         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
1230     }
1231     if ((not exists $msg_hash->{'macaddress'}) || (@{$msg_hash->{'macaddress'}} != 1) || (@{$msg_hash->{'macaddress'}}[0] eq ref 'HASH') )  {
1232         $error++;
1233         &add_content2xml_hash($out_hash, "error_string", "no macaddress specified or macaddress tag invalid");
1234         &add_content2xml_hash($out_hash, "error", "macaddress");
1235         &main::daemon_log("$session_id ERROR: no macaddress specified or macaddress tag invalid: $msg", 1); 
1236     } else {
1237         if ((exists $msg_hash->{'macaddress'}) && 
1238                 ($msg_hash->{'macaddress'}[0] =~ /^([0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2})$/i)) {  
1239             $macaddress = $1; 
1240         } else { 
1241             $error ++; 
1242             &add_content2xml_hash($out_hash, "error_string", "given mac address is not correct");
1243             &add_content2xml_hash($out_hash, "error", "macaddress");
1244             &main::daemon_log("$session_id ERROR: given mac address is not correct: $msg", 1); 
1245         }
1246     }
1248     if (not $error) {
1250     # Get hostId
1251         $hostId = @{$msg_hash->{'hostId'}}[0];
1252         &add_content2xml_hash($out_hash, "hostId", "$hostId");
1254         # Load all products for this host with status != "not_installed" or actionRequest != "none"
1255         my $callobj = {
1256             method  => 'getProductStates_hash',
1257             params  => [ $hostId ],
1258             id  => 1,
1259         };
1261         my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
1262         if (not &check_opsi_res($hres)){
1263             my $htmp= $hres->result->{$hostId};
1265             # check state != not_installed or action == setup -> load and add
1266             foreach my $product (@{$htmp}){
1267                 # Now we've a couple of hashes...
1268                 if ($product->{'installationStatus'} ne "not_installed" or
1269                         $product->{'actionRequest'} ne "none"){
1271                     # Do an action request for all these -> "setup".
1272                     $callobj = {
1273                         method  => 'setProductActionRequest',
1274                         params  => [ $product->{'productId'}, $hostId, "setup" ],
1275                         id  => 1,
1276                     };
1277                     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1278                     my ($res_err, $res_err_string) = &check_opsi_res($res);
1279                     if ($res_err){
1280                         &main::daemon_log("$session_id ERROR: cannot set product action request for '$hostId': ".$product->{'productId'}, 1);
1281                     } else {
1282                         &main::daemon_log("$session_id INFO: requesting 'setup' for '".$product->{'productId'}."' on $hostId", 1);
1283                     }
1284                 }
1285             }
1286         }
1287         push(@out_msg_l, &create_xml_string($out_hash));
1288     
1290     # Build wakeup message for client
1291         if (not $error) {
1292             my $wakeup_hash = &create_xml_hash("trigger_wake", "GOSA", "KNOWN_SERVER");
1293             &add_content2xml_hash($wakeup_hash, 'macaddress', $macaddress);
1294             my $wakeup_msg = &create_xml_string($wakeup_hash);
1295             push(@out_msg_l, $wakeup_msg);
1297             # invoke trigger wake for this gosa-si-server
1298             &main::server_server_com::trigger_wake($wakeup_msg, $wakeup_hash, $session_id);
1299         }
1300     }
1301     
1302     # Return messages
1303     return @out_msg_l;
1307 ## @method _set_action
1308 # Set action for an Opsi client
1309 # @param product - STRING - Opsi product
1310 # @param action - STRING - action
1311 # @param hostId - STRING - Opsi hostId
1312 sub _set_action {
1313   my $product= shift;
1314   my $action = shift;
1315   my $hostId = shift;
1316   my $callobj;
1318   $callobj = {
1319     method  => 'setProductActionRequest',
1320     params  => [ $product, $hostId, $action],
1321     id  => 1,
1322   };
1324   $main::opsi_client->call($main::opsi_url, $callobj);
1327 ## @method _set_state
1328 # Set state for an Opsi client
1329 # @param product - STRING - Opsi product
1330 # @param action - STRING - state
1331 # @param hostId - STRING - Opsi hostId
1332 sub _set_state {
1333   my $product = shift;
1334   my $state = shift;
1335   my $hostId = shift;
1336   my $callobj;
1338   $callobj = {
1339     method  => 'setProductState',
1340     params  => [ $product, $hostId, $state ],
1341     id  => 1,
1342   };
1344   $main::opsi_client->call($main::opsi_url, $callobj);
1347 # TODO
1348 ################################
1350 # @brief Create a license pool at Opsi server.
1351 # @param licensePoolId The name of the pool (optional). 
1352 # @param description The description of the pool (optional).
1353 # @param productIds A list of assigned porducts of the pool (optional). 
1354 # @param windowsSoftwareIds A list of windows software IDs associated to the pool (optional). 
1356 sub opsi_createLicensePool {
1357     my ($msg, $msg_hash, $session_id) = @_;
1358     my $header = @{$msg_hash->{'header'}}[0];
1359     my $source = @{$msg_hash->{'source'}}[0];
1360     my $target = @{$msg_hash->{'target'}}[0];
1361         my $out_hash;
1362         my $licensePoolId = defined $msg_hash->{'licensePoolId'} ? @{$msg_hash->{'licensePoolId'}}[0] : undef;
1363         my $description = defined $msg_hash->{'description'} ? @{$msg_hash->{'description'}}[0] : undef;
1364         my @productIds = defined $msg_hash->{'productIds'} ? $msg_hash->{'productIds'} : undef;
1365         my @windowsSoftwareIds = defined $msg_hash->{'windowsSoftwareIds'} ? $msg_hash->{'windowsSoftwareIds'} : undef;
1367         # Create license Pool
1368     my $callobj = {
1369         method  => 'createLicensePool',
1370         params  => [ $licensePoolId, $description, @productIds, @windowsSoftwareIds],
1371         id  => 1,
1372     };
1373     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1375         # Check Opsi error
1376         my ($res_error, $res_error_str) = &check_opsi_res($res);
1377         if ($res_error){
1378                 # Create error message
1379                 &main::daemon_log("$session_id ERROR: cannot create license pool at Opsi server: ".$res_error_str, 1);
1380                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1381                 return ( &create_xml_string($out_hash) );
1382         }
1384         # Create function result message
1385         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source, $res->result);
1387         return ( &create_xml_string($out_hash) );
1390 ################################
1392 # @brief Return licensePoolId, description, productIds and windowsSoftwareIds for all found license pools.
1394 sub opsi_getLicensePools_listOfHashes {
1395     my ($msg, $msg_hash, $session_id) = @_;
1396     my $header = @{$msg_hash->{'header'}}[0];
1397     my $source = @{$msg_hash->{'source'}}[0];
1398         my $out_hash;
1400         # Fetch infos from Opsi server
1401     my $callobj = {
1402         method  => 'getLicensePools_listOfHashes',
1403         params  => [ ],
1404         id  => 1,
1405     };
1406     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1408         # Check Opsi error
1409         my ($res_error, $res_error_str) = &check_opsi_res($res);
1410         if ($res_error){
1411                 # Create error message
1412                 &main::daemon_log("$session_id ERROR: cannot get license pool ID list from Opsi server: ".$res_error_str, 1);
1413                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1414                 return ( &create_xml_string($out_hash) );
1415         }
1417         # Create function result message
1418         my $res_hash = { 'hit'=> [] };
1419         foreach my $licensePool ( @{$res->result}) {
1420                 my $licensePool_hash = { 'licensePoolId' => [$licensePool->{'licensePoolId'}],
1421                         'description' => [$licensePool->{'description'}],
1422                         'productIds' => $licensePool->{'productIds'},
1423                         'windowsSoftwareIds' => $licensePool->{'windowsSoftwareIds'},
1424                         };
1425                 push( @{$res_hash->{hit}}, $licensePool_hash );
1426         }
1428         # Create function result message
1429         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1430         $out_hash->{result} = [$res_hash];
1432         return ( &create_xml_string($out_hash) );
1435 ################################
1437 # @brief Return productIds, windowsSoftwareIds and description for a given licensePoolId
1438 # @param licensePoolId The name of the pool. 
1440 sub opsi_getLicensePool_hash {
1441     my ($msg, $msg_hash, $session_id) = @_;
1442     my $header = @{$msg_hash->{'header'}}[0];
1443     my $source = @{$msg_hash->{'source'}}[0];
1444     my $target = @{$msg_hash->{'target'}}[0];
1445     my $licensePoolId;
1446         my $out_hash;
1448         # Check input sanity
1449         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1450                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1451         } else {
1452                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1453         }
1455         # Fetch infos from Opsi server
1456     my $callobj = {
1457         method  => 'getLicensePool_hash',
1458         params  => [ $licensePoolId ],
1459         id  => 1,
1460     };
1461     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1463         # Check Opsi error
1464         my ($res_error, $res_error_str) = &check_opsi_res($res);
1465         if ($res_error){
1466                 # Create error message
1467                 &main::daemon_log("$session_id ERROR: cannot get license pool from Opsi server: ".$res_error_str, 1);
1468                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source);
1469                 &add_content2xml_hash($out_hash, "error", $res_error_str);
1470                 return ( &create_xml_string($out_hash) );
1471         }
1473         # Create function result message
1474         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1475         &add_content2xml_hash($out_hash, "licensePoolId", $res->result->{'licensePoolId'});
1476         &add_content2xml_hash($out_hash, "description", $res->result->{'description'});
1477         map(&add_content2xml_hash($out_hash, "productIds", "$_"), @{ $res->result->{'productIds'} });
1478         map(&add_content2xml_hash($out_hash, "windowsSoftwareIds", "$_"), @{ $res->result->{'windowsSoftwareIds'} });
1480         return ( &create_xml_string($out_hash) );
1483 ################################
1485 # @brief Returns softwareLicenseId, notes, licenseKey, hostId and licensePoolId for optional given licensePoolId and hostId
1486 # @param hostid Something like client_1.intranet.mydomain.de (optional).
1487 # @param licensePoolId The name of the pool (optional). 
1488
1489 sub opsi_getSoftwareLicenseUsages_listOfHashes {
1490         my ($msg, $msg_hash, $session_id) = @_;
1491         my $header = @{$msg_hash->{'header'}}[0];
1492         my $source = @{$msg_hash->{'source'}}[0];
1493         my $target = @{$msg_hash->{'target'}}[0];
1494         my $licensePoolId = defined $msg_hash->{'licensePoolId'} ? @{$msg_hash->{'licensePoolId'}}[0] : undef;
1495         my $hostId = defined $msg_hash->{'hostId'} ? @{$msg_hash->{'hostId'}}[0] : undef;
1496         my $out_hash;
1498         # Fetch information from Opsi server
1499         my $callobj = {
1500                 method  => 'getSoftwareLicenseUsages_listOfHashes',
1501                 params  => [  $hostId, $licensePoolId ],
1502                 id  => 1,
1503         };
1504         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1506         # Check Opsi error
1507         my ($res_error, $res_error_str) = &check_opsi_res($res);
1508         if ($res_error){
1509                 # Create error message
1510                 &main::daemon_log("$session_id ERROR: cannot fetch software licenses from license pool '$licensePoolId': ".$res_error_str, 1);
1511                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1512                 return ( &create_xml_string($out_hash) );
1513         }
1515         # Parse Opsi result
1516         my $res_hash = { 'hit'=> [] };
1517         foreach my $license ( @{$res->result}) {
1518                 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
1519                         'notes' => [$license->{'notes'}],
1520                         'licenseKey' => [$license->{'licenseKey'}],
1521                         'hostId' => [$license->{'hostId'}],
1522                         'licensePoolId' => [$license->{'licensePoolId'}],
1523                         };
1524                 push( @{$res_hash->{hit}}, $license_hash );
1525         }
1527         # Create function result message
1528         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1529         $out_hash->{result} = [$res_hash];
1531         return ( &create_xml_string($out_hash) );
1534 ################################
1536 # @brief Returns expirationDate, boundToHost, maxInstallation, licenseTyp, licensePoolIds and licenseKeys for a given softwareLicense ID.
1537 # @param softwareLicenseId Identificator of a license.
1539 sub opsi_getSoftwareLicense_hash {
1540         my ($msg, $msg_hash, $session_id) = @_;
1541         my $header = @{$msg_hash->{'header'}}[0];
1542         my $source = @{$msg_hash->{'source'}}[0];
1543         my $target = @{$msg_hash->{'target'}}[0];
1544         my $softwareLicenseId;
1545         my $out_hash;
1547         # Check input sanity
1548         if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
1549                 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
1550         } else {
1551                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1552         }
1554         my $callobj = {
1555                 method  => 'getSoftwareLicense_hash',
1556                 params  => [ $softwareLicenseId ],
1557                 id  => 1,
1558         };
1559         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1561         # Check Opsi error
1562         my ($res_error, $res_error_str) = &check_opsi_res($res);
1563         if ($res_error){
1564                 # Create error message
1565                 &main::daemon_log("$session_id ERROR: cannot fetch information for license '$softwareLicenseId': ".$res_error_str, 1);
1566                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1567                 return ( &create_xml_string($out_hash) );
1568         }
1569         
1570         # Create function result message
1571         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1572         &add_content2xml_hash($out_hash, "expirationDate", $res->result->{'expirationDate'});
1573         &add_content2xml_hash($out_hash, "boundToHost", $res->result->{'boundToHost'});
1574         &add_content2xml_hash($out_hash, "maxInstallations", $res->result->{'maxInstallations'});
1575         &add_content2xml_hash($out_hash, "licenseTyp", $res->result->{'licenseTyp'});
1576         foreach my $licensePoolId ( @{$res->result->{'licensePoolIds'}}) {
1577                 &add_content2xml_hash($out_hash, "licensePoolId", $licensePoolId);
1578                 &add_content2xml_hash($out_hash, $licensePoolId, $res->result->{'licenseKeys'}->{$licensePoolId});
1579         }
1581         return ( &create_xml_string($out_hash) );
1584 ################################
1586 # @brief Delete licnese pool by license pool ID. A pool can only be deleted if there are no software licenses bound to the pool. 
1587 # The fixed parameter deleteLicenses=True specifies that all software licenses bound to the pool are being deleted. 
1588 # @param licensePoolId The name of the pool. 
1590 sub opsi_deleteLicensePool {
1591         my ($msg, $msg_hash, $session_id) = @_;
1592     my $header = @{$msg_hash->{'header'}}[0];
1593     my $source = @{$msg_hash->{'source'}}[0];
1594     my $target = @{$msg_hash->{'target'}}[0];
1595     my $licensePoolId;
1596         my $out_hash;
1598         # Check input sanity
1599         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1600                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1601         } else {
1602                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1603         }
1605         # Fetch softwareLicenseIds used in license pool
1606         # This has to be done because function deleteLicensePool deletes the pool and the corresponding software licenses
1607         # but not the license contracts of the software licenses. In our case each software license has exactly one license contract. 
1608         my $callobj = {
1609                 method  => 'getSoftwareLicenses_listOfHashes',
1610                 params  => [ ],
1611                 id  => 1,
1612         };
1613         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1615         # Keep list of licenseContractIds in mind to delete it after the deletion of the software licenses
1616         my @lCI_toBeDeleted;
1617         foreach my $softwareLicenseHash ( @{$res->result} ) {
1618                 if ((@{$softwareLicenseHash->{'licensePoolIds'}} == 0) || (@{$softwareLicenseHash->{'licensePoolIds'}}[0] ne $licensePoolId)) { 
1619                         next; 
1620                 }  
1621                 push (@lCI_toBeDeleted, $softwareLicenseHash->{'licenseContractId'});
1622         }
1624         # Delete license pool at Opsi server
1625     $callobj = {
1626         method  => 'deleteLicensePool',
1627         params  => [ $licensePoolId, 'deleteLicenses=True'  ],
1628         id  => 1,
1629     };
1630     $res = $main::opsi_client->call($main::opsi_url, $callobj);
1631         my ($res_error, $res_error_str) = &check_opsi_res($res);
1632         if ($res_error){
1633                 # Create error message
1634                 &main::daemon_log("$session_id ERROR: cannot delete license pool at Opsi server: ".$res_error_str, 1);
1635                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1636                 return ( &create_xml_string($out_hash) );
1637         } 
1639         # Delete each license contract connected with the license pool
1640         foreach my $licenseContractId ( @lCI_toBeDeleted ) {
1641                 my $callobj = {
1642                         method  => 'deleteLicenseContract',
1643                         params  => [ $licenseContractId ],
1644                         id  => 1,
1645                 };
1646                 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1647                 my ($res_error, $res_error_str) = &check_opsi_res($res);
1648                 if ($res_error){
1649                         # Create error message
1650                         &main::daemon_log("$session_id ERROR: cannot delete license contract '$licenseContractId' connected with license pool '$licensePoolId' at Opsi server: ".$res_error_str, 1);
1651                         $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1652                         return ( &create_xml_string($out_hash) );
1653                 }
1654         }
1656         # Create function result message
1657         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1658         
1659         return ( &create_xml_string($out_hash) );
1662 ################################
1664 # @brief Create a license contract, create a software license and add the software license to the license pool
1665 # @param licensePoolId The name of the pool the license should be assigned.
1666 # @param licenseKey The license key.
1667 # @param partner Name of the license partner (optional).
1668 # @param conclusionDate Date of conclusion of license contract (optional)
1669 # @param notificationDate Date of notification that license is running out soon (optional).
1670 # @param notes This is the place for some notes (optional)
1671 # @param softwareLicenseId Identificator of a license (optional).
1672 # @param licenseTyp Typ of a licnese, either "OEM", "VOLUME" or "RETAIL" (optional).
1673 # @param maxInstallations The number of clients use this license (optional). 
1674 # @param boundToHost The name of the client the license is bound to (optional).
1675 # @param expirationDate The date when the license is running down (optional). 
1677 sub opsi_createLicense {
1678         my ($msg, $msg_hash, $session_id) = @_;
1679     my $header = @{$msg_hash->{'header'}}[0];
1680     my $source = @{$msg_hash->{'source'}}[0];
1681     my $target = @{$msg_hash->{'target'}}[0];
1682         my $partner = defined $msg_hash->{'partner'} ? @{$msg_hash->{'partner'}}[0] : undef;
1683         my $conclusionDate = defined $msg_hash->{'conclusionDate'} ? @{$msg_hash->{'conclusionDate'}}[0] : undef;
1684         my $notificationDate = defined $msg_hash->{'notificationDate'} ? @{$msg_hash->{'notificationDate'}}[0] : undef;
1685         my $notes = defined $msg_hash->{'notes'} ? @{$msg_hash->{'notes'}}[0] : undef;
1686         my $licenseContractId;
1687         my $softwareLicenseId = defined $msg_hash->{'licenseId'} ? @{$msg_hash->{'licenseId'}}[0] : undef;
1688         my $licenseType = defined $msg_hash->{'licenseType'} ? @{$msg_hash->{'licenseType'}}[0] : undef;
1689         my $maxInstallations = defined $msg_hash->{'maxInstallations'} ? @{$msg_hash->{'maxInstallations'}}[0] : undef;
1690         my $boundToHost = defined $msg_hash->{'boundToHost'} ? @{$msg_hash->{'boundToHost'}}[0] : undef;
1691         my $expirationDate = defined $msg_hash->{'expirationDate'} ? @{$msg_hash->{'expirationDate'}}[0] : undef;
1692         my $licensePoolId;
1693         my $licenseKey;
1694         my $out_hash;
1696         # Check input sanity
1697         if (&_check_xml_tag_is_ok ($msg_hash, 'licenseKey')) {
1698                 $licenseKey = @{$msg_hash->{'licenseKey'}}[0];
1699         } else {
1700                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1701         }
1702         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1703                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1704         } else {
1705                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1706         }
1707         if ((defined $licenseType) && (not exists $licenseTyp_hash->{$licenseType})) {
1708                 return ( &_give_feedback($msg, $msg_hash, $session_id, "The typ of a license can be either 'OEM', 'VOLUME' or 'RETAIL'."));
1709         }
1711         # Create license contract at Opsi server
1712     my $callobj = {
1713         method  => 'createLicenseContract',
1714         params  => [ undef, $partner, $conclusionDate, $notificationDate, undef, $notes ],
1715         id  => 1,
1716     };
1717     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1719         # Check Opsi error
1720         my ($res_error, $res_error_str) = &check_opsi_res($res);
1721         if ($res_error){
1722                 # Create error message
1723                 &main::daemon_log("$session_id ERROR: cannot create license contract at Opsi server: ".$res_error_str, 1);
1724                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1725                 return ( &create_xml_string($out_hash) );
1726         }
1727         
1728         $licenseContractId = $res->result;
1730         # Create software license at Opsi server
1731     $callobj = {
1732         method  => 'createSoftwareLicense',
1733         params  => [ $softwareLicenseId, $licenseContractId, $licenseType, $maxInstallations, $boundToHost, $expirationDate ],
1734         id  => 1,
1735     };
1736     $res = $main::opsi_client->call($main::opsi_url, $callobj);
1738         # Check Opsi error
1739         ($res_error, $res_error_str) = &check_opsi_res($res);
1740         if ($res_error){
1741                 # Create error message
1742                 &main::daemon_log("$session_id ERROR: cannot create software license at Opsi server: ".$res_error_str, 1);
1743                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1744                 return ( &create_xml_string($out_hash) );
1745         }
1747         $softwareLicenseId = $res->result;
1749         # Add software license to license pool
1750         $callobj = {
1751         method  => 'addSoftwareLicenseToLicensePool',
1752         params  => [ $softwareLicenseId, $licensePoolId, $licenseKey ],
1753         id  => 1,
1754     };
1755     $res = $main::opsi_client->call($main::opsi_url, $callobj);
1757         # Check Opsi error
1758         ($res_error, $res_error_str) = &check_opsi_res($res);
1759         if ($res_error){
1760                 # Create error message
1761                 &main::daemon_log("$session_id ERROR: cannot add software license to license pool at Opsi server: ".$res_error_str, 1);
1762                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1763                 return ( &create_xml_string($out_hash) );
1764         }
1766         # Create function result message
1767         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1768         
1769         return ( &create_xml_string($out_hash) );
1772 ################################
1774 # @brief Assign a software license to a host
1775 # @param hostid Something like client_1.intranet.mydomain.de
1776 # @param licensePoolId The name of the pool.
1778 sub opsi_assignSoftwareLicenseToHost {
1779         my ($msg, $msg_hash, $session_id) = @_;
1780     my $header = @{$msg_hash->{'header'}}[0];
1781     my $source = @{$msg_hash->{'source'}}[0];
1782     my $target = @{$msg_hash->{'target'}}[0];
1783         my $hostId;
1784         my $licensePoolId;
1786         # Check input sanity
1787         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1788                 $hostId = @{$msg_hash->{'hostId'}}[0];
1789         } else {
1790                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1791         }
1792         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1793                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1794         } else {
1795                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1796         }
1798         # Assign a software license to a host
1799         my $callobj = {
1800         method  => 'getAndAssignSoftwareLicenseKey',
1801         params  => [ $hostId, $licensePoolId ],
1802         id  => 1,
1803     };
1804     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1806         # Check Opsi error
1807         my ($res_error, $res_error_str) = &check_opsi_res($res);
1808         if ($res_error){
1809                 # Create error message
1810                 &main::daemon_log("$session_id ERROR: cannot assign a software license to a host at Opsi server: ".$res_error_str, 1);
1811                 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1812                 return ( &create_xml_string($out_hash) );
1813         }
1815         # Create function result message
1816         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1817         
1818         return ( &create_xml_string($out_hash) );
1821 ################################
1823 # @brief Unassign a software license from a host.
1824 # @param hostid Something like client_1.intranet.mydomain.de
1825 # @param licensePoolId The name of the pool.
1827 sub opsi_unassignSoftwareLicenseFromHost {
1828         my ($msg, $msg_hash, $session_id) = @_;
1829     my $header = @{$msg_hash->{'header'}}[0];
1830     my $source = @{$msg_hash->{'source'}}[0];
1831     my $target = @{$msg_hash->{'target'}}[0];
1832         my $hostId;
1833         my $licensePoolId;
1835         # Check input sanity
1836         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1837                 $hostId = @{$msg_hash->{'hostId'}}[0];
1838         } else {
1839                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1840         }
1841         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1842                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1843         } else {
1844                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1845         }
1847         # Unassign a software license from a host
1848         my $callobj = {
1849         method  => 'deleteSoftwareLicenseUsage',
1850         params  => [ $hostId, '', $licensePoolId ],
1851         id  => 1,
1852     };
1853     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1855         # Check Opsi error
1856         my ($res_error, $res_error_str) = &check_opsi_res($res);
1857         if ($res_error){
1858                 # Create error message
1859                 &main::daemon_log("$session_id ERROR: cannot unassign a software license from a host at Opsi server: ".$res_error_str, 1);
1860                 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1861                 return ( &create_xml_string($out_hash) );
1862         }
1864         # Create function result message
1865         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1866         
1867         return ( &create_xml_string($out_hash) );
1870 ################################
1872 # @brief Unassign all software licenses from a host
1873 # @param hostid Something like client_1.intranet.mydomain.de
1875 sub opsi_unassignAllSoftwareLicensesFromHost {
1876         my ($msg, $msg_hash, $session_id) = @_;
1877     my $header = @{$msg_hash->{'header'}}[0];
1878     my $source = @{$msg_hash->{'source'}}[0];
1879     my $target = @{$msg_hash->{'target'}}[0];
1880         my $hostId;
1882         # Check input sanity
1883         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1884                 $hostId = @{$msg_hash->{'hostId'}}[0];
1885         } else {
1886                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1887         }
1889         # Unassign all software licenses from a host
1890         my $callobj = {
1891         method  => 'deleteAllSoftwareLicenseUsages',
1892         params  => [ $hostId ],
1893         id  => 1,
1894     };
1895     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1897         # Check Opsi error
1898         my ($res_error, $res_error_str) = &check_opsi_res($res);
1899         if ($res_error){
1900                 # Create error message
1901                 &main::daemon_log("$session_id ERROR: cannot unassign a software license from a host at Opsi server: ".$res_error_str, 1);
1902                 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1903                 return ( &create_xml_string($out_hash) );
1904         }
1906         # Create function result message
1907         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1908         
1909         return ( &create_xml_string($out_hash) );
1913 ################################
1915 # @brief Returns the assigned licensePoolId and licenses, how often the product is installed and at which host
1916 # and the number of max and remaining installations for a given OPSI product.
1917 # @param productId Identificator of an OPSI product.
1918 #       
1919 sub opsi_getLicenseInformationForProduct {
1920     my ($msg, $msg_hash, $session_id) = @_;
1921     my $header = @{$msg_hash->{'header'}}[0];
1922     my $source = @{$msg_hash->{'source'}}[0];
1923         my $productId;
1924         my $out_hash;
1926         # Check input sanity
1927         if (&_check_xml_tag_is_ok ($msg_hash, 'productId')) {
1928                 $productId = @{$msg_hash->{'productId'}}[0];
1929         } else {
1930                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1931         }
1933         # Fetch infos from Opsi server
1934     my $callobj = {
1935         method  => 'getLicensePoolId',
1936         params  => [ $productId ],
1937         id  => 1,
1938     };
1939     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1941         # Check Opsi error
1942         my ($res_error, $res_error_str) = &check_opsi_res($res);
1943         if ($res_error){
1944                 # Create error message
1945                 &main::daemon_log("$session_id ERROR: cannot get license pool for product '$productId' : ".$res_error_str, 1);
1946                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1947                 return ( &create_xml_string($out_hash) );
1948         } 
1949         
1950         my $licensePoolId = $res->result;
1952         # Fetch statistic information for given pool ID
1953         $callobj = {
1954                 method  => 'getLicenseStatistics_hash',
1955                 params  => [ ],
1956                 id  => 1,
1957         };
1958         $res = $main::opsi_client->call($main::opsi_url, $callobj);
1960         # Check Opsi error
1961         ($res_error, $res_error_str) = &check_opsi_res($res);
1962         if ($res_error){
1963                 # Create error message
1964                 &main::daemon_log("$session_id ERROR: cannot get statistic informations for license pools : ".$res_error_str, 1);
1965                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1966                 return ( &create_xml_string($out_hash) );
1967         }
1969         # Create function result message
1970         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1971         &add_content2xml_hash($out_hash, "licensePoolId", $licensePoolId);
1972         &add_content2xml_hash($out_hash, "licenses", $res->result->{$licensePoolId}->{'licenses'});
1973         &add_content2xml_hash($out_hash, "usageCount", $res->result->{$licensePoolId}->{'usageCount'});
1974         &add_content2xml_hash($out_hash, "maxInstallations", $res->result->{$licensePoolId}->{'maxInstallations'});
1975         &add_content2xml_hash($out_hash, "remainingInstallations", $res->result->{$licensePoolId}->{'remainingInstallations'});
1976         map(&add_content2xml_hash($out_hash, "usedBy", "$_"), @{ $res->result->{$licensePoolId}->{'usedBy'}});
1978         return ( &create_xml_string($out_hash) );
1982 ################################
1984 # @brief
1985 # @param 
1986 #       
1987 sub opsi_getPool {
1988     my ($msg, $msg_hash, $session_id) = @_;
1989     my $header = @{$msg_hash->{'header'}}[0];
1990     my $source = @{$msg_hash->{'source'}}[0];
1992         # Check input sanity
1993         my $licensePoolId;
1994         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1995                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1996         } else {
1997                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1998         }
2000         # Create hash for the answer
2001         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2003         # Call Opsi
2004         my ($res, $err) = &_getLicensePool_hash( 'licensePoolId'=> $licensePoolId );
2005         if ($err){
2006                 return &_giveErrorFeedback($msg_hash, "cannot get license pool from Opsi server: ".$res, $session_id);
2007         }
2008         # Add data to outgoing hash
2009         &add_content2xml_hash($out_hash, "licensePoolId", $res->{'licensePoolId'});
2010         &add_content2xml_hash($out_hash, "description", $res->{'description'});
2011         map(&add_content2xml_hash($out_hash, "productIds", "$_"), @{ $res->{'productIds'} });
2012         map(&add_content2xml_hash($out_hash, "windowsSoftwareIds", "$_"), @{ $res->{'windowsSoftwareIds'} });
2015         # Call Opsi
2016         ($res, $err) = &_getSoftwareLicenses_listOfHashes();
2017         if ($err){
2018                 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server: ".$res, $session_id);
2019         }
2020         # Add data to outgoing hash
2021         # Parse through all software licenses and select those associated to the pool
2022         my $res_hash = { 'softwareLicenseIds'=> [] };
2023         foreach my $license ( @$res) {
2024                 # Each license hash has a list of licensePoolIds so go through this list and search for matching licensePoolIds
2025                 my $found = 0;
2026                 my @licensePoolIds_list = @{$license->{licensePoolIds}};
2027                 foreach my $lPI ( @licensePoolIds_list) {
2028                         if ($lPI eq $licensePoolId) { $found++ }
2029                 }
2030                 if (not $found ) { next; };
2031                 push( @{$res_hash->{softwareLicenseId}}, $license->{'softwareLicenseId'} );
2032         }
2033         $out_hash->{licenses} = [$res_hash];
2035     return ( &create_xml_string($out_hash) );
2038 sub opsi_test {
2039     my ($msg, $msg_hash, $session_id) = @_;
2040     my $header = @{$msg_hash->{'header'}}[0];
2041     my $source = @{$msg_hash->{'source'}}[0];
2042         my $pram1 = @{$msg_hash->{'productId'}}[0];
2044 print STDERR Dumper $pram1;
2046         # Fetch infos from Opsi server
2047     my $callobj = {
2048         method  => 'getLicensePoolId',
2049         params  => [ $pram1 ],
2050         id  => 1,
2051     };
2052     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
2054         print STDERR Dumper $res;
2055         return ();
2059 sub _getLicensePool_hash {
2060         my %arg = (
2061                 'licensePoolId' => undef,
2062                 @_,
2063         );
2065         if (not defined $arg{licensePoolId} ) { 
2066                 return ("function requires licensePoolId as parameter", 1);
2067         }
2069         # Fetch pool infos from Opsi server
2070     my $callobj = {
2071         method  => 'getLicensePool_hash',
2072         params  => [ $arg{licensePoolId} ],
2073         id  => 1,
2074     };
2075     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
2077         # Check Opsi error
2078         my ($res_error, $res_error_str) = &check_opsi_res($res);
2079         if ($res_error){
2080                 return ( $res_error_str, 1 );
2081         }
2083         return ($res->result, 0);
2087 sub _getSoftwareLicenses_listOfHashes {
2088         # Fetch licenses associated to the given pool
2089         my $callobj = {
2090                 method  => 'getSoftwareLicenses_listOfHashes',
2091                 params  => [ ],
2092                 id  => 1,
2093         };
2094         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
2096         # Check Opsi error
2097         my ($res_error, $res_error_str) = &check_opsi_res($res);
2098         if ($res_error){
2099                 return ( $res_error_str, 1 );
2100         }
2102         return ($res->result, 0);
2106 sub _giveErrorFeedback {
2107         my ($msg_hash, $err_string, $session_id) = @_;
2108         &main::daemon_log("$session_id ERROR: $err_string", 1);
2109         my $out_hash = &main::create_xml_hash("error", $main::server_address, @{$msg_hash->{source}}[0], $err_string);
2110         return ( &create_xml_string($out_hash) );
2113 1;