Code

Move information to 90_gosa.conf
[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",
33         "opsi_getSoftwareLicenseUsagesForProductId",
34         "opsi_getLicensePools_listOfHashes",
35         "opsi_getLicenseInformationForProduct",
36         "opsi_getPool",
37         "opsi_getAllSoftwareLicenses",
38         "opsi_removeLicense",
39         "opsi_getReservedLicenses",
40         "opsi_boundHostToLicense",
41         "opsi_unboundHostFromLicense",
42         "opsi_test",
43    );
44 @EXPORT = @events;
46 use strict;
47 use warnings;
48 use GOSA::GosaSupportDaemon;
49 use Data::Dumper;
50 use XML::Quote qw(:all);
52 BEGIN {}
54 END {}
56 # ----------------------------------------------------------------------------
57 #                          D E C L A R A T I O N S
58 # ----------------------------------------------------------------------------
60 my $licenseTyp_hash = { 'OEM'=>'', 'VOLUME'=>'', 'RETAIL'=>''};
61 my ($opsi_enabled, $opsi_server, $opsi_admin, $opsi_password, $opsi_url, $opsi_client);
62 my %cfg_defaults = (
63                 "Opsi" => {
64                 "enabled"  => [\$opsi_enabled, "false"],
65                 "server"   => [\$opsi_server, "localhost"],
66                 "admin"    => [\$opsi_admin, "opsi-admin"],
67                 "password" => [\$opsi_password, "secret"],
68                 },
69 );
70 &read_configfile($main::cfg_file, %cfg_defaults);
71 if ($opsi_enabled eq "true") {
72         use JSON::RPC::Client;
73         use XML::Quote qw(:all);
74         use Time::HiRes qw( time );
75         $opsi_url= "https://".$opsi_admin.":".$opsi_password."@".$opsi_server.":4447/rpc";
76         $opsi_client = new JSON::RPC::Client;
77 }
79 # ----------------------------------------------------------------------------
80 #   external methods handling the comunication with GOsa/GOsa-si
81 # ----------------------------------------------------------------------------
83 ################################
84 # @brief A function returning a list of functions which are exported by importing the module.
85 # @return List of all provided functions
86 sub get_events {
87     return \@events;
88 }
90 ################################
91 # @brief Adds an Opsi product to an Opsi client.
92 # @param msg - STRING - xml message with tags hostId and productId
93 # @param msg_hash - HASHREF - message information parsed into a hash
94 # @param session_id - INTEGER - POE session id of the processing of this message
95 # @return out_msg - STRING - feedback to GOsa in success and error case
96 sub opsi_add_product_to_client {
97         my $startTime = Time::HiRes::time;
98     my ($msg, $msg_hash, $session_id) = @_;
99     my $header = @{$msg_hash->{'header'}}[0];
100     my $source = @{$msg_hash->{'source'}}[0];
101     my $target = @{$msg_hash->{'target'}}[0];
102     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
104     # Build return message
105     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
106     if (defined $forward_to_gosa) {
107         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
108     }
110     # Sanity check of needed parameter
111     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
112                 return &_giveErrorFeedback($msg_hash, "no hostId specified or hostId tag invalid", $session_id);
113     }
114     if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
115                 return &_giveErrorFeedback($msg_hash, "no productId specified or productId tag invalid", $session_id);
116     }
118         # Get hostId
119         my $hostId = @{$msg_hash->{'hostId'}}[0];
120         &add_content2xml_hash($out_hash, "hostId", $hostId);
122         # Get productID
123         my $productId = @{$msg_hash->{'productId'}}[0];
124         &add_content2xml_hash($out_hash, "productId", $productId);
126         # Do an action request for all these -> "setup".
127         my $callobj = {
128                 method  => 'setProductActionRequest',
129                 params  => [ $productId, $hostId, "setup" ],
130                 id  => 1, }; 
131         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
133         if (&check_opsi_res($res)) { return ( (caller(0))[3]." : ".$_, 1 ); };
135         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
136     return ( &create_xml_string($out_hash) );
139 ################################
140 # @brief Deletes an Opsi-product from an Opsi-client. 
141 # @param msg - STRING - xml message with tags hostId and productId
142 # @param msg_hash - HASHREF - message information parsed into a hash
143 # @param session_id - INTEGER - POE session id of the processing of this message
144 # @return out_msg - STRING - feedback to GOsa in success and error case
145 sub opsi_del_product_from_client {
146         my $startTime = Time::HiRes::time;
147     my ($msg, $msg_hash, $session_id) = @_;
148     my $header = @{$msg_hash->{'header'}}[0];
149     my $source = @{$msg_hash->{'source'}}[0];
150     my $target = @{$msg_hash->{'target'}}[0];
151     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
152     my ($hostId, $productId);
153     my $error = 0;
154     my ($sres, $sres_err, $sres_err_string);
156     # Build return message
157     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
158     if (defined $forward_to_gosa) {
159         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
160     }
162     # Sanity check of needed parameter
163     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
164         $error++;
165         &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
166         &add_content2xml_hash($out_hash, "error", "hostId");
167         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
169     }
170     if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
171         $error++;
172         &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
173         &add_content2xml_hash($out_hash, "error", "productId");
174         &main::daemon_log("$session_id ERROR: no productId specified or procutId tag invalid: $msg", 1); 
175     }
177     # All parameter available
178     if (not $error) {
179         # Get hostId
180         $hostId = @{$msg_hash->{'hostId'}}[0];
181         &add_content2xml_hash($out_hash, "hostId", $hostId);
183         # Get productID
184         $productId = @{$msg_hash->{'productId'}}[0];
185         &add_content2xml_hash($out_hash, "productId", $productId);
187         # Check to get product action list 
188         my $callobj = {
189             method  => 'getPossibleProductActions_list',
190             params  => [ $productId ],
191             id  => 1, };
192         $sres = $main::opsi_client->call($main::opsi_url, $callobj);
193         ($sres_err, $sres_err_string) = &check_opsi_res($sres);
194         if ($sres_err){
195             &main::daemon_log("$session_id ERROR: cannot get product action list: ".$sres_err_string, 1);
196             &add_content2xml_hash($out_hash, "error", $sres_err_string);
197             $error++;
198         }
199     }
201     # Check action uninstall of product
202     if (not $error) {
203         my $uninst_possible= 0;
204         foreach my $r (@{$sres->result}) {
205             if ($r eq 'uninstall') {
206                 $uninst_possible= 1;
207             }
208         }
209         if (!$uninst_possible){
210             &main::daemon_log("$session_id ERROR: cannot uninstall product '$productId', product do not has the action 'uninstall'", 1);
211             &add_content2xml_hash($out_hash, "error", "cannot uninstall product '$productId', product do not has the action 'uninstall'");
212             $error++;
213         }
214     }
216     # Set product state to "none"
217     # Do an action request for all these -> "setup".
218     if (not $error) {
219         my $callobj = {
220             method  => 'setProductActionRequest',
221             params  => [ $productId, $hostId, "none" ],
222             id  => 1, 
223         }; 
224         $sres = $main::opsi_client->call($main::opsi_url, $callobj);
225         ($sres_err, $sres_err_string) = &check_opsi_res($sres);
226         if ($sres_err){
227             &main::daemon_log("$session_id ERROR: cannot delete product: ".$sres_err_string, 1);
228             &add_content2xml_hash($out_hash, "error", $sres_err_string);
229         }
230     }
232     # Return message
233         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
234     return ( &create_xml_string($out_hash) );
237 ################################
238 # @brief Adds an Opsi client to Opsi.
239 # @param msg - STRING - xml message with tags hostId and macaddress
240 # @param msg_hash - HASHREF - message information parsed into a hash
241 # @param session_id - INTEGER - POE session id of the processing of this message
242 # @return out_msg - STRING - feedback to GOsa in success and error case
243 sub opsi_add_client {
244         my $startTime = Time::HiRes::time;
245     my ($msg, $msg_hash, $session_id) = @_;
246     my $header = @{$msg_hash->{'header'}}[0];
247     my $source = @{$msg_hash->{'source'}}[0];
248     my $target = @{$msg_hash->{'target'}}[0];
249     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
250     my ($hostId, $mac);
251     my $error = 0;
252     my ($sres, $sres_err, $sres_err_string);
254     # Build return message with twisted target and source
255     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
256     if (defined $forward_to_gosa) {
257         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
258     }
260     # Sanity check of needed parameter
261     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
262         $error++;
263         &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
264         &add_content2xml_hash($out_hash, "error", "hostId");
265         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
266     }
267     if ((not exists $msg_hash->{'macaddress'}) || (@{$msg_hash->{'macaddress'}} != 1) || (@{$msg_hash->{'macaddress'}}[0] eq ref 'HASH'))  {
268         $error++;
269         &add_content2xml_hash($out_hash, "error_string", "no macaddress specified or macaddress tag invalid");
270         &add_content2xml_hash($out_hash, "error", "macaddress");
271         &main::daemon_log("$session_id ERROR: no macaddress specified or macaddress tag invalid: $msg", 1); 
272     }
274     if (not $error) {
275         # Get hostId
276         $hostId = @{$msg_hash->{'hostId'}}[0];
277         &add_content2xml_hash($out_hash, "hostId", $hostId);
279         # Get macaddress
280         $mac = @{$msg_hash->{'macaddress'}}[0];
281         &add_content2xml_hash($out_hash, "macaddress", $mac);
283         my $name= $hostId;
284         $name=~ s/^([^.]+).*$/$1/;
285         my $domain= $hostId;
286         $domain=~ s/^[^.]+\.(.*)$/$1/;
287         my ($description, $notes, $ip);
289         if (defined @{$msg_hash->{'description'}}[0]){
290             $description = @{$msg_hash->{'description'}}[0];
291         }
292         if (defined @{$msg_hash->{'notes'}}[0]){
293             $notes = @{$msg_hash->{'notes'}}[0];
294         }
295         if (defined @{$msg_hash->{'ip'}}[0]){
296             $ip = @{$msg_hash->{'ip'}}[0];
297         }
299         my $callobj;
300         $callobj = {
301             method  => 'createClient',
302             params  => [ $name, $domain, $description, $notes, $ip, $mac ],
303             id  => 1,
304         };
306         $sres = $main::opsi_client->call($main::opsi_url, $callobj);
307         ($sres_err, $sres_err_string) = &check_opsi_res($sres);
308         if ($sres_err){
309             &main::daemon_log("$session_id ERROR: cannot create client: ".$sres_err_string, 1);
310             &add_content2xml_hash($out_hash, "error", $sres_err_string);
311         } else {
312             &main::daemon_log("$session_id INFO: add opsi client '$hostId' with mac '$mac'", 5); 
313         }
314     }
316     # Return message
317         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
318     return ( &create_xml_string($out_hash) );
321 ################################
322 # @brief Modifies the parameters description, mac or notes for an Opsi client if the corresponding message tags are given.
323 # @param msg - STRING - xml message with tag hostId and optional description, mac or notes
324 # @param msg_hash - HASHREF - message information parsed into a hash
325 # @param session_id - INTEGER - POE session id of the processing of this message    
326 # @return out_msg - STRING - feedback to GOsa in success and error case
327 sub opsi_modify_client {
328         my $startTime = Time::HiRes::time;
329     my ($msg, $msg_hash, $session_id) = @_;
330     my $header = @{$msg_hash->{'header'}}[0];
331     my $source = @{$msg_hash->{'source'}}[0];
332     my $target = @{$msg_hash->{'target'}}[0];
333     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
334     my $hostId;
335     my $error = 0;
336     my ($sres, $sres_err, $sres_err_string);
338     # Build return message with twisted target and source
339     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
340     if (defined $forward_to_gosa) {
341         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
342     }
344     # Sanity check of needed parameter
345     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
346         $error++;
347         &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
348         &add_content2xml_hash($out_hash, "error", "hostId");
349         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
350     }
352     if (not $error) {
353         # Get hostId
354         $hostId = @{$msg_hash->{'hostId'}}[0];
355         &add_content2xml_hash($out_hash, "hostId", $hostId);
356         my $name= $hostId;
357         $name=~ s/^([^.]+).*$/$1/;
358         my $domain= $hostId;
359         $domain=~ s/^[^.]+(.*)$/$1/;
361         # Modify description, notes or mac if defined
362         my ($description, $notes, $mac);
363         my $callobj;
364         if ((exists $msg_hash->{'description'}) && (@{$msg_hash->{'description'}} == 1) ){
365             $description = @{$msg_hash->{'description'}}[0];
366             $callobj = {
367                 method  => 'setHostDescription',
368                 params  => [ $hostId, $description ],
369                 id  => 1,
370             };
371             my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
372             my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
373             if ($sres_err){
374                 &main::daemon_log("ERROR: cannot set description: ".$sres_err_string, 1);
375                 &add_content2xml_hash($out_hash, "error", $sres_err_string);
376             }
377         }
378         if ((exists $msg_hash->{'notes'}) && (@{$msg_hash->{'notes'}} == 1)) {
379             $notes = @{$msg_hash->{'notes'}}[0];
380             $callobj = {
381                 method  => 'setHostNotes',
382                 params  => [ $hostId, $notes ],
383                 id  => 1,
384             };
385             my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
386             my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
387             if ($sres_err){
388                 &main::daemon_log("ERROR: cannot set notes: ".$sres_err_string, 1);
389                 &add_content2xml_hash($out_hash, "error", $sres_err_string);
390             }
391         }
392         if ((exists $msg_hash->{'mac'}) && (@{$msg_hash->{'mac'}} == 1)){
393             $mac = @{$msg_hash->{'mac'}}[0];
394             $callobj = {
395                 method  => 'setMacAddress',
396                 params  => [ $hostId, $mac ],
397                 id  => 1,
398             };
399             my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
400             my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
401             if ($sres_err){
402                 &main::daemon_log("ERROR: cannot set mac address: ".$sres_err_string, 1);
403                 &add_content2xml_hash($out_hash, "error", $sres_err_string);
404             }
405         }
406     }
408     # Return message
409         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
410     return ( &create_xml_string($out_hash) );
412  
413 ################################
414 # @brief Get netboot products for specific host.
415 # @param msg - STRING - xml message with tag hostId
416 # @param msg_hash - HASHREF - message information parsed into a hash
417 # @param session_id - INTEGER - POE session id of the processing of this message
418 # @return out_msg - STRING - feedback to GOsa in success and error case
419 sub opsi_get_netboot_products {
420         my $startTime = Time::HiRes::time;
421     my ($msg, $msg_hash, $session_id) = @_;
422     my $header = @{$msg_hash->{'header'}}[0];
423     my $source = @{$msg_hash->{'source'}}[0];
424     my $target = @{$msg_hash->{'target'}}[0];
425     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
426     my $hostId;
427     my $xml_msg;
429     # Build return message with twisted target and source
430     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
431     if (defined $forward_to_gosa) {
432         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
433     }
435     # Get hostId if defined
436     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1))  {
437         $hostId = @{$msg_hash->{'hostId'}}[0];
438         &add_content2xml_hash($out_hash, "hostId", $hostId);
439     }
441     &add_content2xml_hash($out_hash, "xxx", "");
442     $xml_msg = &create_xml_string($out_hash);
443     # For hosts, only return the products that are or get installed
444     my $callobj;
445     $callobj = {
446         method  => 'getNetBootProductIds_list',
447         params  => [ ],
448         id  => 1,
449     };
450     &main::daemon_log("$session_id DEBUG: send callobj to opsi_client: ".&opsi_callobj2string($callobj), 7);
451     &main::daemon_log("$session_id DEBUG: opsi_url $main::opsi_url", 7);
452     &main::daemon_log("$session_id DEBUG: waiting for answer from opsi_client!", 7);
453     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
454     &main::daemon_log("$session_id DEBUG: get answer from opsi_client", 7);
455     my %r = ();
456     for (@{$res->result}) { $r{$_} = 1 }
458       if (not &check_opsi_res($res)){
460         if (defined $hostId){
462             $callobj = {
463                 method  => 'getProductStates_hash',
464                 params  => [ $hostId ],
465                 id  => 1,
466             };
468             my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
469             if (not &check_opsi_res($hres)){
470                 my $htmp= $hres->result->{$hostId};
472                 # check state != not_installed or action == setup -> load and add
473                 foreach my $product (@{$htmp}){
475                     if (!defined ($r{$product->{'productId'}})){
476                         next;
477                     }
479                     # Now we've a couple of hashes...
480                     if ($product->{'installationStatus'} ne "not_installed" or
481                             $product->{'actionRequest'} eq "setup"){
482                         my $state= "<state>".$product->{'installationStatus'}."</state><action>".$product->{'actionRequest'}."</action>";
484                         $callobj = {
485                             method  => 'getProduct_hash',
486                             params  => [ $product->{'productId'} ],
487                             id  => 1,
488                         };
490                         my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
491                         if (not &check_opsi_res($sres)){
492                             my $tres= $sres->result;
494                             my $name= xml_quote($tres->{'name'});
495                             my $r= $product->{'productId'};
496                             my $description= xml_quote($tres->{'description'});
497                             $name=~ s/\//\\\//;
498                             $description=~ s/\//\\\//;
499                             $xml_msg=~ s/<xxx><\/xxx>/\n<item><productId>$r<\/productId><name>$name<\/name><description>$description<\/description><\/item>$state<xxx><\/xxx>/;
500                         }
501                     }
502                 }
504             }
506         } else {
507             foreach my $r (@{$res->result}) {
508                 $callobj = {
509                     method  => 'getProduct_hash',
510                     params  => [ $r ],
511                     id  => 1,
512                 };
514                 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
515                 if (not &check_opsi_res($sres)){
516                     my $tres= $sres->result;
518                     my $name= xml_quote($tres->{'name'});
519                     my $description= xml_quote($tres->{'description'});
520                     $name=~ s/\//\\\//;
521                     $description=~ s/\//\\\//;
522                     $xml_msg=~ s/<xxx><\/xxx>/\n<item><productId>$r<\/productId><name>$name<\/name><description>$description<\/description><\/item><xxx><\/xxx>/;
523                 }
524             }
526         }
527     }
528     $xml_msg=~ s/<xxx><\/xxx>//;
530     # Return message
531         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
532     return ( $xml_msg );
535 ################################   
536 # @brief Get product properties for a product and a specific host or gobally for a product.
537 # @param msg - STRING - xml message with tags productId and optional hostId
538 # @param msg_hash - HASHREF - message information parsed into a hash
539 # @param session_id - INTEGER - POE session id of the processing of this message
540 # @return out_msg - STRING - feedback to GOsa in success and error case
541 sub opsi_get_product_properties {
542         my $startTime = Time::HiRes::time;
543     my ($msg, $msg_hash, $session_id) = @_;
544     my $header = @{$msg_hash->{'header'}}[0];
545     my $source = @{$msg_hash->{'source'}}[0];
546     my $target = @{$msg_hash->{'target'}}[0];
547     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
548     my ($hostId, $productId);
549     my $xml_msg;
551     # Build return message with twisted target and source
552     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
553     if (defined $forward_to_gosa) {
554         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
555     }
557     # Sanity check of needed parameter
558     if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH'))  {
559         &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
560         &add_content2xml_hash($out_hash, "error", "productId");
561         &main::daemon_log("$session_id ERROR: no productId specified or productId tag invalid: $msg", 1); 
563         # Return message
564         return ( &create_xml_string($out_hash) );
565     }
567     # Get productid
568     $productId = @{$msg_hash->{'productId'}}[0];
569     &add_content2xml_hash($out_hash, "producId", "$productId");
571     # Get hostId if defined
572     if (defined @{$msg_hash->{'hostId'}}[0]){
573       $hostId = @{$msg_hash->{'hostId'}}[0];
574       &add_content2xml_hash($out_hash, "hostId", $hostId);
575     }
577     # Load actions
578     my $callobj = {
579       method  => 'getPossibleProductActions_list',
580       params  => [ $productId ],
581       id  => 1,
582     };
583     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
584     if (not &check_opsi_res($res)){
585       foreach my $action (@{$res->result}){
586         &add_content2xml_hash($out_hash, "action", $action);
587       }
588     }
590     # Add place holder
591     &add_content2xml_hash($out_hash, "xxx", "");
593     # Move to XML string
594     $xml_msg= &create_xml_string($out_hash);
596     # JSON Query
597     if (defined $hostId){
598       $callobj = {
599           method  => 'getProductProperties_hash',
600           params  => [ $productId, $hostId ],
601           id  => 1,
602       };
603     } else {
604       $callobj = {
605           method  => 'getProductProperties_hash',
606           params  => [ $productId ],
607           id  => 1,
608       };
609     }
610     $res = $main::opsi_client->call($main::opsi_url, $callobj);
612     # JSON Query 2
613     $callobj = {
614       method  => 'getProductPropertyDefinitions_listOfHashes',
615       params  => [ $productId ],
616       id  => 1,
617     };
619     # Assemble options
620     my $res2 = $main::opsi_client->call($main::opsi_url, $callobj);
621     my $values = {};
622     my $descriptions = {};
623     if (not &check_opsi_res($res2)){
624         my $r= $res2->result;
626           foreach my $entr (@$r){
627             # Unroll values
628             my $cnv;
629             if (UNIVERSAL::isa( $entr->{'values'}, "ARRAY" )){
630               foreach my $v (@{$entr->{'values'}}){
631                 $cnv.= "<value>$v</value>";
632               }
633             } else {
634               $cnv= $entr->{'values'};
635             }
636             $values->{$entr->{'name'}}= $cnv;
637             $descriptions->{$entr->{'name'}}= "<description>".$entr->{'description'}."</description>";
638           }
639     }
641     if (not &check_opsi_res($res)){
642         my $r= $res->result;
643         foreach my $key (keys %{$r}) {
644             my $item= "\n<item>";
645             my $value= $r->{$key};
646             my $dsc= "";
647             my $vals= "";
648             if (defined $descriptions->{$key}){
649               $dsc= $descriptions->{$key};
650             }
651             if (defined $values->{$key}){
652               $vals= $values->{$key};
653             }
654             $item.= "<$key>$dsc<default>".xml_quote($value)."</default>$vals</$key>";
655             $item.= "</item>";
656             $xml_msg=~ s/<xxx><\/xxx>/$item<xxx><\/xxx>/;
657         }
658     }
660     $xml_msg=~ s/<xxx><\/xxx>//;
662     # Return message
663         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
664     return ( $xml_msg );
667 ################################   
668 # @brief 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.
669 # @param msg - STRING - xml message with tags productId, action, state and optional hostId, action and state
670 # @param msg_hash - HASHREF - message information parsed into a hash
671 # @param session_id - INTEGER - POE session id of the processing of this message
672 # @return out_msg - STRING - feedback to GOsa in success and error case
673 sub opsi_set_product_properties {
674         my $startTime = Time::HiRes::time;
675     my ($msg, $msg_hash, $session_id) = @_;
676     my $header = @{$msg_hash->{'header'}}[0];
677     my $source = @{$msg_hash->{'source'}}[0];
678     my $target = @{$msg_hash->{'target'}}[0];
679     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
680     my ($productId, $hostId);
682     # Build return message with twisted target and source
683     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
684     if (defined $forward_to_gosa) {
685         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
686     }
688     # Sanity check of needed parameter
689     if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH'))  {
690         &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
691         &add_content2xml_hash($out_hash, "error", "productId");
692         &main::daemon_log("$session_id ERROR: no productId specified or productId tag invalid: $msg", 1); 
693         return ( &create_xml_string($out_hash) );
694     }
695     if (not exists $msg_hash->{'item'}) {
696         &add_content2xml_hash($out_hash, "error_string", "message needs one xml-tag 'item' and within the xml-tags 'name' and 'value'");
697         &add_content2xml_hash($out_hash, "error", "item");
698         &main::daemon_log("$session_id ERROR: message needs one xml-tag 'item' and within the xml-tags 'name' and 'value': $msg", 1); 
699         return ( &create_xml_string($out_hash) );
700     } else {
701         if ((not exists @{$msg_hash->{'item'}}[0]->{'name'}) || (@{@{$msg_hash->{'item'}}[0]->{'name'}} != 1 )) {
702             &add_content2xml_hash($out_hash, "error_string", "message needs within the xml-tag 'item' one xml-tags 'name'");
703             &add_content2xml_hash($out_hash, "error", "name");
704             &main::daemon_log("$session_id ERROR: message needs within the xml-tag 'item' one xml-tags 'name': $msg", 1); 
705             return ( &create_xml_string($out_hash) );
706         }
707         if ((not exists @{$msg_hash->{'item'}}[0]->{'value'}) || (@{@{$msg_hash->{'item'}}[0]->{'value'}} != 1 )) {
708             &add_content2xml_hash($out_hash, "error_string", "message needs within the xml-tag 'item' one xml-tags 'value'");
709             &add_content2xml_hash($out_hash, "error", "value");
710             &main::daemon_log("$session_id ERROR: message needs within the xml-tag 'item' one xml-tags 'value': $msg", 1); 
711             return ( &create_xml_string($out_hash) );
712         }
713     }
714     # if no hostId is given, set_product_properties will act on globally
715     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} > 1))  {
716         &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
717         &add_content2xml_hash($out_hash, "error", "hostId");
718         &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1); 
719         return ( &create_xml_string($out_hash) );
720     }
722         
723     # Get productId
724     $productId =  @{$msg_hash->{'productId'}}[0];
725     &add_content2xml_hash($out_hash, "productId", $productId);
727     # Get hostId if defined
728     if (exists $msg_hash->{'hostId'}){
729         $hostId = @{$msg_hash->{'hostId'}}[0];
730         &add_content2xml_hash($out_hash, "hostId", $hostId);
731     }
733     # Set product states if requested
734     if (defined @{$msg_hash->{'action'}}[0]){
735         &_set_action($productId, @{$msg_hash->{'action'}}[0], $hostId);
736     }
737     if (defined @{$msg_hash->{'state'}}[0]){
738         &_set_state($productId, @{$msg_hash->{'state'}}[0], $hostId);
739     }
741     # Find properties
742     foreach my $item (@{$msg_hash->{'item'}}){
743         # JSON Query
744         my $callobj;
746         if (defined $hostId){
747             $callobj = {
748                 method  => 'setProductProperty',
749                 params  => [ $productId, $item->{'name'}[0], $item->{'value'}[0], $hostId ],
750                 id  => 1,
751             };
752         } else {
753             $callobj = {
754                 method  => 'setProductProperty',
755                 params  => [ $productId, $item->{'name'}[0], $item->{'value'}[0] ],
756                 id  => 1,
757             };
758         }
760         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
761         my ($res_err, $res_err_string) = &check_opsi_res($res);
763         if ($res_err){
764             &main::daemon_log("$session_id ERROR: communication failed while setting '".$item->{'name'}[0]."': ".$res_err_string, 1);
765             &add_content2xml_hash($out_hash, "error", $res_err_string);
766         }
767     }
770     # Return message
771         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
772     return ( &create_xml_string($out_hash) );
775 ################################   
776 # @brief Reports client hardware inventory.
777 # @param msg - STRING - xml message with tag hostId
778 # @param msg_hash - HASHREF - message information parsed into a hash
779 # @param session_id - INTEGER - POE session id of the processing of this message
780 # @return out_msg - STRING - feedback to GOsa in success and error case
781 sub opsi_get_client_hardware {
782         my $startTime = Time::HiRes::time;
783     my ($msg, $msg_hash, $session_id) = @_;
784     my $header = @{$msg_hash->{'header'}}[0];
785     my $source = @{$msg_hash->{'source'}}[0];
786     my $target = @{$msg_hash->{'target'}}[0];
787     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
788     my $hostId;
789     my $error = 0;
790     my $xml_msg;
792     # Sanity check of needed parameter
793         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
794         $hostId = @{$msg_hash->{'hostId'}}[0];
795         } else {
796                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
797         }
800     # Build return message with twisted target and source
801     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
802     if (defined $forward_to_gosa) {
803       &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
804     }
805         &add_content2xml_hash($out_hash, "hostId", "$hostId");
806         &add_content2xml_hash($out_hash, "xxx", "");
808     # Move to XML string
809     $xml_msg= &create_xml_string($out_hash);
810     
811         my $res = &_callOpsi(method=>'getHardwareInformation_hash', params=>[ $hostId ]);
812         if (not &check_opsi_res($res)){
813                 my $result= $res->result;
814                 if (ref $result eq "HASH") {
815                         foreach my $r (keys %{$result}){
816                                 my $item= "\n<item><id>".xml_quote($r)."</id>";
817                                 my $value= $result->{$r};
818                                 foreach my $sres (@{$value}){
820                                         foreach my $dres (keys %{$sres}){
821                                                 if (defined $sres->{$dres}){
822                                                         $item.= "<$dres>".xml_quote($sres->{$dres})."</$dres>";
823                                                 }
824                                         }
826                                 }
827                                 $item.= "</item>";
828                                 $xml_msg=~ s%<xxx></xxx>%$item<xxx></xxx>%;
830                         }
831                 }
832         }
834         $xml_msg=~ s/<xxx><\/xxx>//;
836     # Return message
837         my $endTime = Time::HiRes::time;
838         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
839         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
840     return ( $xml_msg );
843 ################################   
844 # @brief Reports all Opsi clients. 
845 # @param msg - STRING - xml message 
846 # @param msg_hash - HASHREF - message information parsed into a hash
847 # @param session_id - INTEGER - POE session id of the processing of this message
848 # @return out_msg - STRING - feedback to GOsa in success and error case
849 sub opsi_list_clients {
850         my $startTime = Time::HiRes::time;
851     my ($msg, $msg_hash, $session_id) = @_;
852     my $header = @{$msg_hash->{'header'}}[0];
853     my $source = @{$msg_hash->{'source'}}[0];
854     my $target = @{$msg_hash->{'target'}}[0];
855     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
857     # Build return message with twisted target and source
858     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
859     if (defined $forward_to_gosa) {
860       &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
861     }
862     &add_content2xml_hash($out_hash, "xxx", "");
864     # Move to XML string
865     my $xml_msg= &create_xml_string($out_hash);
867     # JSON Query
868     my $callobj = {
869         method  => 'getClients_listOfHashes',
870         params  => [ ],
871         id  => 1,
872     };
874     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
875     if (not &check_opsi_res($res)){
876         foreach my $host (@{$res->result}){
877             my $item= "\n<item><name>".$host->{'hostId'}."</name>";
878             $item.= "<mac>".xml_quote($host->{'macAddress'})."</mac>";
879             if (defined($host->{'description'})){
880                 $item.= "<description>".xml_quote($host->{'description'})."</description>";
881             }
882             if (defined($host->{'notes'})){
883                 $item.= "<notes>".xml_quote($host->{'notes'})."</notes>";
884             }
885             if (defined($host->{'lastSeen'})){
886                 $item.= "<lastSeen>".xml_quote($host->{'lastSeen'})."</lastSeen>";
887             }
889             $item.= "</item>";
890             $xml_msg=~ s%<xxx></xxx>%$item<xxx></xxx>%;
891         }
892     }
893     $xml_msg=~ s/<xxx><\/xxx>//;
895         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
896     return ( $xml_msg );
899 ################################   
900 # @brief Reports client software inventory.
901 # @param msg - STRING - xml message with tag hostId
902 # @param msg_hash - HASHREF - message information parsed into a hash
903 # @param session_id - INTEGER - POE session id of the processing of this message
904 # @return out_msg - STRING - feedback to GOsa in success and error case
905 sub opsi_get_client_software {
906         my $startTime = Time::HiRes::time;
907     my ($msg, $msg_hash, $session_id) = @_;
908     my $header = @{$msg_hash->{'header'}}[0];
909     my $source = @{$msg_hash->{'source'}}[0];
910     my $target = @{$msg_hash->{'target'}}[0];
911     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
912     my $error = 0;
913     my $hostId;
914     my $xml_msg;
916     # Build return message with twisted target and source
917     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
918     if (defined $forward_to_gosa) {
919       &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
920     }
922     # Sanity check of needed parameter
923     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
924         $error++;
925         &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
926         &add_content2xml_hash($out_hash, "error", "hostId");
927         &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1); 
928     }
930     if (not $error) {
932     # Get hostId
933         $hostId = @{$msg_hash->{'hostId'}}[0];
934         &add_content2xml_hash($out_hash, "hostId", "$hostId");
935         &add_content2xml_hash($out_hash, "xxx", "");
936     }
938     $xml_msg= &create_xml_string($out_hash);
940     if (not $error) {
942     # JSON Query
943         my $callobj = {
944             method  => 'getSoftwareInformation_hash',
945             params  => [ $hostId ],
946             id  => 1,
947         };
949         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
950         if (not &check_opsi_res($res)){
951             my $result= $res->result;
952         }
954         $xml_msg=~ s/<xxx><\/xxx>//;
956     }
958     # Return message
959         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
960     return ( $xml_msg );
963 ################################   
964 # @brief Reports product for given hostId or globally.
965 # @param msg - STRING - xml message with optional 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_local_products {
970         my $startTime = Time::HiRes::time;
971     my ($msg, $msg_hash, $session_id) = @_;
972     my $header = @{$msg_hash->{'header'}}[0];
973     my $source = @{$msg_hash->{'source'}}[0];
974     my $target = @{$msg_hash->{'target'}}[0];
975     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
976     my $hostId;
978     # Build return message with twisted target and source
979     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
980     if (defined $forward_to_gosa) {
981         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
982     }
983     &add_content2xml_hash($out_hash, "xxx", "");
985     # Get hostId if defined
986     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1))  {
987         $hostId = @{$msg_hash->{'hostId'}}[0];
988         &add_content2xml_hash($out_hash, "hostId", $hostId);
989     }
991     # Move to XML string
992     my $xml_msg= &create_xml_string($out_hash);
994     # For hosts, only return the products that are or get installed
995     my $callobj;
996     $callobj = {
997         method  => 'getLocalBootProductIds_list',
998         params  => [ ],
999         id  => 1,
1000     };
1002     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1003     my %r = ();
1004     for (@{$res->result}) { $r{$_} = 1 }
1006     if (not &check_opsi_res($res)){
1008         if (defined $hostId){
1009             $callobj = {
1010                 method  => 'getProductStates_hash',
1011                 params  => [ $hostId ],
1012                 id  => 1,
1013             };
1015             my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
1016             if (not &check_opsi_res($hres)){
1017                 my $htmp= $hres->result->{$hostId};
1019                 # Check state != not_installed or action == setup -> load and add
1020                 foreach my $product (@{$htmp}){
1022                     if (!defined ($r{$product->{'productId'}})){
1023                         next;
1024                     }
1026                     # Now we've a couple of hashes...
1027                     if ($product->{'installationStatus'} ne "not_installed" or
1028                             $product->{'actionRequest'} eq "setup"){
1029                         my $state= "<state>".$product->{'installationStatus'}."</state><action>".$product->{'actionRequest'}."</action>";
1031                         $callobj = {
1032                             method  => 'getProduct_hash',
1033                             params  => [ $product->{'productId'} ],
1034                             id  => 1,
1035                         };
1037                         my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
1038                         if (not &check_opsi_res($sres)){
1039                             my $tres= $sres->result;
1041                             my $name= xml_quote($tres->{'name'});
1042                             my $r= $product->{'productId'};
1043                             my $description= xml_quote($tres->{'description'});
1044                             $name=~ s/\//\\\//;
1045                             $description=~ s/\//\\\//;
1046                             $xml_msg=~ s/<xxx><\/xxx>/\n<item><productId>$r<\/productId><name>$name<\/name><description>$description<\/description><\/item>$state<xxx><\/xxx>/;
1047                         }
1049                     }
1050                 }
1052             }
1054         } else {
1055             foreach my $r (@{$res->result}) {
1056                 $callobj = {
1057                     method  => 'getProduct_hash',
1058                     params  => [ $r ],
1059                     id  => 1,
1060                 };
1062                 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
1063                 if (not &check_opsi_res($sres)){
1064                     my $tres= $sres->result;
1066                     my $name= xml_quote($tres->{'name'});
1067                     my $description= xml_quote($tres->{'description'});
1068                     $name=~ s/\//\\\//;
1069                     $description=~ s/\//\\\//;
1070                     $xml_msg=~ s/<xxx><\/xxx>/\n<item><productId>$r<\/productId><name>$name<\/name><description>$description<\/description><\/item><xxx><\/xxx>/;
1071                 }
1073             }
1075         }
1076     }
1078     $xml_msg=~ s/<xxx><\/xxx>//;
1080     # Retrun Message
1081         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1082     return ( $xml_msg );
1085 ################################   
1086 # @brief Deletes a client from Opsi.
1087 # @param msg - STRING - xml message with tag hostId
1088 # @param msg_hash - HASHREF - message information parsed into a hash
1089 # @param session_id - INTEGER - POE session id of the processing of this message
1090 # @return out_msg - STRING - feedback to GOsa in success and error case
1091 sub opsi_del_client {
1092         my $startTime = Time::HiRes::time;
1093     my ($msg, $msg_hash, $session_id) = @_;
1094     my $header = @{$msg_hash->{'header'}}[0];
1095     my $source = @{$msg_hash->{'source'}}[0];
1096     my $target = @{$msg_hash->{'target'}}[0];
1097     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1098     my $hostId;
1099     my $error = 0;
1101     # Build return message with twisted target and source
1102     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1103     if (defined $forward_to_gosa) {
1104       &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1105     }
1107     # Sanity check of needed parameter
1108     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
1109         $error++;
1110         &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
1111         &add_content2xml_hash($out_hash, "error", "hostId");
1112         &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1); 
1113     }
1115     if (not $error) {
1117     # Get hostId
1118         $hostId = @{$msg_hash->{'hostId'}}[0];
1119         &add_content2xml_hash($out_hash, "hostId", "$hostId");
1121     # JSON Query
1122         my $callobj = {
1123             method  => 'deleteClient',
1124             params  => [ $hostId ],
1125             id  => 1,
1126         };
1127         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1128     }
1130     # Move to XML string
1131     my $xml_msg= &create_xml_string($out_hash);
1133     # Return message
1134         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1135     return ( $xml_msg );
1138 ################################   
1139 # @brief Set a client in Opsi to install and trigger a wake on lan message (WOL).  
1140 # @param msg - STRING - xml message with tags hostId, macaddress
1141 # @param msg_hash - HASHREF - message information parsed into a hash
1142 # @param session_id - INTEGER - POE session id of the processing of this message
1143 # @return out_msg - STRING - feedback to GOsa in success and error case
1144 sub opsi_install_client {
1145         my $startTime = Time::HiRes::time;
1146     my ($msg, $msg_hash, $session_id) = @_;
1147     my $header = @{$msg_hash->{'header'}}[0];
1148     my $source = @{$msg_hash->{'source'}}[0];
1149     my $target = @{$msg_hash->{'target'}}[0];
1150     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1151     my ($hostId, $macaddress);
1152     my $error = 0;
1153     my @out_msg_l;
1155     # Build return message with twisted target and source
1156     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1157     if (defined $forward_to_gosa) {
1158         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1159     }
1161     # Sanity check of needed parameter
1162     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
1163         $error++;
1164         &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
1165         &add_content2xml_hash($out_hash, "error", "hostId");
1166         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
1167     }
1168     if ((not exists $msg_hash->{'macaddress'}) || (@{$msg_hash->{'macaddress'}} != 1) || (@{$msg_hash->{'macaddress'}}[0] eq ref 'HASH') )  {
1169         $error++;
1170         &add_content2xml_hash($out_hash, "error_string", "no macaddress specified or macaddress tag invalid");
1171         &add_content2xml_hash($out_hash, "error", "macaddress");
1172         &main::daemon_log("$session_id ERROR: no macaddress specified or macaddress tag invalid: $msg", 1); 
1173     } else {
1174         if ((exists $msg_hash->{'macaddress'}) && 
1175                 ($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)) {  
1176             $macaddress = $1; 
1177         } else { 
1178             $error ++; 
1179             &add_content2xml_hash($out_hash, "error_string", "given mac address is not correct");
1180             &add_content2xml_hash($out_hash, "error", "macaddress");
1181             &main::daemon_log("$session_id ERROR: given mac address is not correct: $msg", 1); 
1182         }
1183     }
1185     if (not $error) {
1187     # Get hostId
1188         $hostId = @{$msg_hash->{'hostId'}}[0];
1189         &add_content2xml_hash($out_hash, "hostId", "$hostId");
1191         # Load all products for this host with status != "not_installed" or actionRequest != "none"
1192         my $callobj = {
1193             method  => 'getProductStates_hash',
1194             params  => [ $hostId ],
1195             id  => 1,
1196         };
1198         my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
1199         if (not &check_opsi_res($hres)){
1200             my $htmp= $hres->result->{$hostId};
1202             # check state != not_installed or action == setup -> load and add
1203             foreach my $product (@{$htmp}){
1204                 # Now we've a couple of hashes...
1205                 if ($product->{'installationStatus'} ne "not_installed" or
1206                         $product->{'actionRequest'} ne "none"){
1208                     # Do an action request for all these -> "setup".
1209                     $callobj = {
1210                         method  => 'setProductActionRequest',
1211                         params  => [ $product->{'productId'}, $hostId, "setup" ],
1212                         id  => 1,
1213                     };
1214                     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1215                     my ($res_err, $res_err_string) = &check_opsi_res($res);
1216                     if ($res_err){
1217                         &main::daemon_log("$session_id ERROR: cannot set product action request for '$hostId': ".$product->{'productId'}, 1);
1218                     } else {
1219                         &main::daemon_log("$session_id INFO: requesting 'setup' for '".$product->{'productId'}."' on $hostId", 1);
1220                     }
1221                 }
1222             }
1223         }
1224         push(@out_msg_l, &create_xml_string($out_hash));
1225     
1227     # Build wakeup message for client
1228         if (not $error) {
1229             my $wakeup_hash = &create_xml_hash("trigger_wake", "GOSA", "KNOWN_SERVER");
1230             &add_content2xml_hash($wakeup_hash, 'macaddress', $macaddress);
1231             my $wakeup_msg = &create_xml_string($wakeup_hash);
1232             push(@out_msg_l, $wakeup_msg);
1234             # invoke trigger wake for this gosa-si-server
1235             &main::server_server_com::trigger_wake($wakeup_msg, $wakeup_hash, $session_id);
1236         }
1237     }
1238     
1239     # Return messages
1240         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1241     return @out_msg_l;
1244 ################################
1245 # @brief Set action for an Opsi client
1246 # @param product - STRING - Opsi product
1247 # @param action - STRING - action
1248 # @param hostId - STRING - Opsi hostId
1249 sub _set_action {
1250   my $product= shift;
1251   my $action = shift;
1252   my $hostId = shift;
1253   my $callobj;
1255   $callobj = {
1256     method  => 'setProductActionRequest',
1257     params  => [ $product, $hostId, $action],
1258     id  => 1,
1259   };
1261   $main::opsi_client->call($main::opsi_url, $callobj);
1264 ################################
1265 # @brief Set state for an Opsi client
1266 # @param product - STRING - Opsi product
1267 # @param action - STRING - state
1268 # @param hostId - STRING - Opsi hostId
1269 sub _set_state {
1270   my $product = shift;
1271   my $state = shift;
1272   my $hostId = shift;
1273   my $callobj;
1275   $callobj = {
1276     method  => 'setProductState',
1277     params  => [ $product, $hostId, $state ],
1278     id  => 1,
1279   };
1281   $main::opsi_client->call($main::opsi_url, $callobj);
1284 ################################
1285 # @brief Create a license pool at Opsi server.
1286 # @param licensePoolId The name of the pool (optional). 
1287 # @param description The description of the pool (optional).
1288 # @param productIds A list of assigned porducts of the pool (optional). 
1289 # @param windowsSoftwareIds A list of windows software IDs associated to the pool (optional). 
1290 sub opsi_createLicensePool {
1291         my $startTime = Time::HiRes::time;
1292     my ($msg, $msg_hash, $session_id) = @_;
1293     my $header = @{$msg_hash->{'header'}}[0];
1294     my $source = @{$msg_hash->{'source'}}[0];
1295     my $target = @{$msg_hash->{'target'}}[0];
1296         my $out_hash;
1297         my $licensePoolId = defined $msg_hash->{'licensePoolId'} ? @{$msg_hash->{'licensePoolId'}}[0] : undef;
1298         my $description = defined $msg_hash->{'description'} ? @{$msg_hash->{'description'}}[0] : undef;
1299         my @productIds = defined $msg_hash->{'productIds'} ? $msg_hash->{'productIds'} : undef;
1300         my @windowsSoftwareIds = defined $msg_hash->{'windowsSoftwareIds'} ? $msg_hash->{'windowsSoftwareIds'} : undef;
1302         # Create license Pool
1303     my $callobj = {
1304         method  => 'createLicensePool',
1305         params  => [ $licensePoolId, $description, @productIds, @windowsSoftwareIds],
1306         id  => 1,
1307     };
1308     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1310         # Check Opsi error
1311         my ($res_error, $res_error_str) = &check_opsi_res($res);
1312         if ($res_error){
1313                 # Create error message
1314                 &main::daemon_log("$session_id ERROR: cannot create license pool at Opsi server: ".$res_error_str, 1);
1315                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1316                 return ( &create_xml_string($out_hash) );
1317         }
1319         # Create function result message
1320         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source, $res->result);
1321         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1323         my $endTime = Time::HiRes::time;
1324         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1325         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1326         return ( &create_xml_string($out_hash) );
1329 ################################
1330 # @brief Return licensePoolId, description, productIds and windowsSoftwareIds for all found license pools.
1331 sub opsi_getLicensePools_listOfHashes {
1332         my $startTime = Time::HiRes::time;
1333     my ($msg, $msg_hash, $session_id) = @_;
1334     my $header = @{$msg_hash->{'header'}}[0];
1335     my $source = @{$msg_hash->{'source'}}[0];
1336         my $out_hash;
1338         # Fetch infos from Opsi server
1339     my $callobj = {
1340         method  => 'getLicensePools_listOfHashes',
1341         params  => [ ],
1342         id  => 1,
1343     };
1344     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1346         # Check Opsi error
1347         my ($res_error, $res_error_str) = &check_opsi_res($res);
1348         if ($res_error){
1349                 # Create error message
1350                 &main::daemon_log("$session_id ERROR: cannot get license pool ID list from Opsi server: ".$res_error_str, 1);
1351                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1352                 return ( &create_xml_string($out_hash) );
1353         }
1355         # Create function result message
1356         my $res_hash = { 'hit'=> [] };
1357         foreach my $licensePool ( @{$res->result}) {
1358                 my $licensePool_hash = { 'licensePoolId' => [$licensePool->{'licensePoolId'}],
1359                         'description' => [$licensePool->{'description'}],
1360                         'productIds' => $licensePool->{'productIds'},
1361                         'windowsSoftwareIds' => $licensePool->{'windowsSoftwareIds'},
1362                         };
1363                 push( @{$res_hash->{hit}}, $licensePool_hash );
1364         }
1366         # Create function result message
1367         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1368         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1369         $out_hash->{result} = [$res_hash];
1371         my $endTime = Time::HiRes::time;
1372         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1373         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1374         return ( &create_xml_string($out_hash) );
1377 ################################
1378 # @brief Return productIds, windowsSoftwareIds and description for a given licensePoolId
1379 # @param licensePoolId The name of the pool. 
1380 sub opsi_getLicensePool_hash {
1381         my $startTime = Time::HiRes::time;
1382     my ($msg, $msg_hash, $session_id) = @_;
1383     my $header = @{$msg_hash->{'header'}}[0];
1384     my $source = @{$msg_hash->{'source'}}[0];
1385     my $target = @{$msg_hash->{'target'}}[0];
1386     my $licensePoolId;
1387         my $out_hash;
1389         # Check input sanity
1390         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1391                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1392         } else {
1393                 return &_giveErrorFeedback($msg_hash, "", $session_id, $_);
1394         }
1396         # Fetch infos from Opsi server
1397     my $callobj = {
1398         method  => 'getLicensePool_hash',
1399         params  => [ $licensePoolId ],
1400         id  => 1,
1401     };
1402     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1404         # Check Opsi error
1405         my ($res_error, $res_error_str) = &check_opsi_res($res);
1406         if ($res_error){
1407                 # Create error message
1408                 &main::daemon_log("$session_id ERROR: cannot get license pool from Opsi server: ".$res_error_str, 1);
1409                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source);
1410                 &add_content2xml_hash($out_hash, "error", $res_error_str);
1411                 return ( &create_xml_string($out_hash) );
1412         }
1414         # Create function result message
1415         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1416         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1417         &add_content2xml_hash($out_hash, "licensePoolId", $res->result->{'licensePoolId'});
1418         &add_content2xml_hash($out_hash, "description", $res->result->{'description'});
1419         map(&add_content2xml_hash($out_hash, "productIds", "$_"), @{ $res->result->{'productIds'} });
1420         map(&add_content2xml_hash($out_hash, "windowsSoftwareIds", "$_"), @{ $res->result->{'windowsSoftwareIds'} });
1422         my $endTime = Time::HiRes::time;
1423         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1424         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1425         return ( &create_xml_string($out_hash) );
1428 sub _parse_getSoftwareLicenseUsages {
1429         my $res = shift;
1431         # Parse Opsi result
1432         my $tmp_licensePool_cache = {};
1433         my $res_hash = { 'hit'=> [] };
1434         foreach my $license ( @{$res}) {
1435                 my $tmp_licensePool = $license->{'licensePoolId'};
1436                 if (not exists $tmp_licensePool_cache->{$tmp_licensePool}) {
1437                         # Fetch missing informations from Opsi and cache the results for a possible later usage
1438                         my ($res, $err) = &_getLicensePool_hash('licensePoolId'=>$tmp_licensePool);
1439                         if (not $err) {
1440                                 $tmp_licensePool_cache->{$tmp_licensePool} = $res;
1441                         }
1442                 }
1443                 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
1444                         'notes' => [$license->{'notes'}],
1445                         'licenseKey' => [$license->{'licenseKey'}],
1446                         'hostId' => [$license->{'hostId'}],
1447                         'licensePoolId' => [$tmp_licensePool],
1448                         };
1449                 if (exists $tmp_licensePool_cache->{$tmp_licensePool}) {
1450                         $license_hash->{$tmp_licensePool} = {'productIds'=>[], 'windowsSoftwareIds'=>[]};
1451                         map (push (@{$license_hash->{$tmp_licensePool}->{productIds}}, $_), @{$tmp_licensePool_cache->{$tmp_licensePool}->{productIds}});
1452                         map (push (@{$license_hash->{$tmp_licensePool}->{windowsSoftwareIds}}, $_), @{$tmp_licensePool_cache->{$tmp_licensePool}->{windowsSoftwareIds}});
1453                 }
1454                 push( @{$res_hash->{hit}}, $license_hash );
1455         }
1457         return $res_hash;
1460 ################################
1461 # @brief Returns softwareLicenseId, notes, licenseKey, hostId and licensePoolId for optional given licensePoolId and hostId
1462 # @param hostid Something like client_1.intranet.mydomain.de (optional).
1463 # @param licensePoolId The name of the pool (optional). 
1464 sub opsi_getSoftwareLicenseUsages {
1465         my $startTime = Time::HiRes::time;
1466         my ($msg, $msg_hash, $session_id) = @_;
1467         my $header = @{$msg_hash->{'header'}}[0];
1468         my $source = @{$msg_hash->{'source'}}[0];
1469         my $target = @{$msg_hash->{'target'}}[0];
1470         my $licensePoolId = defined $msg_hash->{'licensePoolId'} ? @{$msg_hash->{'licensePoolId'}}[0] : undef;
1471         my $hostId = defined $msg_hash->{'hostId'} ? @{$msg_hash->{'hostId'}}[0] : undef;
1472         my $out_hash;
1474         my ($res, $err) = &_getSoftwareLicenseUsages_listOfHashes('licensePoolId'=>$licensePoolId, 'hostId'=>$hostId);
1475         if ($err){
1476                 return &_giveErrorFeedback($msg_hash, "cannot fetch software licenses from license pool : ".$res, $session_id);
1477         }
1479         # Parse Opsi result
1480         my $res_hash = &_parse_getSoftwareLicenseUsages($res);
1482         # Create function result message
1483         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1484         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1485         $out_hash->{result} = [$res_hash];
1487         my $endTime = Time::HiRes::time;
1488         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1489         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1490         return ( &create_xml_string($out_hash) );
1493 ################################
1494 # @brief Returns softwareLicenseId, notes, licenseKey, hostId and licensePoolId. Function return is identical to opsi_getSoftwareLicenseUsages
1495 # @param productId Something like 'firefox', 'python' or anything else .
1496 sub opsi_getSoftwareLicenseUsagesForProductId {
1497         my $startTime = Time::HiRes::time;
1498         my ($msg, $msg_hash, $session_id) = @_;
1499         my $header = @{$msg_hash->{'header'}}[0];
1500         my $source = @{$msg_hash->{'source'}}[0];
1502         # Check input sanity
1503         my $productId;
1504         if (&_check_xml_tag_is_ok ($msg_hash, 'productId')) {
1505                 $productId= @{$msg_hash->{'productId'}}[0];
1506         } else {
1507                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1508         }
1510         # Fetch licensePoolId for productId
1511         my ($res, $err) = &_getLicensePoolId('productId'=>$productId);
1512         if ($err){
1513                 return &_giveErrorFeedback($msg_hash, "cannot fetch licensePoolId for given productId : ".$res, $session_id);
1514         }
1516         my $licensePoolId;
1518         # Fetch softwareLiceceUsages for licensePoolId
1519         ($res, $err) = &_getSoftwareLicenseUsages_listOfHashes('licensePoolId'=>$licensePoolId);
1520         if ($err){
1521                 return &_giveErrorFeedback($msg_hash, "cannot fetch software licenses from license pool : ".$res, $session_id);
1522         }
1524         # Parse Opsi result
1525         my $res_hash = &_parse_getSoftwareLicenseUsages($res);
1527         # Create function result message
1528         my $out_hash = &create_xml_hash("answer_$header", $main::server_address, $source);
1529         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1530         $out_hash->{result} = [$res_hash];
1532         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1533         return ( &create_xml_string($out_hash) );
1536 ################################
1537 # @brief Returns expirationDate, boundToHost, maxInstallation, licenseTyp, licensePoolIds and licenseKeys for a given softwareLicense ID.
1538 # @param softwareLicenseId Identificator of a license.
1539 sub opsi_getSoftwareLicense_hash {
1540         my $startTime = Time::HiRes::time;
1541         my ($msg, $msg_hash, $session_id) = @_;
1542         my $header = @{$msg_hash->{'header'}}[0];
1543         my $source = @{$msg_hash->{'source'}}[0];
1544         my $target = @{$msg_hash->{'target'}}[0];
1545         my $softwareLicenseId;
1546         my $out_hash;
1548         # Check input sanity
1549         if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
1550                 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
1551         } else {
1552                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1553         }
1555         my $callobj = {
1556                 method  => 'getSoftwareLicense_hash',
1557                 params  => [ $softwareLicenseId ],
1558                 id  => 1,
1559         };
1560         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1562         # Check Opsi error
1563         my ($res_error, $res_error_str) = &check_opsi_res($res);
1564         if ($res_error){
1565                 # Create error message
1566                 &main::daemon_log("$session_id ERROR: cannot fetch information for license '$softwareLicenseId': ".$res_error_str, 1);
1567                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1568                 return ( &create_xml_string($out_hash) );
1569         }
1570         
1571         # Create function result message
1572         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1573         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1574         &add_content2xml_hash($out_hash, "expirationDate", $res->result->{'expirationDate'});
1575         &add_content2xml_hash($out_hash, "boundToHost", $res->result->{'boundToHost'});
1576         &add_content2xml_hash($out_hash, "maxInstallations", $res->result->{'maxInstallations'});
1577         &add_content2xml_hash($out_hash, "licenseTyp", $res->result->{'licenseTyp'});
1578         foreach my $licensePoolId ( @{$res->result->{'licensePoolIds'}}) {
1579                 &add_content2xml_hash($out_hash, "licensePoolId", $licensePoolId);
1580                 &add_content2xml_hash($out_hash, $licensePoolId, $res->result->{'licenseKeys'}->{$licensePoolId});
1581         }
1583         my $endTime = Time::HiRes::time;
1584         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1585         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1586         return ( &create_xml_string($out_hash) );
1589 ################################
1590 # @brief Delete licnese pool by license pool ID. A pool can only be deleted if there are no software licenses bound to the pool. 
1591 # The fixed parameter deleteLicenses=True specifies that all software licenses bound to the pool are being deleted. 
1592 # @param licensePoolId The name of the pool. 
1593 sub opsi_deleteLicensePool {
1594         my $startTime = Time::HiRes::time;
1595         my ($msg, $msg_hash, $session_id) = @_;
1596     my $header = @{$msg_hash->{'header'}}[0];
1597     my $source = @{$msg_hash->{'source'}}[0];
1598     my $target = @{$msg_hash->{'target'}}[0];
1599     my $licensePoolId;
1600         my $out_hash;
1602         # Check input sanity
1603         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1604                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1605         } else {
1606                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1607         }
1609         # Fetch softwareLicenseIds used in license pool
1610         # This has to be done because function deleteLicensePool deletes the pool and the corresponding software licenses
1611         # but not the license contracts of the software licenses. In our case each software license has exactly one license contract. 
1612         my $callobj = {
1613                 method  => 'getSoftwareLicenses_listOfHashes',
1614                 params  => [ ],
1615                 id  => 1,
1616         };
1617         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1619         # Keep list of licenseContractIds in mind to delete it after the deletion of the software licenses
1620         my @lCI_toBeDeleted;
1621         foreach my $softwareLicenseHash ( @{$res->result} ) {
1622                 if ((@{$softwareLicenseHash->{'licensePoolIds'}} == 0) || (@{$softwareLicenseHash->{'licensePoolIds'}}[0] ne $licensePoolId)) { 
1623                         next; 
1624                 }  
1625                 push (@lCI_toBeDeleted, $softwareLicenseHash->{'licenseContractId'});
1626         }
1628         # Delete license pool at Opsi server
1629     $callobj = {
1630         method  => 'deleteLicensePool',
1631         params  => [ $licensePoolId, 'deleteLicenses=True'  ],
1632         id  => 1,
1633     };
1634     $res = $main::opsi_client->call($main::opsi_url, $callobj);
1635         my ($res_error, $res_error_str) = &check_opsi_res($res);
1636         if ($res_error){
1637                 # Create error message
1638                 &main::daemon_log("$session_id ERROR: cannot delete license pool at Opsi server: ".$res_error_str, 1);
1639                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1640                 return ( &create_xml_string($out_hash) );
1641         } 
1643         # Delete each license contract connected with the license pool
1644         foreach my $licenseContractId ( @lCI_toBeDeleted ) {
1645                 my $callobj = {
1646                         method  => 'deleteLicenseContract',
1647                         params  => [ $licenseContractId ],
1648                         id  => 1,
1649                 };
1650                 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1651                 my ($res_error, $res_error_str) = &check_opsi_res($res);
1652                 if ($res_error){
1653                         # Create error message
1654                         &main::daemon_log("$session_id ERROR: cannot delete license contract '$licenseContractId' connected with license pool '$licensePoolId' at Opsi server: ".$res_error_str, 1);
1655                         $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1656                         return ( &create_xml_string($out_hash) );
1657                 }
1658         }
1660         # Create function result message
1661         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1662         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1664         my $endTime = Time::HiRes::time;
1665         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1666         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1667         return ( &create_xml_string($out_hash) );
1670 ################################
1671 # @brief Create a license contract, create a software license and add the software license to the license pool
1672 # @param licensePoolId The name of the pool the license should be assigned.
1673 # @param licenseKey The license key.
1674 # @param partner Name of the license partner (optional).
1675 # @param conclusionDate Date of conclusion of license contract (optional)
1676 # @param notificationDate Date of notification that license is running out soon (optional).
1677 # @param notes This is the place for some notes (optional)
1678 # @param softwareLicenseId Identificator of a license (optional).
1679 # @param licenseTyp Typ of a licnese, either "OEM", "VOLUME" or "RETAIL" (optional).
1680 # @param maxInstallations The number of clients use this license (optional). 
1681 # @param boundToHost The name of the client the license is bound to (optional).
1682 # @param expirationDate The date when the license is running down (optional). 
1683 sub opsi_createLicense {
1684         my $startTime = Time::HiRes::time;
1685         my ($msg, $msg_hash, $session_id) = @_;
1686     my $header = @{$msg_hash->{'header'}}[0];
1687     my $source = @{$msg_hash->{'source'}}[0];
1688     my $target = @{$msg_hash->{'target'}}[0];
1689         my $partner = defined $msg_hash->{'partner'} ? @{$msg_hash->{'partner'}}[0] : undef;
1690         my $conclusionDate = defined $msg_hash->{'conclusionDate'} ? @{$msg_hash->{'conclusionDate'}}[0] : undef;
1691         my $notificationDate = defined $msg_hash->{'notificationDate'} ? @{$msg_hash->{'notificationDate'}}[0] : undef;
1692         my $notes = defined $msg_hash->{'notes'} ? @{$msg_hash->{'notes'}}[0] : undef;
1693         my $licenseContractId = undef;
1694         my $softwareLicenseId = defined $msg_hash->{'softwareLicenseId'} ? @{$msg_hash->{'softwareLicenseId'}}[0] : undef;
1695         my $licenseType = defined $msg_hash->{'licenseType'} ? @{$msg_hash->{'licenseType'}}[0] : undef;
1696         my $maxInstallations = defined $msg_hash->{'maxInstallations'} ? @{$msg_hash->{'maxInstallations'}}[0] : undef;
1697         my $boundToHost = defined $msg_hash->{'boundToHost'} ? @{$msg_hash->{'boundToHost'}}[0] : undef;
1698         my $expirationDate = defined $msg_hash->{'expirationDate'} ? @{$msg_hash->{'expirationDate'}}[0] : undef;
1699         my $licensePoolId;
1700         my $licenseKey;
1701         my $out_hash;
1703         # Check input sanity
1704         if (&_check_xml_tag_is_ok ($msg_hash, 'licenseKey')) {
1705                 $licenseKey = @{$msg_hash->{'licenseKey'}}[0];
1706         } else {
1707                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1708         }
1709         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1710                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1711         } else {
1712                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1713         }
1714         if ((defined $licenseType) && (not exists $licenseTyp_hash->{$licenseType})) {
1715                 return &_giveErrorFeedback($msg_hash, "The typ of a license can be either 'OEM', 'VOLUME' or 'RETAIL'.", $session_id);
1716         }
1717         
1718         # Automatically define licenseContractId if ID is not given
1719         if (defined $softwareLicenseId) { 
1720                 $licenseContractId = "c_".$softwareLicenseId;
1721         }
1723         # Create license contract at Opsi server
1724     my $callobj = {
1725         method  => 'createLicenseContract',
1726         params  => [ $licenseContractId, $partner, $conclusionDate, $notificationDate, undef, $notes ],
1727         id  => 1,
1728     };
1729     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1731         # Check Opsi error
1732         my ($res_error, $res_error_str) = &check_opsi_res($res);
1733         if ($res_error){
1734                 # Create error message
1735                 &main::daemon_log("$session_id ERROR: cannot create license contract at Opsi server: ".$res_error_str, 1);
1736                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1737                 return ( &create_xml_string($out_hash) );
1738         }
1739         
1740         $licenseContractId = $res->result;
1742         # Create software license at Opsi server
1743     $callobj = {
1744         method  => 'createSoftwareLicense',
1745         params  => [ $softwareLicenseId, $licenseContractId, $licenseType, $maxInstallations, $boundToHost, $expirationDate ],
1746         id  => 1,
1747     };
1748     $res = $main::opsi_client->call($main::opsi_url, $callobj);
1750         # Check Opsi error
1751         ($res_error, $res_error_str) = &check_opsi_res($res);
1752         if ($res_error){
1753                 # Create error message
1754                 &main::daemon_log("$session_id ERROR: cannot create software license at Opsi server: ".$res_error_str, 1);
1755                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1756                 return ( &create_xml_string($out_hash) );
1757         }
1759         $softwareLicenseId = $res->result;
1761         # Add software license to license pool
1762         $callobj = {
1763         method  => 'addSoftwareLicenseToLicensePool',
1764         params  => [ $softwareLicenseId, $licensePoolId, $licenseKey ],
1765         id  => 1,
1766     };
1767     $res = $main::opsi_client->call($main::opsi_url, $callobj);
1769         # Check Opsi error
1770         ($res_error, $res_error_str) = &check_opsi_res($res);
1771         if ($res_error){
1772                 # Create error message
1773                 &main::daemon_log("$session_id ERROR: cannot add software license to license pool at Opsi server: ".$res_error_str, 1);
1774                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1775                 return ( &create_xml_string($out_hash) );
1776         }
1778         # Create function result message
1779         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1780         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1781         
1782         my $endTime = Time::HiRes::time;
1783         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1784         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1785         return ( &create_xml_string($out_hash) );
1788 ################################
1789 # @brief Assign a software license to a host
1790 # @param hostid Something like client_1.intranet.mydomain.de
1791 # @param licensePoolId The name of the pool.
1792 sub opsi_assignSoftwareLicenseToHost {
1793         my $startTime = Time::HiRes::time;
1794         my ($msg, $msg_hash, $session_id) = @_;
1795     my $header = @{$msg_hash->{'header'}}[0];
1796     my $source = @{$msg_hash->{'source'}}[0];
1797     my $target = @{$msg_hash->{'target'}}[0];
1798         my $hostId;
1799         my $licensePoolId;
1801         # Check input sanity
1802         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1803                 $hostId = @{$msg_hash->{'hostId'}}[0];
1804         } else {
1805                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1806         }
1807         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1808                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1809         } else {
1810                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1811         }
1813         # Assign a software license to a host
1814         my $callobj = {
1815         method  => 'getAndAssignSoftwareLicenseKey',
1816         params  => [ $hostId, $licensePoolId ],
1817         id  => 1,
1818     };
1819     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1821         # Check Opsi error
1822         my ($res_error, $res_error_str) = &check_opsi_res($res);
1823         if ($res_error){
1824                 # Create error message
1825                 &main::daemon_log("$session_id ERROR: cannot assign a software license to a host at Opsi server: ".$res_error_str, 1);
1826                 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1827                 return ( &create_xml_string($out_hash) );
1828         }
1830         # Create function result message
1831         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1832         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1833         
1834         my $endTime = Time::HiRes::time;
1835         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1836         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1837         return ( &create_xml_string($out_hash) );
1840 ################################
1841 # @brief Unassign a software license from a host.
1842 # @param hostid Something like client_1.intranet.mydomain.de
1843 # @param licensePoolId The name of the pool.
1844 sub opsi_unassignSoftwareLicenseFromHost {
1845         my $startTime = Time::HiRes::time;
1846         my ($msg, $msg_hash, $session_id) = @_;
1847     my $header = @{$msg_hash->{'header'}}[0];
1848     my $source = @{$msg_hash->{'source'}}[0];
1849     my $target = @{$msg_hash->{'target'}}[0];
1850         my $hostId;
1851         my $licensePoolId;
1853         # Check input sanity
1854         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1855                 $hostId = @{$msg_hash->{'hostId'}}[0];
1856         } else {
1857                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1858         }
1859         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1860                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1861         } else {
1862                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1863         }
1865         # Unassign a software license from a host
1866         my $callobj = {
1867         method  => 'deleteSoftwareLicenseUsage',
1868         params  => [ $hostId, '', $licensePoolId ],
1869         id  => 1,
1870     };
1871     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1873         # Check Opsi error
1874         my ($res_error, $res_error_str) = &check_opsi_res($res);
1875         if ($res_error){
1876                 # Create error message
1877                 &main::daemon_log("$session_id ERROR: cannot unassign a software license from a host at Opsi server: ".$res_error_str, 1);
1878                 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1879                 return ( &create_xml_string($out_hash) );
1880         }
1882         # Create function result message
1883         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1884         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1885         
1886         my $endTime = Time::HiRes::time;
1887         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1888         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1889         return ( &create_xml_string($out_hash) );
1892 ################################
1893 # @brief Unassign all software licenses from a host
1894 # @param hostid Something like client_1.intranet.mydomain.de
1895 sub opsi_unassignAllSoftwareLicensesFromHost {
1896         my $startTime = Time::HiRes::time;
1897         my ($msg, $msg_hash, $session_id) = @_;
1898     my $header = @{$msg_hash->{'header'}}[0];
1899     my $source = @{$msg_hash->{'source'}}[0];
1900     my $target = @{$msg_hash->{'target'}}[0];
1901         my $hostId;
1903         # Check input sanity
1904         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1905                 $hostId = @{$msg_hash->{'hostId'}}[0];
1906         } else {
1907                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1908         }
1910         # Unassign all software licenses from a host
1911         my $callobj = {
1912         method  => 'deleteAllSoftwareLicenseUsages',
1913         params  => [ $hostId ],
1914         id  => 1,
1915     };
1916     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1918         # Check Opsi error
1919         my ($res_error, $res_error_str) = &check_opsi_res($res);
1920         if ($res_error){
1921                 # Create error message
1922                 &main::daemon_log("$session_id ERROR: cannot unassign a software license from a host at Opsi server: ".$res_error_str, 1);
1923                 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1924                 return ( &create_xml_string($out_hash) );
1925         }
1927         # Create function result message
1928         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1929         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1930         
1931         my $endTime = Time::HiRes::time;
1932         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1933         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1934         return ( &create_xml_string($out_hash) );
1938 ################################
1939 # @brief Returns the assigned licensePoolId and licenses, how often the product is installed and at which host
1940 # and the number of max and remaining installations for a given OPSI product.
1941 # @param productId Identificator of an OPSI product.
1942 sub opsi_getLicenseInformationForProduct {
1943         my $startTime = Time::HiRes::time;
1944     my ($msg, $msg_hash, $session_id) = @_;
1945     my $header = @{$msg_hash->{'header'}}[0];
1946     my $source = @{$msg_hash->{'source'}}[0];
1947         my $productId;
1948         my $out_hash;
1950         # Check input sanity
1951         if (&_check_xml_tag_is_ok ($msg_hash, 'productId')) {
1952                 $productId = @{$msg_hash->{'productId'}}[0];
1953         } else {
1954                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1955         }
1957         # Fetch infos from Opsi server
1958     my $callobj = {
1959         method  => 'getLicensePoolId',
1960         params  => [ $productId ],
1961         id  => 1,
1962     };
1963     #my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1964     my $res = $opsi_client->call($opsi_url, $callobj);
1966         # Check Opsi error
1967         my ($res_error, $res_error_str) = &check_opsi_res($res);
1968         if ($res_error){
1969                 return &_giveErrorFeedback($msg_hash, "cannot get license pool for product '$productId' : ".$res_error_str, $session_id);
1970         } 
1971         
1972         my $licensePoolId = $res->result;
1974         # Fetch statistic information for given pool ID
1975         $callobj = {
1976                 method  => 'getLicenseStatistics_hash',
1977                 params  => [ ],
1978                 id  => 1,
1979         };
1980         $res = $opsi_client->call($opsi_url, $callobj);
1982         # Check Opsi error
1983         ($res_error, $res_error_str) = &check_opsi_res($res);
1984         if ($res_error){
1985                 # Create error message
1986                 &main::daemon_log("$session_id ERROR: cannot get statistic informations for license pools : ".$res_error_str, 1);
1987                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1988                 return ( &create_xml_string($out_hash) );
1989         }
1991         # Create function result message
1992         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1993         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1994         &add_content2xml_hash($out_hash, "licensePoolId", $licensePoolId);
1995         &add_content2xml_hash($out_hash, "licenses", $res->result->{$licensePoolId}->{'licenses'});
1996         &add_content2xml_hash($out_hash, "usageCount", $res->result->{$licensePoolId}->{'usageCount'});
1997         &add_content2xml_hash($out_hash, "maxInstallations", $res->result->{$licensePoolId}->{'maxInstallations'});
1998         &add_content2xml_hash($out_hash, "remainingInstallations", $res->result->{$licensePoolId}->{'remainingInstallations'});
1999         map(&add_content2xml_hash($out_hash, "usedBy", "$_"), @{ $res->result->{$licensePoolId}->{'usedBy'}});
2001         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
2002         return ( &create_xml_string($out_hash) );
2006 ################################
2007 # @brief Returns licensePoolId, description, a list of productIds, al list of windowsSoftwareIds and a list of licenses for a given licensePoolId. 
2008 # Each license contains softwareLicenseId, maxInstallations, licenseType, licensePoolIds, licenseKeys, hostIds, expirationDate, boundToHost and licenseContractId.
2009 # The licenseContract contains conclusionDate, expirationDate, notes, notificationDate and partner. 
2010 # @param licensePoolId The name of the pool.
2011 sub opsi_getPool {
2012         my $startTime = Time::HiRes::time;
2013     my ($msg, $msg_hash, $session_id) = @_;
2014     my $header = @{$msg_hash->{'header'}}[0];
2015     my $source = @{$msg_hash->{'source'}}[0];
2017         # Check input sanity
2018         my $licensePoolId;
2019         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
2020                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
2021         } else {
2022                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2023         }
2025         # Create hash for the answer
2026         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2027         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2029         # Call Opsi
2030         my ($res, $err) = &_getLicensePool_hash( 'licensePoolId'=> $licensePoolId );
2031         if ($err){
2032                 return &_giveErrorFeedback($msg_hash, "cannot get license pool from Opsi server: ".$res, $session_id);
2033         }
2034         # Add data to outgoing hash
2035         &add_content2xml_hash($out_hash, "licensePoolId", $res->{'licensePoolId'});
2036         &add_content2xml_hash($out_hash, "description", $res->{'description'});
2037         map(&add_content2xml_hash($out_hash, "productIds", "$_"), @{ $res->{'productIds'} });
2038         map(&add_content2xml_hash($out_hash, "windowsSoftwareIds", "$_"), @{ $res->{'windowsSoftwareIds'} });
2041         # Call Opsi two times
2042         my ($usages_res, $usages_err) = &_getSoftwareLicenseUsages_listOfHashes('licensePoolId'=>$licensePoolId);
2043         if ($usages_err){
2044                 return &_giveErrorFeedback($msg_hash, "cannot get software license usage information from Opsi server: ".$usages_res, $session_id);
2045         }
2046         my ($licenses_res, $licenses_err) = &_getSoftwareLicenses_listOfHashes();
2047         if ($licenses_err){
2048                 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server: ".$licenses_res, $session_id);
2049         }
2051         # Add data to outgoing hash
2052         # Parse through all software licenses and select those associated to the pool
2053         my $res_hash = { 'hit'=> [] };
2054         foreach my $license ( @$licenses_res) {
2055                 # Each license hash has a list of licensePoolIds so go through this list and search for matching licensePoolIds
2056                 my $found = 0;
2057                 my @licensePoolIds_list = @{$license->{licensePoolIds}};
2058                 foreach my $lPI ( @licensePoolIds_list) {
2059                         if ($lPI eq $licensePoolId) { $found++ }
2060                 }
2061                 if (not $found ) { next; };
2062                 # Found matching licensePoolId
2063                 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
2064                         'licenseKeys' => {},
2065                         'expirationDate' => [$license->{'expirationDate'}],
2066                         'boundToHost' => [$license->{'boundToHost'}],
2067                         'maxInstallations' => [$license->{'maxInstallations'}],
2068                         'licenseType' => [$license->{'licenseType'}],
2069                         'licenseContractId' => [$license->{'licenseContractId'}],
2070                         'licensePoolIds' => [],
2071                         'hostIds' => [],
2072                         };
2073                 foreach my $licensePoolId (@{ $license->{'licensePoolIds'}}) {
2074                         push( @{$license_hash->{'licensePoolIds'}}, $licensePoolId);
2075                         $license_hash->{licenseKeys}->{$licensePoolId} =  [ $license->{'licenseKeys'}->{$licensePoolId} ];
2076                 }
2077                 foreach my $usage (@$usages_res) {
2078                         # Search for hostIds with matching softwareLicenseId
2079                         if ($license->{'softwareLicenseId'} eq $usage->{'softwareLicenseId'}) {
2080                                 push( @{ $license_hash->{hostIds}}, $usage->{hostId});
2081                         }
2082                 }
2084                 # Each softwareLicenseId has one licenseContractId, fetch contract details for each licenseContractId
2085                 my ($lContract_res, $lContract_err) = &_getLicenseContract_hash('licenseContractId'=>$license->{licenseContractId});
2086                 if ($lContract_err){
2087                         return &_giveErrorFeedback($msg_hash, "cannot get software license contract information from Opsi server: ".$licenses_res, $session_id);
2088                 }
2089                 $license_hash->{$license->{'licenseContractId'}} = [];
2090                 my $licenseContract_hash = { 'conclusionDate' => [$lContract_res->{conclusionDate}],
2091                         'notificationDate' => [$lContract_res->{notificationDate}],
2092                         'notes' => [$lContract_res->{notes}],
2093                         'exirationDate' => [$lContract_res->{expirationDate}],
2094                         'partner' => [$lContract_res->{partner}],
2095                 };
2096                 push( @{$license_hash->{licenseContractData}}, $licenseContract_hash );
2098                 push( @{$res_hash->{hit}}, $license_hash );
2099         }
2100         $out_hash->{licenses} = [$res_hash];
2102         my $endTime = Time::HiRes::time;
2103         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2104         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2105     return ( &create_xml_string($out_hash) );
2109 ################################
2110 # @brief Removes at first the software license from license pool and than deletes the software license. 
2111 # Attention, the software license has to exists otherwise it will lead to an Opsi internal server error.
2112 # @param softwareLicenseId Identificator of a license.
2113 # @param licensePoolId The name of the pool.
2114 sub opsi_removeLicense {
2115         my $startTime = Time::HiRes::time;
2116     my ($msg, $msg_hash, $session_id) = @_;
2117     my $header = @{$msg_hash->{'header'}}[0];
2118     my $source = @{$msg_hash->{'source'}}[0];
2120         # Check input sanity
2121         my $softwareLicenseId;
2122         if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
2123                 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
2124         } else {
2125                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2126         }
2127         my $licensePoolId;
2128         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
2129                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
2130         } else {
2131                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2132         }
2133         
2134         # Call Opsi
2135         my ($res, $err) = &_removeSoftwareLicenseFromLicensePool( 'licensePoolId' => $licensePoolId, 'softwareLicenseId' => $softwareLicenseId );
2136         if ($err){
2137                 return &_giveErrorFeedback($msg_hash, "cannot delete software license from pool: ".$res, $session_id);
2138         }
2140         # Call Opsi
2141         ($res, $err) = &_deleteSoftwareLicense( 'softwareLicenseId'=>$softwareLicenseId );
2142         if ($err){
2143                 return &_giveErrorFeedback($msg_hash, "cannot delete software license from Opsi server: ".$res, $session_id);
2144         }
2146         # Create hash for the answer
2147         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2148         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2149         my $endTime = Time::HiRes::time;
2150         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2151         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2152         return ( &create_xml_string($out_hash) );
2156 ################################
2157 # @brief Return softwareLicenseId, maxInstallations, licenseType, licensePoolIds, licenseContractId, expirationDate, boundToHost and a list of productIds.
2158 # @param hostId Something like client_1.intranet.mydomain.de
2159 sub opsi_getReservedLicenses {
2160         my $startTime = Time::HiRes::time;
2161         my ($msg, $msg_hash, $session_id) = @_;
2162         my $header = @{$msg_hash->{'header'}}[0];
2163         my $source = @{$msg_hash->{'source'}}[0];
2165         # Check input sanity
2166         my $hostId;
2167         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
2168                 $hostId = @{$msg_hash->{'hostId'}}[0];
2169         } else {
2170                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2171         }
2173         # Fetch informations from Opsi server
2174         my ($license_res, $license_err) = &_getSoftwareLicenses_listOfHashes();
2175         if ($license_err){
2176                 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server: ".$license_res, $session_id);
2177         }
2179         # Parse result
2180         my $res_hash = { 'hit'=> [] };
2181         foreach my $license ( @$license_res) {
2182                 if ($license->{boundToHost} ne $hostId) { next; }
2184                 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
2185                         'maxInstallations' => [$license->{'maxInstallations'}],
2186                         'boundToHost' => [$license->{'boundToHost'}],
2187                         'expirationDate' => [$license->{'expirationDate'}],
2188                         'licenseContractId' => [$license->{'licenseContractId'}],
2189                         'licenseType' => [$license->{'licenseType'}],
2190                         'licensePoolIds' => [],
2191                         };
2192                 
2193                 foreach my $licensePoolId (@{$license->{'licensePoolIds'}}) {
2194                         # Fetch information for license pools containing a software license which is bound to given host
2195                         my ($pool_res, $pool_err) = &_getLicensePool_hash( 'licensePoolId'=>$licensePoolId );
2196                         if ($pool_err){
2197                                 return &_giveErrorFeedback($msg_hash, "cannot get license pool from Opsi server: ".$pool_res, $session_id);
2198                         }
2200                         # Add licensePool information to result hash
2201                         push (@{$license_hash->{licensePoolIds}}, $licensePoolId);
2202                         $license_hash->{$licensePoolId} = {'productIds'=>[], 'windowsSoftwareIds'=>[]};
2203                         map (push (@{$license_hash->{$licensePoolId}->{productIds}}, $_), @{$pool_res->{productIds}});
2204                         map (push (@{$license_hash->{$licensePoolId}->{windowsSoftwareIds}}, $_), @{$pool_res->{windowsSoftwareIds}});
2205                 }
2206                 push( @{$res_hash->{hit}}, $license_hash );
2207         }
2208         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2209         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2210         $out_hash->{licenses} = [$res_hash];
2212         my $endTime = Time::HiRes::time;
2213         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2214         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2215     return ( &create_xml_string($out_hash) );
2218 ################################
2219 # @brief Bound the given softwareLicenseId to the given host.
2220 # @param hostId Opsi hostId
2221 # @param softwareLicenseId Identificator of a license (optional).
2222 sub opsi_boundHostToLicense {
2223         my $startTime = Time::HiRes::time;
2224         my ($msg, $msg_hash, $session_id) = @_;
2225         my $header = @{$msg_hash->{'header'}}[0];
2226         my $source = @{$msg_hash->{'source'}}[0];
2228         # Check input sanity
2229         my $hostId;
2230         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
2231                 $hostId = @{$msg_hash->{'hostId'}}[0];
2232         } else {
2233                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2234         }
2235         my $softwareLicenseId;
2236         if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
2237                 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
2238         } else {
2239                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2240         }
2242         # Fetch informations from Opsi server
2243         my ($license_res, $license_err) = &_getSoftwareLicenses_listOfHashes();
2244         if ($license_err){
2245                 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server: ".$license_res, $session_id);
2246         }
2248         # Memorize parameter for given softwareLicenseId
2249         my $licenseContractId;
2250         my $licenseType;
2251         my $maxInstallations;
2252         my $boundToHost;
2253         my $expirationDate = "";
2254         my $found;
2255         foreach my $license (@$license_res) {
2256                 if ($license->{softwareLicenseId} ne $softwareLicenseId) { next; }
2257                 $licenseContractId = $license->{licenseContractId};
2258                 $licenseType = $license->{licenseType};
2259                 $maxInstallations = $license->{maxInstallations};
2260                 $expirationDate = $license->{expirationDate};
2261                 $found++;
2262         }
2264         if (not $found) {
2265                 return &_giveErrorFeedback($msg_hash, "no softwarelicenseId found with name '".$softwareLicenseId."'", $session_id);
2266         }
2268         # Set boundToHost option for a given software license
2269         my ($bound_res, $bound_err) = &_createSoftwareLicense('softwareLicenseId'=>$softwareLicenseId, 
2270                         'licenseContractId' => $licenseContractId, 
2271                         'licenseType' => $licenseType, 
2272                         'maxInstallations' => $maxInstallations, 
2273                         'boundToHost' => $hostId, 
2274                         'expirationDate' => $expirationDate);
2275         if ($bound_err) {
2276                 return &_giveErrorFeedback($msg_hash, "cannot set boundToHost for given softwareLicenseId and hostId: ".$bound_res, $session_id);
2277         }
2279         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2280         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2282         my $endTime = Time::HiRes::time;
2283         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2284         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2285     return ( &create_xml_string($out_hash) );
2288 ################################
2289 # @brief Release a software license formerly bound to a host.
2290 # @param softwareLicenseId Identificator of a license.
2291 sub opsi_unboundHostFromLicense {
2292         # This is really mad! Opsi is not able to unbound a lincense from a host. To provide the functionality for GOsa
2293         # 4 rpc calls to Opsi are necessary. First, fetch all data for the given softwareLicenseId, then all details for the associated
2294         # licenseContractId, then delete the softwareLicense and finally recreate the softwareLicense without the boundToHost option. NASTY!
2295         my $startTime = Time::HiRes::time;
2296         my ($msg, $msg_hash, $session_id) = @_;
2297         my $header = @{$msg_hash->{'header'}}[0];
2298         my $source = @{$msg_hash->{'source'}}[0];
2300         # Check input sanity
2301         my $softwareLicenseId;
2302         if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
2303                 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
2304         } else {
2305                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2306         }
2307         
2308         # Memorize parameter witch are required for this procedure
2309         my $licenseContractId;
2310         my $licenseType;
2311         my $maxInstallations;
2312         my $expirationDate;
2313         my $partner;
2314         my $conclusionDate;
2315         my $notificationDate;
2316         my $notes;
2317         my $licensePoolId;
2318         my $licenseKey;
2320         # Fetch license informations from Opsi server
2321         my ($license_res, $license_err) = &_getSoftwareLicenses_listOfHashes();
2322         if ($license_err){
2323                 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server, required to unbound license from host: ".$license_res, $session_id);
2324         }
2325         my $found = 0;
2326         foreach my $license (@$license_res) {
2327                 if (($found > 0) || ($license->{softwareLicenseId} ne $softwareLicenseId)) { next; }
2328                 $licenseContractId = $license->{licenseContractId};
2329                 $licenseType = $license->{licenseType};
2330                 $maxInstallations = $license->{maxInstallations};
2331                 $expirationDate = $license->{expirationDate};
2332                 $licensePoolId = @{$license->{licensePoolIds}}[0];
2333                 $licenseKey = $license->{licenseKeys}->{$licensePoolId};
2334                 $found++;
2335         }
2336         
2337         # Fetch contract informations from Opsi server
2338         my ($contract_res, $contract_err) = &_getLicenseContract_hash('licenseContractId'=>$licenseContractId);
2339         if ($contract_err){
2340                 return &_giveErrorFeedback($msg_hash, "cannot get contract license information from Opsi server, required to unbound license from host: ".$license_res, $session_id);
2341         }
2342         $partner = $contract_res->{partner};
2343         $conclusionDate = $contract_res->{conclusionDate};
2344         $notificationDate = $contract_res->{notificationDate};
2345         $expirationDate = $contract_res->{expirationDate};
2346         $notes = $contract_res->{notes};
2348         # Delete software license
2349         my ($res, $err) = &_deleteSoftwareLicense( 'softwareLicenseId' => $softwareLicenseId, 'removeFromPools'=> "true" );
2350         if ($err) {
2351                 return &_giveErrorFeedback($msg_hash, "cannot delet license from Opsi server, required to unbound license from host : ".$res, $session_id);
2352         }
2354         # Recreate software license without boundToHost
2355         ($res, $err) = &_createLicenseContract( 'licenseContractId' => $licenseContractId, 'partner' => $partner, 'conclusionDate' => $conclusionDate, 
2356                         'notificationDate' => $notificationDate, 'expirationDate' => $expirationDate, 'notes' => $notes );
2357         if ($err) {
2358                 return &_giveErrorFeedback($msg_hash, "cannot create license contract at Opsi server, required to unbound license from host : ".$res, $session_id);
2359         }
2360         ($res, $err) = &_createSoftwareLicense( 'softwareLicenseId' => $softwareLicenseId, 'licenseContractId' => $licenseContractId, 'licenseType' => $licenseType, 
2361                         'maxInstallations' => $maxInstallations, 'boundToHost' => "", 'expirationDate' => $expirationDate       );
2362         if ($err) {
2363                 return &_giveErrorFeedback($msg_hash, "cannot create software license at Opsi server, required to unbound license from host : ".$res, $session_id);
2364         }
2365         ($res, $err) = &_addSoftwareLicenseToLicensePool( 'softwareLicenseId' => $softwareLicenseId, 'licensePoolId' => $licensePoolId, 'licenseKey' => $licenseKey );
2366         if ($err) {
2367                 return &_giveErrorFeedback($msg_hash, "cannot add software license to license pool at Opsi server, required to unbound license from host : ".$res, $session_id);
2368         }
2370         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2371         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2373         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
2374     return ( &create_xml_string($out_hash) );
2377 ################################
2378 # @brief Returns a list of licenses with softwaerLicenseId, maxInstallations, boundToHost, expirationDate, licenseContractId, licenseType, a list of licensePoolIds with associated licenseKeys
2379 sub opsi_getAllSoftwareLicenses {
2380         my $startTime = Time::HiRes::time;
2381         my ($msg, $msg_hash, $session_id) = @_;
2382         my $header = @{$msg_hash->{'header'}}[0];
2383         my $source = @{$msg_hash->{'source'}}[0];
2385         my ($res, $err) = &_getSoftwareLicenses_listOfHashes();
2386         if ($err) {
2387                 return &_giveErrorFeedback($msg_hash, "cannot fetch software licenses from Opsi server : ".$res, $session_id);
2388         }
2390         # Parse result
2391         my $res_hash = { 'hit'=> [] };
2392         foreach my $license ( @$res) {
2393                 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
2394                         'maxInstallations' => [$license->{'maxInstallations'}],
2395                         'boundToHost' => [$license->{'boundToHost'}],
2396                         'expirationDate' => [$license->{'expirationDate'}],
2397                         'licenseContractId' => [$license->{'licenseContractId'}],
2398                         'licenseType' => [$license->{'licenseType'}],
2399                         'licensePoolIds' => [],
2400                         'licenseKeys'=> {}
2401                         };
2402                 foreach my $licensePoolId (@{$license->{'licensePoolIds'}}) {
2403                         push( @{$license_hash->{'licensePoolIds'}}, $licensePoolId);
2404                         $license_hash->{licenseKeys}->{$licensePoolId} =  [ $license->{'licenseKeys'}->{$licensePoolId} ];
2405                 }
2406                 push( @{$res_hash->{hit}}, $license_hash );
2407         }
2408         
2409         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2410         $out_hash->{licenses} = [$res_hash];
2411         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2413         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
2414     return ( &create_xml_string($out_hash) );
2417 sub opsi_test {
2418     my ($msg, $msg_hash, $session_id) = @_;
2419     my $header = @{$msg_hash->{'header'}}[0];
2420     my $source = @{$msg_hash->{'source'}}[0];
2421         my $pram1 = @{$msg_hash->{'productId'}}[0];
2423 print STDERR Dumper $pram1;
2425         # Fetch infos from Opsi server
2426     my $callobj = {
2427         method  => 'getLicensePoolId',
2428         params  => [ $pram1 ],
2429         id  => 1,
2430     };
2431     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
2433         print STDERR Dumper $res;
2434         return ();
2438 # ----------------------------------------------------------------------------
2439 #  internal methods handling the comunication with Opsi
2440 # ----------------------------------------------------------------------------
2442 ################################
2443 # @brief Checks if there is a specified tag and if the the tag has a content.
2444 sub _check_xml_tag_is_ok {
2445         my ($msg_hash,$tag) = @_;
2446         if (not defined $msg_hash->{$tag}) {
2447                 $_ = "message contains no tag '$tag'";
2448                 return 0;
2449         }
2450         if (ref @{$msg_hash->{$tag}}[0] eq 'HASH') {
2451                 $_ = "message tag '$tag' has no content";
2452                 return  0;
2453         }
2454         return 1;
2457 ################################
2458 # @brief Writes the log line and returns the error message for GOsa.
2459 sub _giveErrorFeedback {
2460         my ($msg_hash, $err_string, $session_id) = @_;
2461         &main::daemon_log("$session_id ERROR: $err_string", 1);
2462         my $out_hash = &main::create_xml_hash("error", $main::server_address, @{$msg_hash->{source}}[0], $err_string);
2463     if (exists $msg_hash->{forward_to_gosa}) {
2464         &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]);
2465     }
2466         return ( &create_xml_string($out_hash) );
2470 ################################
2471 # @brief Perform the call to the Opsi server and measure the time for the call
2472 sub _callOpsi {
2473         my %arg = ('method'=>undef, 'params'=>[], 'id'=>1, @_);
2475         my $callObject = {
2476                 method => $arg{method},
2477                 params => $arg{params},
2478                 id => $arg{id},
2479         };
2481         my $startTime = Time::HiRes::time;
2482         my $opsiResult = $opsi_client->call($opsi_url, $callObject);
2483         my $endTime = Time::HiRes::time;
2484         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2486         &main::daemon_log("0 DEBUG: time to process opsi call '$arg{method}' : $elapsedTime seconds", 1034); 
2488         return $opsiResult;
2491 sub _getLicensePool_hash {
2492         my %arg = ( 'licensePoolId' => undef, @_ );
2494         if (not defined $arg{licensePoolId} ) { 
2495                 return ("function requires licensePoolId as parameter", 1);
2496         }
2498         my $res = &_callOpsi( method  => 'getLicensePool_hash', params =>[$arg{licensePoolId}], id  => 1 );
2499         my ($res_error, $res_error_str) = &check_opsi_res($res);
2500         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2502         return ($res->result, 0);
2505 sub _getSoftwareLicenses_listOfHashes {
2506         
2507         my $res = &_callOpsi( method  => 'getSoftwareLicenses_listOfHashes' );
2508         my ($res_error, $res_error_str) = &check_opsi_res($res);
2509         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2511         return ($res->result, 0);
2514 sub _getSoftwareLicenseUsages_listOfHashes {
2515         my %arg = ( 'hostId' => "", 'licensePoolId' => "", @_ );
2517         my $res = &_callOpsi( method=>'getSoftwareLicenseUsages_listOfHashes', params=>[ $arg{hostId}, $arg{licensePoolId} ] );
2518         my ($res_error, $res_error_str) = &check_opsi_res($res);
2519         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2521         return ($res->result, 0);
2524 sub _removeSoftwareLicenseFromLicensePool {
2525         my %arg = ( 'softwareLicenseId' => undef, 'licensePoolId' => undef, @_ );
2527         if (not defined $arg{softwareLicenseId} ) { 
2528                 return ("function requires softwareLicenseId as parameter", 1);
2529                 }
2530                 if (not defined $arg{licensePoolId} ) { 
2531                 return ("function requires licensePoolId as parameter", 1);
2532         }
2534         my $res = &_callOpsi( method=>'removeSoftwareLicenseFromLicensePool', params=>[ $arg{softwareLicenseId}, $arg{licensePoolId} ] );
2535         my ($res_error, $res_error_str) = &check_opsi_res($res);
2536         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2538         return ($res->result, 0);
2541 sub _deleteSoftwareLicense {
2542         my %arg = ( 'softwareLicenseId' => undef, 'removeFromPools' => "false", @_ );
2544         if (not defined $arg{softwareLicenseId} ) { 
2545                 return ("function requires softwareLicenseId as parameter", 1);
2546         }
2547         my $removeFromPools = "";
2548         if ((defined $arg{removeFromPools}) && ($arg{removeFromPools} eq "true")) { 
2549                 $removeFromPools = "removeFromPools";
2550         }
2552         my $res = &_callOpsi( method=>'deleteSoftwareLicense', params=>[ $arg{softwareLicenseId}, $removeFromPools ] );
2553         my ($res_error, $res_error_str) = &check_opsi_res($res);
2554         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2556         return ($res->result, 0);
2559 sub _getLicensePoolId {
2560         my %arg = ( 'productId' => undef, @_ );
2561         
2562         if (not defined $arg{productId} ) {
2563                 return ("function requires productId as parameter", 1);
2564         }
2566     my $res = &_callOpsi( method  => 'getLicensePoolId', params  => [ $arg{productId} ] );
2567         my ($res_error, $res_error_str) = &check_opsi_res($res);
2568         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2570         return ($res->result, 0);
2573 sub _getLicenseContract_hash {
2574         my %arg = ( 'licenseContractId' => undef, @_ );
2575         
2576         if (not defined $arg{licenseContractId} ) {
2577                 return ("function requires licenseContractId as parameter", 1);
2578         }
2580     my $res = &_callOpsi( method  => 'getLicenseContract_hash', params  => [ $arg{licenseContractId} ] );
2581         my ($res_error, $res_error_str) = &check_opsi_res($res);
2582         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2584         return ($res->result, 0);
2587 sub _createLicenseContract {
2588         my %arg = (
2589                         'licenseContractId' => undef,
2590                         'partner' => undef,
2591                         'conclusionDate' => undef,
2592                         'notificationDate' => undef,
2593                         'expirationDate' => undef,
2594                         'notes' => undef,
2595                         @_ );
2597         my $res = &_callOpsi( method  => 'createLicenseContract', 
2598                         params  => [ $arg{licenseContractId}, $arg{partner}, $arg{conclusionDate}, $arg{notificationDate}, $arg{expirationDate}, $arg{notes} ],
2599                         );
2600         my ($res_error, $res_error_str) = &check_opsi_res($res);
2601         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2603         return ($res->result, 0);
2606 sub _createSoftwareLicense {
2607         my %arg = (
2608                         'softwareLicenseId' => undef,
2609                         'licenseContractId' => undef,
2610                         'licenseType' => undef,
2611                         'maxInstallations' => undef,
2612                         'boundToHost' => undef,
2613                         'expirationDate' => undef,
2614                         @_ );
2616     my $res = &_callOpsi( method  => 'createSoftwareLicense',
2617         params  => [ $arg{softwareLicenseId}, $arg{licenseContractId}, $arg{licenseType}, $arg{maxInstallations}, $arg{boundToHost}, $arg{expirationDate} ],
2618                 );
2619         my ($res_error, $res_error_str) = &check_opsi_res($res);
2620         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2622         return ($res->result, 0);
2625 sub _addSoftwareLicenseToLicensePool {
2626         my %arg = (
2627             'softwareLicenseId' => undef,
2628             'licensePoolId' => undef,
2629             'licenseKey' => undef,
2630             @_ );
2632         if (not defined $arg{softwareLicenseId} ) {
2633                 return ("function requires softwareLicenseId as parameter", 1);
2634         }
2635         if (not defined $arg{licensePoolId} ) {
2636                 return ("function requires licensePoolId as parameter", 1);
2637         }
2639         my $res = &_callOpsi( method  => 'addSoftwareLicenseToLicensePool', params  => [ $arg{softwareLicenseId}, $arg{licensePoolId}, $arg{licenseKey} ] );
2640         my ($res_error, $res_error_str) = &check_opsi_res($res);
2641         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2643         return ($res->result, 0);
2646 sub _getProductStates_hash {
2647         my %arg = (     'hostId' => undef, @_ );
2649         if (not defined $arg{hostId} ) {
2650                 return ("function requires hostId as parameter", 1);
2651         }
2653         my $res = &_callOpsi( method => 'getProductStates_hash', params => [$arg{hostId}]);
2654         my ($res_error, $res_error_str) = &check_opsi_res($res);
2655         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2657         return ($res->result, 0);
2660 1;