Code

Removed usePrototype flag, its activated always now.
[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;
8 use strict;
9 use warnings;
11 use Exporter;
12 use UNIVERSAL 'isa';
13 use GOSA::GosaSupportDaemon;
14 use Data::Dumper;
15 use XML::Quote qw(:all);
17 our @ISA = qw(Exporter);
19 my @events = (
20     "get_events",
21     "opsi_install_client",
22     "opsi_get_netboot_products",  
23     "opsi_get_local_products",
24     "opsi_get_client_hardware",
25     "opsi_get_client_software",
26     "opsi_get_product_properties",
27     "opsi_get_full_product_host_information",
28     "opsi_set_product_properties",
29     "opsi_list_clients",
30     "opsi_del_client",
31     "opsi_add_client",
32     "opsi_modify_client",
33     "opsi_add_product_to_client",
34     "opsi_del_product_from_client",
35     "opsi_createLicensePool",
36     "opsi_deleteLicensePool",
37     "opsi_createLicense",
38     "opsi_assignSoftwareLicenseToHost",
39     "opsi_unassignSoftwareLicenseFromHost",
40     "opsi_unassignAllSoftwareLicensesFromHost",
41     "opsi_getSoftwareLicense_hash",
42     "opsi_getLicensePool_hash",
43     "opsi_getSoftwareLicenseUsages",
44     "opsi_getSoftwareLicenseUsagesForProductId",
45     "opsi_getLicensePools_listOfHashes",
46     "opsi_getLicenseInformationForProduct",
47     "opsi_getPool",
48     "opsi_getAllSoftwareLicenses",
49     "opsi_removeLicense",
50     "opsi_getReservedLicenses",
51     "opsi_boundHostToLicense",
52     "opsi_unboundHostFromLicense",
53     "opsi_test",
54    );
56 our @EXPORT = @events;
59 BEGIN {}
61 END {}
63 # ----------------------------------------------------------------------------
64 #                          D E C L A R A T I O N S
65 # ----------------------------------------------------------------------------
67 my $licenseTyp_hash = { 'OEM'=>'', 'VOLUME'=>'', 'RETAIL'=>''};
68 my ($opsi_enabled, $opsi_server, $opsi_admin, $opsi_password, $opsi_url, $opsi_client);
69 my %cfg_defaults = (
70                 "Opsi" => {
71                 "enabled"  => [\$opsi_enabled, "false"],
72                 "server"   => [\$opsi_server, "localhost"],
73                 "admin"    => [\$opsi_admin, "opsi-admin"],
74                 "password" => [\$opsi_password, "secret"],
75                 },
76 );
77 &read_configfile($main::cfg_file, %cfg_defaults);
78 if ($opsi_enabled eq "true") {
79         use JSON::RPC::Client;
80         use XML::Quote qw(:all);
81         use Time::HiRes qw( time );
82         $opsi_url= "https://".$opsi_admin.":".$opsi_password."@".$opsi_server.":4447/rpc";
83         $opsi_client = new JSON::RPC::Client;
85         # Check version dependencies
86         eval { &myXmlHashToString(); };
87         if ($@ ) {
88                 die "\nThe version of the Opsi plugin you want to use requires a newer version of GosaSupportDaemon. Please update your GOsa-SI or deactivate the Opsi plugin.\n";
89         }
90 }
92 # ----------------------------------------------------------------------------
93 #   external methods handling the comunication with GOsa/GOsa-si
94 # ----------------------------------------------------------------------------
96 ################################
97 # @brief A function returning a list of functions which are exported by importing the module.
98 # @return List of all provided functions
99 sub get_events {
100     return \@events;
103 ################################
104 # @brief Adds an Opsi product to an Opsi client.
105 # @param msg - STRING - xml message with tags hostId and productId
106 # @param msg_hash - HASHREF - message information parsed into a hash
107 # @param session_id - INTEGER - POE session id of the processing of this message
108 # @return out_msg - STRING - feedback to GOsa in success and error case
109 sub opsi_add_product_to_client {
110         my $startTime = Time::HiRes::time;
111     my ($msg, $msg_hash, $session_id) = @_;
112     my $header = @{$msg_hash->{'header'}}[0];
113     my $source = @{$msg_hash->{'source'}}[0];
114     my $target = @{$msg_hash->{'target'}}[0];
115     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
117     # Build return message
118     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
119     if (defined $forward_to_gosa) {
120         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
121     }
123     # Sanity check of needed parameter
124     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
125                 return &_giveErrorFeedback($msg_hash, "no hostId specified or hostId tag invalid", $session_id);
126     }
127     if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
128                 return &_giveErrorFeedback($msg_hash, "no productId specified or productId tag invalid", $session_id);
129     }
131         # Get hostId
132         my $hostId = @{$msg_hash->{'hostId'}}[0];
133         &add_content2xml_hash($out_hash, "hostId", $hostId);
135         # Get productID
136         my $productId = @{$msg_hash->{'productId'}}[0];
137         &add_content2xml_hash($out_hash, "productId", $productId);
139         # Do an action request for all these -> "setup".
140         my $callobj = {
141                 method  => 'setProductActionRequest',
142                 params  => [ $productId, $hostId, "setup" ],
143                 id  => 1, }; 
144         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
146         if (&check_opsi_res($res)) { return ( (caller(0))[3]." : ".$_, 1 ); };
148         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
149     return ( &create_xml_string($out_hash) );
152 ################################
153 # @brief Deletes an Opsi-product from an Opsi-client. 
154 # @param msg - STRING - xml message with tags hostId and productId
155 # @param msg_hash - HASHREF - message information parsed into a hash
156 # @param session_id - INTEGER - POE session id of the processing of this message
157 # @return out_msg - STRING - feedback to GOsa in success and error case
158 sub opsi_del_product_from_client {
159         my $startTime = Time::HiRes::time;
160     my ($msg, $msg_hash, $session_id) = @_;
161     my $header = @{$msg_hash->{'header'}}[0];
162     my $source = @{$msg_hash->{'source'}}[0];
163     my $target = @{$msg_hash->{'target'}}[0];
164     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
165     my ($hostId, $productId);
166     my $error = 0;
167     my ($sres, $sres_err, $sres_err_string);
169     # Build return message
170     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
171     if (defined $forward_to_gosa) {
172         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
173     }
175     # Sanity check of needed parameter
176     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
177         $error++;
178         &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
179         &add_content2xml_hash($out_hash, "error", "hostId");
180         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
182     }
183     if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
184         $error++;
185         &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
186         &add_content2xml_hash($out_hash, "error", "productId");
187         &main::daemon_log("$session_id ERROR: no productId specified or procutId tag invalid: $msg", 1); 
188     }
190     # All parameter available
191     if (not $error) {
192         # Get hostId
193         $hostId = @{$msg_hash->{'hostId'}}[0];
194         &add_content2xml_hash($out_hash, "hostId", $hostId);
196         # Get productID
197         $productId = @{$msg_hash->{'productId'}}[0];
198         &add_content2xml_hash($out_hash, "productId", $productId);
200         # Check to get product action list 
201         my $callobj = {
202             method  => 'getPossibleProductActions_list',
203             params  => [ $productId ],
204             id  => 1, };
205         $sres = $main::opsi_client->call($main::opsi_url, $callobj);
206         ($sres_err, $sres_err_string) = &check_opsi_res($sres);
207         if ($sres_err){
208             &main::daemon_log("$session_id ERROR: cannot get product action list: ".$sres_err_string, 1);
209             &add_content2xml_hash($out_hash, "error", $sres_err_string);
210             $error++;
211         }
212     }
214     # Check action uninstall of product
215     if (not $error) {
216         my $uninst_possible= 0;
217         foreach my $r (@{$sres->result}) {
218             if ($r eq 'uninstall') {
219                 $uninst_possible= 1;
220             }
221         }
222         if (!$uninst_possible){
223             &main::daemon_log("$session_id ERROR: cannot uninstall product '$productId', product do not has the action 'uninstall'", 1);
224             &add_content2xml_hash($out_hash, "error", "cannot uninstall product '$productId', product do not has the action 'uninstall'");
225             $error++;
226         }
227     }
229     # Set product state to "none"
230     # Do an action request for all these -> "setup".
231     if (not $error) {
232         my $callobj = {
233             method  => 'setProductActionRequest',
234             params  => [ $productId, $hostId, "none" ],
235             id  => 1, 
236         }; 
237         $sres = $main::opsi_client->call($main::opsi_url, $callobj);
238         ($sres_err, $sres_err_string) = &check_opsi_res($sres);
239         if ($sres_err){
240             &main::daemon_log("$session_id ERROR: cannot delete product: ".$sres_err_string, 1);
241             &add_content2xml_hash($out_hash, "error", $sres_err_string);
242         }
243     }
245     # Return message
246         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
247     return ( &create_xml_string($out_hash) );
250 ################################
251 # @brief Adds an Opsi client to Opsi.
252 # @param msg - STRING - xml message with tags hostId and macaddress
253 # @param msg_hash - HASHREF - message information parsed into a hash
254 # @param session_id - INTEGER - POE session id of the processing of this message
255 # @return out_msg - STRING - feedback to GOsa in success and error case
256 sub opsi_add_client {
257         my $startTime = Time::HiRes::time;
258     my ($msg, $msg_hash, $session_id) = @_;
259     my $header = @{$msg_hash->{'header'}}[0];
260     my $source = @{$msg_hash->{'source'}}[0];
261     my $target = @{$msg_hash->{'target'}}[0];
262     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
263     my ($hostId, $mac);
264     my $error = 0;
265     my ($sres, $sres_err, $sres_err_string);
267     # Build return message with twisted target and source
268     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
269     if (defined $forward_to_gosa) {
270         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
271     }
273     # Sanity check of needed parameter
274     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
275         $error++;
276         &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
277         &add_content2xml_hash($out_hash, "error", "hostId");
278         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
279     }
280     if ((not exists $msg_hash->{'macaddress'}) || (@{$msg_hash->{'macaddress'}} != 1) || (@{$msg_hash->{'macaddress'}}[0] eq ref 'HASH'))  {
281         $error++;
282         &add_content2xml_hash($out_hash, "error_string", "no macaddress specified or macaddress tag invalid");
283         &add_content2xml_hash($out_hash, "error", "macaddress");
284         &main::daemon_log("$session_id ERROR: no macaddress specified or macaddress tag invalid: $msg", 1); 
285     }
287     if (not $error) {
288         # Get hostId
289         $hostId = @{$msg_hash->{'hostId'}}[0];
290         &add_content2xml_hash($out_hash, "hostId", $hostId);
292         # Get macaddress
293         $mac = @{$msg_hash->{'macaddress'}}[0];
294         &add_content2xml_hash($out_hash, "macaddress", $mac);
296         my $name= $hostId;
297         $name=~ s/^([^.]+).*$/$1/;
298         my $domain= $hostId;
299         $domain=~ s/^[^.]+\.(.*)$/$1/;
300         my ($description, $notes, $ip);
302         if (defined @{$msg_hash->{'description'}}[0]){
303             $description = @{$msg_hash->{'description'}}[0];
304         }
305         if (defined @{$msg_hash->{'notes'}}[0]){
306             $notes = @{$msg_hash->{'notes'}}[0];
307         }
308         if (defined @{$msg_hash->{'ip'}}[0]){
309             $ip = @{$msg_hash->{'ip'}}[0];
310         }
312         my $callobj;
313         $callobj = {
314             method  => 'createClient',
315             params  => [ $name, $domain, $description, $notes, $ip, $mac ],
316             id  => 1,
317         };
319         $sres = $main::opsi_client->call($main::opsi_url, $callobj);
320         ($sres_err, $sres_err_string) = &check_opsi_res($sres);
321         if ($sres_err){
322             &main::daemon_log("$session_id ERROR: cannot create client: ".$sres_err_string, 1);
323             &add_content2xml_hash($out_hash, "error", $sres_err_string);
324         } else {
325             &main::daemon_log("$session_id INFO: add opsi client '$hostId' with mac '$mac'", 5); 
326         }
327     }
329     # Return message
330         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
331     return ( &create_xml_string($out_hash) );
334 ################################
335 # @brief Modifies the parameters description, mac or notes for an Opsi client if the corresponding message tags are given.
336 # @param msg - STRING - xml message with tag hostId and optional description, mac or notes
337 # @param msg_hash - HASHREF - message information parsed into a hash
338 # @param session_id - INTEGER - POE session id of the processing of this message    
339 # @return out_msg - STRING - feedback to GOsa in success and error case
340 sub opsi_modify_client {
341         my $startTime = Time::HiRes::time;
342     my ($msg, $msg_hash, $session_id) = @_;
343     my $header = @{$msg_hash->{'header'}}[0];
344     my $source = @{$msg_hash->{'source'}}[0];
345     my $target = @{$msg_hash->{'target'}}[0];
346     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
347     my $hostId;
348     my $error = 0;
349     my ($sres, $sres_err, $sres_err_string);
351     # Build return message with twisted target and source
352     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
353     if (defined $forward_to_gosa) {
354         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
355     }
357     # Sanity check of needed parameter
358     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
359         $error++;
360         &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
361         &add_content2xml_hash($out_hash, "error", "hostId");
362         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
363     }
365     if (not $error) {
366         # Get hostId
367         $hostId = @{$msg_hash->{'hostId'}}[0];
368         &add_content2xml_hash($out_hash, "hostId", $hostId);
369         my $name= $hostId;
370         $name=~ s/^([^.]+).*$/$1/;
371         my $domain= $hostId;
372         $domain=~ s/^[^.]+(.*)$/$1/;
374         # Modify description, notes or mac if defined
375         my ($description, $notes, $mac);
376         my $callobj;
377         if ((exists $msg_hash->{'description'}) && (@{$msg_hash->{'description'}} == 1) ){
378             $description = @{$msg_hash->{'description'}}[0];
379             $callobj = {
380                 method  => 'setHostDescription',
381                 params  => [ $hostId, $description ],
382                 id  => 1,
383             };
384             my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
385             my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
386             if ($sres_err){
387                 &main::daemon_log("ERROR: cannot set description: ".$sres_err_string, 1);
388                 &add_content2xml_hash($out_hash, "error", $sres_err_string);
389             }
390         }
391         if ((exists $msg_hash->{'notes'}) && (@{$msg_hash->{'notes'}} == 1)) {
392             $notes = @{$msg_hash->{'notes'}}[0];
393             $callobj = {
394                 method  => 'setHostNotes',
395                 params  => [ $hostId, $notes ],
396                 id  => 1,
397             };
398             my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
399             my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
400             if ($sres_err){
401                 &main::daemon_log("ERROR: cannot set notes: ".$sres_err_string, 1);
402                 &add_content2xml_hash($out_hash, "error", $sres_err_string);
403             }
404         }
405         if ((exists $msg_hash->{'mac'}) && (@{$msg_hash->{'mac'}} == 1)){
406             $mac = @{$msg_hash->{'mac'}}[0];
407             $callobj = {
408                 method  => 'setMacAddress',
409                 params  => [ $hostId, $mac ],
410                 id  => 1,
411             };
412             my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
413             my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
414             if ($sres_err){
415                 &main::daemon_log("ERROR: cannot set mac address: ".$sres_err_string, 1);
416                 &add_content2xml_hash($out_hash, "error", $sres_err_string);
417             }
418         }
419     }
421     # Return message
422         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
423     return ( &create_xml_string($out_hash) );
425  
426 ################################
427 # @brief Get netboot products for specific host.
428 # @param msg - STRING - xml message with tag hostId
429 # @param msg_hash - HASHREF - message information parsed into a hash
430 # @param session_id - INTEGER - POE session id of the processing of this message
431 # @return out_msg - STRING - feedback to GOsa in success and error case
432 sub opsi_get_netboot_products {
433     my $startTime = Time::HiRes::time;
434     my ($msg, $msg_hash, $session_id) = @_;
435     my $header = @{$msg_hash->{'header'}}[0];
436     my $source = @{$msg_hash->{'source'}}[0];
437     my $target = @{$msg_hash->{'target'}}[0];
438     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
439     my $hostId;
441     # Build return message with twisted target and source
442     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
443     if (defined $forward_to_gosa) {
444         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
445     }
446     &add_content2xml_hash($out_hash, "xxx", "");
448     # Get hostId if defined
449     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1))  {
450         $hostId = @{$msg_hash->{'hostId'}}[0];
451         &add_content2xml_hash($out_hash, "hostId", $hostId);
452     }
454     # Move to XML string
455     my $xml_msg= &create_xml_string($out_hash);
457     my $callobj;
458     # Check if we need to get host or global information
459     if (defined $hostId){
460       $callobj = {
461           method  => 'getProductHostInformation_list',
462           params  => [ $hostId, undef, 'netboot'],
463           id  => 1,
464       };
466       my $res = $main::opsi_client->call($main::opsi_url, $callobj);
467       if (not &check_opsi_res($res)){
468           foreach my $product (@{$res->result}){
469                my $replace= "<item><productId>".xml_quote($product->{'productId'})."<\/productId><name>".xml_quote($product->{'name'})."<\/name><description>".xml_quote($product->{'description'})."<\/description><state>".xml_quote($product->{'installationStatus'})."</state><action>".xml_quote($product->{'actionRequest'})."</action><\/item><xxx><\/xxx>";
470                $xml_msg=~ s/<xxx><\/xxx>/\n$replace/;
471           }
472       }
474     } else {
476       # For hosts, only return the products that are or get installed
477       $callobj = {
478           method  => 'getProductInformation_list',
479           params  => [ undef, 'netboot' ],
480           id  => 1,
481       };
483       my $res = $main::opsi_client->call($main::opsi_url, $callobj);
484       if (not &check_opsi_res($res)){
485           foreach my $product (@{$res->result}) {
486                my $replace= "<item><productId>".xml_quote($product->{'productId'})."<\/productId><name>".xml_quote($product->{'name'})."<\/name><description>".xml_quote($product->{'description'})."<\/description><\/item><xxx><\/xxx>";
487                $xml_msg=~ s/<xxx><\/xxx>/\n$replace/;
488           }
489       }
490     }
492     $xml_msg=~ s/<xxx><\/xxx>//;
494     # Retrun Message
495         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
496     return ( $xml_msg );
499 ################################   
500 # @brief Get product properties for a product and a specific host or gobally for a product.
501 # @param msg - STRING - xml message with tags productId and optional hostId
502 # @param msg_hash - HASHREF - message information parsed into a hash
503 # @param session_id - INTEGER - POE session id of the processing of this message
504 # @return out_msg - STRING - feedback to GOsa in success and error case
505 sub opsi_get_product_properties {
506         my $startTime = Time::HiRes::time;
507     my ($msg, $msg_hash, $session_id) = @_;
508     my $header = @{$msg_hash->{'header'}}[0];
509     my $source = @{$msg_hash->{'source'}}[0];
510     my $target = @{$msg_hash->{'target'}}[0];
511     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
512     my ($hostId, $productId);
513     my $xml_msg;
515     # Build return message with twisted target and source
516     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
517     if (defined $forward_to_gosa) {
518         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
519     }
521     # Sanity check of needed parameter
522     if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH'))  {
523         &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
524         &add_content2xml_hash($out_hash, "error", "productId");
525         &main::daemon_log("$session_id ERROR: no productId specified or productId tag invalid: $msg", 1); 
527         # Return message
528         return ( &create_xml_string($out_hash) );
529     }
531     # Get productid
532     $productId = @{$msg_hash->{'productId'}}[0];
533     &add_content2xml_hash($out_hash, "producId", "$productId");
535     # Get hostId if defined
536     if (defined @{$msg_hash->{'hostId'}}[0]){
537       $hostId = @{$msg_hash->{'hostId'}}[0];
538       &add_content2xml_hash($out_hash, "hostId", $hostId);
539     }
541     # Load actions
542     my $callobj = {
543       method  => 'getPossibleProductActions_list',
544       params  => [ $productId ],
545       id  => 1,
546     };
547     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
548     if (not &check_opsi_res($res)){
549       foreach my $action (@{$res->result}){
550         &add_content2xml_hash($out_hash, "action", $action);
551       }
552     }
554     # Add place holder
555     &add_content2xml_hash($out_hash, "xxx", "");
557     # Move to XML string
558     $xml_msg= &create_xml_string($out_hash);
560     # JSON Query
561     if (defined $hostId){
562       $callobj = {
563           method  => 'getProductProperties_hash',
564           params  => [ $productId, $hostId ],
565           id  => 1,
566       };
567     } else {
568       $callobj = {
569           method  => 'getProductProperties_hash',
570           params  => [ $productId ],
571           id  => 1,
572       };
573     }
574     $res = $main::opsi_client->call($main::opsi_url, $callobj);
576     # JSON Query 2
577     $callobj = {
578       method  => 'getProductPropertyDefinitions_listOfHashes',
579       params  => [ $productId ],
580       id  => 1,
581     };
583     # Assemble options
584     my $res2 = $main::opsi_client->call($main::opsi_url, $callobj);
585     my $values = {};
586     my $descriptions = {};
587     if (not &check_opsi_res($res2)){
588         my $r= $res2->result;
590           foreach my $entr (@$r){
591             # Unroll values
592             my $cnv;
593             if (UNIVERSAL::isa( $entr->{'values'}, "ARRAY" )){
594               foreach my $v (@{$entr->{'values'}}){
595                 $cnv.= "<value>$v</value>";
596               }
597             } else {
598               $cnv= $entr->{'values'};
599             }
600             $values->{$entr->{'name'}}= $cnv;
601             $descriptions->{$entr->{'name'}}= "<description>".$entr->{'description'}."</description>";
602           }
603     }
605     if (not &check_opsi_res($res)){
606         my $r= $res->result;
607         foreach my $key (keys %{$r}) {
608             my $item= "\n<item>";
609             my $value= $r->{$key};
610             my $dsc= "";
611             my $vals= "";
612             if (defined $descriptions->{$key}){
613               $dsc= $descriptions->{$key};
614             }
615             if (defined $values->{$key}){
616               $vals= $values->{$key};
617             }
618             $item.= "<$key>$dsc<current>".xml_quote($value)."</current>$vals</$key>";
619             $item.= "</item>";
620             $xml_msg=~ s/<xxx><\/xxx>/$item<xxx><\/xxx>/;
621         }
622     }
624     $xml_msg=~ s/<xxx><\/xxx>//;
626     # Return message
627         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
628     return ( $xml_msg );
631 ################################   
632 # @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.
633 # @param msg - STRING - xml message with tags productId, action, state and optional hostId, action and state
634 # @param msg_hash - HASHREF - message information parsed into a hash
635 # @param session_id - INTEGER - POE session id of the processing of this message
636 # @return out_msg - STRING - feedback to GOsa in success and error case
637 sub opsi_set_product_properties {
638         my $startTime = Time::HiRes::time;
639     my ($msg, $msg_hash, $session_id) = @_;
640     my $header = @{$msg_hash->{'header'}}[0];
641     my $source = @{$msg_hash->{'source'}}[0];
642     my $target = @{$msg_hash->{'target'}}[0];
643     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
644     my ($productId, $hostId);
646     # Build return message with twisted target and source
647     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
648     if (defined $forward_to_gosa) {
649         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
650     }
652     # Sanity check of needed parameter
653     if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH'))  {
654         &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
655         &add_content2xml_hash($out_hash, "error", "productId");
656         &main::daemon_log("$session_id ERROR: no productId specified or productId tag invalid: $msg", 1); 
657         return ( &create_xml_string($out_hash) );
658     }
659     if (not exists $msg_hash->{'item'}) {
660         &add_content2xml_hash($out_hash, "error_string", "message needs one xml-tag 'item' and within the xml-tags 'name' and 'value'");
661         &add_content2xml_hash($out_hash, "error", "item");
662         &main::daemon_log("$session_id ERROR: message needs one xml-tag 'item' and within the xml-tags 'name' and 'value': $msg", 1); 
663         return ( &create_xml_string($out_hash) );
664     } else {
665         if ((not exists @{$msg_hash->{'item'}}[0]->{'name'}) || (@{@{$msg_hash->{'item'}}[0]->{'name'}} != 1 )) {
666             &add_content2xml_hash($out_hash, "error_string", "message needs within the xml-tag 'item' one xml-tags 'name'");
667             &add_content2xml_hash($out_hash, "error", "name");
668             &main::daemon_log("$session_id ERROR: message needs within the xml-tag 'item' one xml-tags 'name': $msg", 1); 
669             return ( &create_xml_string($out_hash) );
670         }
671         if ((not exists @{$msg_hash->{'item'}}[0]->{'value'}) || (@{@{$msg_hash->{'item'}}[0]->{'value'}} != 1 )) {
672             &add_content2xml_hash($out_hash, "error_string", "message needs within the xml-tag 'item' one xml-tags 'value'");
673             &add_content2xml_hash($out_hash, "error", "value");
674             &main::daemon_log("$session_id ERROR: message needs within the xml-tag 'item' one xml-tags 'value': $msg", 1); 
675             return ( &create_xml_string($out_hash) );
676         }
677     }
678     # if no hostId is given, set_product_properties will act on globally
679     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} > 1))  {
680         &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
681         &add_content2xml_hash($out_hash, "error", "hostId");
682         &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1); 
683         return ( &create_xml_string($out_hash) );
684     }
686         
687     # Get productId
688     $productId =  @{$msg_hash->{'productId'}}[0];
689     &add_content2xml_hash($out_hash, "productId", $productId);
691     # Get hostId if defined
692     if (exists $msg_hash->{'hostId'}){
693         $hostId = @{$msg_hash->{'hostId'}}[0];
694         &add_content2xml_hash($out_hash, "hostId", $hostId);
695     }
697     # Set product states if requested
698     if (defined @{$msg_hash->{'action'}}[0]){
699         &_set_action($productId, @{$msg_hash->{'action'}}[0], $hostId);
700     }
701     if (defined @{$msg_hash->{'state'}}[0]){
702         &_set_state($productId, @{$msg_hash->{'state'}}[0], $hostId);
703     }
705     # Find properties
706     foreach my $item (@{$msg_hash->{'item'}}){
707         # JSON Query
708         my $callobj;
710         if (defined $hostId){
711             $callobj = {
712                 method  => 'setProductProperty',
713                 params  => [ $productId, $item->{'name'}[0], $item->{'value'}[0], $hostId ],
714                 id  => 1,
715             };
716         } else {
717             $callobj = {
718                 method  => 'setProductProperty',
719                 params  => [ $productId, $item->{'name'}[0], $item->{'value'}[0] ],
720                 id  => 1,
721             };
722         }
724         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
725         my ($res_err, $res_err_string) = &check_opsi_res($res);
727         if ($res_err){
728             &main::daemon_log("$session_id ERROR: communication failed while setting '".$item->{'name'}[0]."': ".$res_err_string, 1);
729             &add_content2xml_hash($out_hash, "error", $res_err_string);
730         }
731     }
734     # Return message
735         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
736     return ( &create_xml_string($out_hash) );
739 ################################   
740 # @brief Reports client hardware inventory.
741 # @param msg - STRING - xml message with tag hostId
742 # @param msg_hash - HASHREF - message information parsed into a hash
743 # @param session_id - INTEGER - POE session id of the processing of this message
744 # @return out_msg - STRING - feedback to GOsa in success and error case
745 sub opsi_get_client_hardware {
746         my $startTime = Time::HiRes::time;
747     my ($msg, $msg_hash, $session_id) = @_;
748     my $header = @{$msg_hash->{'header'}}[0];
749     my $source = @{$msg_hash->{'source'}}[0];
750     my $target = @{$msg_hash->{'target'}}[0];
751     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
752     my $hostId;
753     my $error = 0;
754     my $xml_msg;
756     # Sanity check of needed parameter
757         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
758         $hostId = @{$msg_hash->{'hostId'}}[0];
759         } else {
760                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
761         }
764     # Build return message with twisted target and source
765     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
766     if (defined $forward_to_gosa) {
767       &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
768     }
769         &add_content2xml_hash($out_hash, "hostId", "$hostId");
770         &add_content2xml_hash($out_hash, "xxx", "");
772     # Move to XML string
773     $xml_msg= &create_xml_string($out_hash);
774     
775         my $res = &_callOpsi(method=>'getHardwareInformation_hash', params=>[ $hostId ]);
776         if (not &check_opsi_res($res)){
777                 my $result= $res->result;
778                 if (ref $result eq "HASH") {
779                         foreach my $r (keys %{$result}){
780                                 my $item= "\n<item><id>".xml_quote($r)."</id>";
781                                 my $value= $result->{$r};
782                                 foreach my $sres (@{$value}){
784                                         foreach my $dres (keys %{$sres}){
785                                                 if (defined $sres->{$dres}){
786                                                         $item.= "<$dres>".xml_quote($sres->{$dres})."</$dres>";
787                                                 }
788                                         }
790                                 }
791                                 $item.= "</item>";
792                                 $xml_msg=~ s%<xxx></xxx>%$item<xxx></xxx>%;
794                         }
795                 }
796         }
798         $xml_msg=~ s/<xxx><\/xxx>//;
800     # Return message
801         my $endTime = Time::HiRes::time;
802         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
803         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
804     return ( $xml_msg );
807 ################################   
808 # @brief Reports all Opsi clients. 
809 # @param msg - STRING - xml message 
810 # @param msg_hash - HASHREF - message information parsed into a hash
811 # @param session_id - INTEGER - POE session id of the processing of this message
812 # @return out_msg - STRING - feedback to GOsa in success and error case
813 sub opsi_list_clients {
814         my $startTime = Time::HiRes::time;
815     my ($msg, $msg_hash, $session_id) = @_;
816     my $header = @{$msg_hash->{'header'}}[0];
817     my $source = @{$msg_hash->{'source'}}[0];
818     my $target = @{$msg_hash->{'target'}}[0];
819     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
821     # Build return message with twisted target and source
822     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
823     if (defined $forward_to_gosa) {
824       &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
825     }
826     &add_content2xml_hash($out_hash, "xxx", "");
828     # Move to XML string
829     my $xml_msg= &create_xml_string($out_hash);
831     # JSON Query
832     my $callobj = {
833         method  => 'getClientsInformation_listOfHashes',
834         params  => [ ],
835         id  => 1,
836     };
838     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
839     if (not &check_opsi_res($res)){
840         foreach my $host (@{$res->result}){
841             my $item= "\n<item><name>".$host->{'hostId'}."</name>";
842             $item.= "<mac>".xml_quote($host->{'macAddress'})."</mac>";
843             if (defined($host->{'description'})){
844                 $item.= "<description>".xml_quote($host->{'description'})."</description>";
845             }
846             if (defined($host->{'notes'})){
847                 $item.= "<notes>".xml_quote($host->{'notes'})."</notes>";
848             }
849             if (defined($host->{'lastSeen'})){
850                 $item.= "<lastSeen>".xml_quote($host->{'lastSeen'})."</lastSeen>";
851             }
853             $item.= "</item>";
854             $xml_msg=~ s%<xxx></xxx>%$item<xxx></xxx>%;
855         }
856     }
857     $xml_msg=~ s/<xxx><\/xxx>//;
859         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
860     return ( $xml_msg );
863 ################################   
864 # @brief Reports client software inventory.
865 # @param msg - STRING - xml message with tag hostId
866 # @param msg_hash - HASHREF - message information parsed into a hash
867 # @param session_id - INTEGER - POE session id of the processing of this message
868 # @return out_msg - STRING - feedback to GOsa in success and error case
869 sub opsi_get_client_software {
870         my $startTime = Time::HiRes::time;
871     my ($msg, $msg_hash, $session_id) = @_;
872     my $header = @{$msg_hash->{'header'}}[0];
873     my $source = @{$msg_hash->{'source'}}[0];
874     my $target = @{$msg_hash->{'target'}}[0];
875     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
876     my $error = 0;
877     my $hostId;
878     my $xml_msg;
880     # Build return message with twisted target and source
881     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
882     if (defined $forward_to_gosa) {
883       &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
884     }
886     # Sanity check of needed parameter
887     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
888         $error++;
889         &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
890         &add_content2xml_hash($out_hash, "error", "hostId");
891         &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1); 
892     }
894     if (not $error) {
896     # Get hostId
897         $hostId = @{$msg_hash->{'hostId'}}[0];
898         &add_content2xml_hash($out_hash, "hostId", "$hostId");
899         &add_content2xml_hash($out_hash, "xxx", "");
900     }
902     $xml_msg= &create_xml_string($out_hash);
904     if (not $error) {
906     # JSON Query
907         my $callobj = {
908             method  => 'getSoftwareInformation_hash',
909             params  => [ $hostId ],
910             id  => 1,
911         };
913         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
914         if (not &check_opsi_res($res)){
915             my $result= $res->result;
916         }
918         $xml_msg=~ s/<xxx><\/xxx>//;
920     }
922     # Return message
923         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
924     return ( $xml_msg );
927 ################################   
928 # @brief Reports product for given hostId or globally.
929 # @param msg - STRING - xml message with optional tag hostId
930 # @param msg_hash - HASHREF - message information parsed into a hash
931 # @param session_id - INTEGER - POE session id of the processing of this message
932 # @return out_msg - STRING - feedback to GOsa in success and error case
933 sub opsi_get_local_products {
934     my $startTime = Time::HiRes::time;
935     my ($msg, $msg_hash, $session_id) = @_;
936     my $header = @{$msg_hash->{'header'}}[0];
937     my $source = @{$msg_hash->{'source'}}[0];
938     my $target = @{$msg_hash->{'target'}}[0];
939     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
940     my $hostId;
942     # Build return message with twisted target and source
943     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
944     if (defined $forward_to_gosa) {
945         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
946     }
947     &add_content2xml_hash($out_hash, "xxx", "");
949     # Get hostId if defined
950     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1))  {
951         $hostId = @{$msg_hash->{'hostId'}}[0];
952         &add_content2xml_hash($out_hash, "hostId", $hostId);
953     }
955     my $callobj;
957     # Move to XML string
958     my $xml_msg= &create_xml_string($out_hash);
960     # Check if we need to get host or global information
961     if (defined $hostId){
962       $callobj = {
963           method  => 'getProductHostInformation_list',
964           params  => [ $hostId ],
965           id  => 1,
966       };
968       my $res = $main::opsi_client->call($main::opsi_url, $callobj);
969       if (not &check_opsi_res($res)){
970           foreach my $product (@{$res->result}){
971                my $replace= "<item><productId>".xml_quote($product->{'productId'})."<\/productId><name>".xml_quote($product->{'name'})."<\/name><description>".xml_quote($product->{'description'})."<\/description><state>".xml_quote($product->{'installationStatus'})."</state><action>".xml_quote($product->{'actionRequest'})."</action><\/item><xxx><\/xxx>";
972                $xml_msg=~ s/<xxx><\/xxx>/\n$replace/;
973           }
974       }
976     } else {
978       # For hosts, only return the products that are or get installed
979       $callobj = {
980           method  => 'getProductInformation_list',
981           params  => [ undef, 'localboot' ],
982           id  => 1,
983       };
985       my $res = $main::opsi_client->call($main::opsi_url, $callobj);
986       if (not &check_opsi_res($res)){
987           foreach my $product (@{$res->result}) {
988                my $replace= "<item><productId>".xml_quote($product->{'productId'})."<\/productId><name>".xml_quote($product->{'name'})."<\/name><description>".xml_quote($product->{'description'})."<\/description><\/item><xxx><\/xxx>";
989                $xml_msg=~ s/<xxx><\/xxx>/\n$replace/;
990           }
991       }
992     }
994     $xml_msg=~ s/<xxx><\/xxx>//;
996     # Retrun Message
997         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
998     return ( $xml_msg );
1001 ################################   
1002 # @brief Deletes a client from Opsi.
1003 # @param msg - STRING - xml message with tag hostId
1004 # @param msg_hash - HASHREF - message information parsed into a hash
1005 # @param session_id - INTEGER - POE session id of the processing of this message
1006 # @return out_msg - STRING - feedback to GOsa in success and error case
1007 sub opsi_del_client {
1008         my $startTime = Time::HiRes::time;
1009     my ($msg, $msg_hash, $session_id) = @_;
1010     my $header = @{$msg_hash->{'header'}}[0];
1011     my $source = @{$msg_hash->{'source'}}[0];
1012     my $target = @{$msg_hash->{'target'}}[0];
1013     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1014     my $hostId;
1015     my $error = 0;
1017     # Build return message with twisted target and source
1018     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1019     if (defined $forward_to_gosa) {
1020       &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1021     }
1023     # Sanity check of needed parameter
1024     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
1025         $error++;
1026         &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
1027         &add_content2xml_hash($out_hash, "error", "hostId");
1028         &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1); 
1029     }
1031     if (not $error) {
1033     # Get hostId
1034         $hostId = @{$msg_hash->{'hostId'}}[0];
1035         &add_content2xml_hash($out_hash, "hostId", "$hostId");
1037     # JSON Query
1038         my $callobj = {
1039             method  => 'deleteClient',
1040             params  => [ $hostId ],
1041             id  => 1,
1042         };
1043         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1044     }
1046     # Move to XML string
1047     my $xml_msg= &create_xml_string($out_hash);
1049     # Return message
1050         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1051     return ( $xml_msg );
1054 ################################   
1055 # @brief Set a client in Opsi to install and trigger a wake on lan message (WOL).  
1056 # @param msg - STRING - xml message with tags hostId, macaddress
1057 # @param msg_hash - HASHREF - message information parsed into a hash
1058 # @param session_id - INTEGER - POE session id of the processing of this message
1059 # @return out_msg - STRING - feedback to GOsa in success and error case
1060 sub opsi_install_client {
1061         my $startTime = Time::HiRes::time;
1062     my ($msg, $msg_hash, $session_id) = @_;
1063     my $header = @{$msg_hash->{'header'}}[0];
1064     my $source = @{$msg_hash->{'source'}}[0];
1065     my $target = @{$msg_hash->{'target'}}[0];
1066     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1067     my ($hostId, $macaddress);
1068     my $error = 0;
1069     my @out_msg_l;
1071     # Build return message with twisted target and source
1072     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1073     if (defined $forward_to_gosa) {
1074         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1075     }
1077     # Sanity check of needed parameter
1078     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
1079         $error++;
1080         &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
1081         &add_content2xml_hash($out_hash, "error", "hostId");
1082         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
1083     }
1084     if ((not exists $msg_hash->{'macaddress'}) || (@{$msg_hash->{'macaddress'}} != 1) || (@{$msg_hash->{'macaddress'}}[0] eq ref 'HASH') )  {
1085         $error++;
1086         &add_content2xml_hash($out_hash, "error_string", "no macaddress specified or macaddress tag invalid");
1087         &add_content2xml_hash($out_hash, "error", "macaddress");
1088         &main::daemon_log("$session_id ERROR: no macaddress specified or macaddress tag invalid: $msg", 1); 
1089     } else {
1090         if ((exists $msg_hash->{'macaddress'}) && 
1091                 ($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)) {  
1092             $macaddress = $1; 
1093         } else { 
1094             $error ++; 
1095             &add_content2xml_hash($out_hash, "error_string", "given mac address is not correct");
1096             &add_content2xml_hash($out_hash, "error", "macaddress");
1097             &main::daemon_log("$session_id ERROR: given mac address is not correct: $msg", 1); 
1098         }
1099     }
1101     if (not $error) {
1103     # Get hostId
1104         $hostId = @{$msg_hash->{'hostId'}}[0];
1105         &add_content2xml_hash($out_hash, "hostId", "$hostId");
1107         # Load all products for this host with status != "not_installed" or actionRequest != "none"
1108         my $callobj = {
1109             method  => 'getProductStates_hash',
1110             params  => [ $hostId ],
1111             id  => 1,
1112         };
1114         my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
1115         if (not &check_opsi_res($hres)){
1116             my $htmp= $hres->result->{$hostId};
1118             # check state != not_installed or action == setup -> load and add
1119             foreach my $product (@{$htmp}){
1120                 # Now we've a couple of hashes...
1121                 if ($product->{'installationStatus'} ne "not_installed" or
1122                         $product->{'actionRequest'} ne "none"){
1124                     # Do an action request for all these -> "setup".
1125                     $callobj = {
1126                         method  => 'setProductActionRequest',
1127                         params  => [ $product->{'productId'}, $hostId, "setup" ],
1128                         id  => 1,
1129                     };
1130                     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1131                     my ($res_err, $res_err_string) = &check_opsi_res($res);
1132                     if ($res_err){
1133                         &main::daemon_log("$session_id ERROR: cannot set product action request for '$hostId': ".$product->{'productId'}, 1);
1134                     } else {
1135                         &main::daemon_log("$session_id INFO: requesting 'setup' for '".$product->{'productId'}."' on $hostId", 1);
1136                     }
1137                 }
1138             }
1139         }
1140         push(@out_msg_l, &create_xml_string($out_hash));
1141     
1143     # Build wakeup message for client
1144         if (not $error) {
1145             my $wakeup_hash = &create_xml_hash("trigger_wake", "GOSA", "KNOWN_SERVER");
1146             &add_content2xml_hash($wakeup_hash, 'macaddress', $macaddress);
1147             my $wakeup_msg = &create_xml_string($wakeup_hash);
1148             push(@out_msg_l, $wakeup_msg);
1150             # invoke trigger wake for this gosa-si-server
1151             &main::server_server_com::trigger_wake($wakeup_msg, $wakeup_hash, $session_id);
1152         }
1153     }
1154     
1155     # Return messages
1156         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1157     return @out_msg_l;
1160 ################################
1161 # @brief Set action for an Opsi client
1162 # @param product - STRING - Opsi product
1163 # @param action - STRING - action
1164 # @param hostId - STRING - Opsi hostId
1165 sub _set_action {
1166   my $product= shift;
1167   my $action = shift;
1168   my $hostId = shift;
1169   my $callobj;
1171   $callobj = {
1172     method  => 'setProductActionRequest',
1173     params  => [ $product, $hostId, $action],
1174     id  => 1,
1175   };
1177   $main::opsi_client->call($main::opsi_url, $callobj);
1180 ################################
1181 # @brief Set state for an Opsi client
1182 # @param product - STRING - Opsi product
1183 # @param action - STRING - state
1184 # @param hostId - STRING - Opsi hostId
1185 sub _set_state {
1186   my $product = shift;
1187   my $state = shift;
1188   my $hostId = shift;
1189   my $callobj;
1191   $callobj = {
1192     method  => 'setProductState',
1193     params  => [ $product, $hostId, $state ],
1194     id  => 1,
1195   };
1197   $main::opsi_client->call($main::opsi_url, $callobj);
1200 ################################
1201 # @brief Create a license pool at Opsi server.
1202 # @param licensePoolId The name of the pool (optional). 
1203 # @param description The description of the pool (optional).
1204 # @param productIds A list of assigned porducts of the pool (optional). 
1205 # @param windowsSoftwareIds A list of windows software IDs associated to the pool (optional). 
1206 sub opsi_createLicensePool {
1207         my $startTime = Time::HiRes::time;
1208     my ($msg, $msg_hash, $session_id) = @_;
1209     my $header = @{$msg_hash->{'header'}}[0];
1210     my $source = @{$msg_hash->{'source'}}[0];
1211     my $target = @{$msg_hash->{'target'}}[0];
1212         my $out_hash;
1213         my $licensePoolId = defined $msg_hash->{'licensePoolId'} ? @{$msg_hash->{'licensePoolId'}}[0] : undef;
1214         my $description = defined $msg_hash->{'description'} ? @{$msg_hash->{'description'}}[0] : undef;
1215         my @productIds = defined $msg_hash->{'productIds'} ? $msg_hash->{'productIds'} : undef;
1216         my @windowsSoftwareIds = defined $msg_hash->{'windowsSoftwareIds'} ? $msg_hash->{'windowsSoftwareIds'} : undef;
1218         # Create license Pool
1219     my $callobj = {
1220         method  => 'createLicensePool',
1221         params  => [ $licensePoolId, $description, @productIds, @windowsSoftwareIds],
1222         id  => 1,
1223     };
1224     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1226         # Check Opsi error
1227         my ($res_error, $res_error_str) = &check_opsi_res($res);
1228         if ($res_error){
1229                 # Create error message
1230                 &main::daemon_log("$session_id ERROR: cannot create license pool at Opsi server: ".$res_error_str, 1);
1231                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1232                 return ( &create_xml_string($out_hash) );
1233         }
1235         # Create function result message
1236         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source, $res->result);
1237         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1239         my $endTime = Time::HiRes::time;
1240         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1241         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1242         return ( &create_xml_string($out_hash) );
1245 ################################
1246 # @brief Return licensePoolId, description, productIds and windowsSoftwareIds for all found license pools.
1247 sub opsi_getLicensePools_listOfHashes {
1248         my $startTime = Time::HiRes::time;
1249     my ($msg, $msg_hash, $session_id) = @_;
1250     my $header = @{$msg_hash->{'header'}}[0];
1251     my $source = @{$msg_hash->{'source'}}[0];
1252         my $out_hash;
1254         # Fetch infos from Opsi server
1255     my $callobj = {
1256         method  => 'getLicensePools_listOfHashes',
1257         params  => [ ],
1258         id  => 1,
1259     };
1260     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1262         # Check Opsi error
1263         my ($res_error, $res_error_str) = &check_opsi_res($res);
1264         if ($res_error){
1265                 # Create error message
1266                 &main::daemon_log("$session_id ERROR: cannot get license pool ID list from Opsi server: ".$res_error_str, 1);
1267                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1268                 return ( &create_xml_string($out_hash) );
1269         }
1271         # Create function result message
1272         my $res_hash = { 'hit'=> [] };
1273         foreach my $licensePool ( @{$res->result}) {
1274                 my $licensePool_hash = { 'licensePoolId' => [$licensePool->{'licensePoolId'}],
1275                         'description' => [$licensePool->{'description'}],
1276                         'productIds' => $licensePool->{'productIds'},
1277                         'windowsSoftwareIds' => $licensePool->{'windowsSoftwareIds'},
1278                         };
1279                 push( @{$res_hash->{hit}}, $licensePool_hash );
1280         }
1282         # Create function result message
1283         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1284         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1285         $out_hash->{result} = [$res_hash];
1287         my $endTime = Time::HiRes::time;
1288         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1289         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1290         return ( &create_xml_string($out_hash) );
1293 ################################
1294 # @brief Return productIds, windowsSoftwareIds and description for a given licensePoolId
1295 # @param licensePoolId The name of the pool. 
1296 sub opsi_getLicensePool_hash {
1297         my $startTime = Time::HiRes::time;
1298     my ($msg, $msg_hash, $session_id) = @_;
1299     my $header = @{$msg_hash->{'header'}}[0];
1300     my $source = @{$msg_hash->{'source'}}[0];
1301     my $target = @{$msg_hash->{'target'}}[0];
1302     my $licensePoolId;
1303         my $out_hash;
1305         # Check input sanity
1306         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1307                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1308         } else {
1309                 return &_giveErrorFeedback($msg_hash, "", $session_id, $_);
1310         }
1312         # Fetch infos from Opsi server
1313     my $callobj = {
1314         method  => 'getLicensePool_hash',
1315         params  => [ $licensePoolId ],
1316         id  => 1,
1317     };
1318     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1320         # Check Opsi error
1321         my ($res_error, $res_error_str) = &check_opsi_res($res);
1322         if ($res_error){
1323                 # Create error message
1324                 &main::daemon_log("$session_id ERROR: cannot get license pool from Opsi server: ".$res_error_str, 1);
1325                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source);
1326                 &add_content2xml_hash($out_hash, "error", $res_error_str);
1327                 return ( &create_xml_string($out_hash) );
1328         }
1330         # Create function result message
1331         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1332         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1333         &add_content2xml_hash($out_hash, "licensePoolId", $res->result->{'licensePoolId'});
1334         &add_content2xml_hash($out_hash, "description", $res->result->{'description'});
1335         map(&add_content2xml_hash($out_hash, "productIds", "$_"), @{ $res->result->{'productIds'} });
1336         map(&add_content2xml_hash($out_hash, "windowsSoftwareIds", "$_"), @{ $res->result->{'windowsSoftwareIds'} });
1338         my $endTime = Time::HiRes::time;
1339         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1340         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1341         return ( &create_xml_string($out_hash) );
1344 sub _parse_getSoftwareLicenseUsages {
1345         my $res = shift;
1347         # Parse Opsi result
1348         my $tmp_licensePool_cache = {};
1349         my $res_hash = { 'hit'=> [] };
1350         foreach my $license ( @{$res}) {
1351                 my $tmp_licensePool = $license->{'licensePoolId'};
1352                 if (not exists $tmp_licensePool_cache->{$tmp_licensePool}) {
1353                         # Fetch missing informations from Opsi and cache the results for a possible later usage
1354                         my ($res, $err) = &_getLicensePool_hash('licensePoolId'=>$tmp_licensePool);
1355                         if (not $err) {
1356                                 $tmp_licensePool_cache->{$tmp_licensePool} = $res;
1357                         }
1358                 }
1359                 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
1360                         'notes' => [$license->{'notes'}],
1361                         'licenseKey' => [$license->{'licenseKey'}],
1362                         'hostId' => [$license->{'hostId'}],
1363                         'licensePoolId' => [$tmp_licensePool],
1364                         };
1365                 if (exists $tmp_licensePool_cache->{$tmp_licensePool}) {
1366                         $license_hash->{$tmp_licensePool} = {'productIds'=>[], 'windowsSoftwareIds'=>[]};
1367                         map (push (@{$license_hash->{$tmp_licensePool}->{productIds}}, $_), @{$tmp_licensePool_cache->{$tmp_licensePool}->{productIds}});
1368                         map (push (@{$license_hash->{$tmp_licensePool}->{windowsSoftwareIds}}, $_), @{$tmp_licensePool_cache->{$tmp_licensePool}->{windowsSoftwareIds}});
1369                 }
1370                 push( @{$res_hash->{hit}}, $license_hash );
1371         }
1373         return $res_hash;
1376 ################################
1377 # @brief Returns softwareLicenseId, notes, licenseKey, hostId and licensePoolId for optional given licensePoolId and hostId
1378 # @param hostid Something like client_1.intranet.mydomain.de (optional).
1379 # @param licensePoolId The name of the pool (optional). 
1380 sub opsi_getSoftwareLicenseUsages {
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 = defined $msg_hash->{'licensePoolId'} ? @{$msg_hash->{'licensePoolId'}}[0] : undef;
1387         my $hostId = defined $msg_hash->{'hostId'} ? @{$msg_hash->{'hostId'}}[0] : undef;
1388         my $out_hash;
1390         my ($res, $err) = &_getSoftwareLicenseUsages_listOfHashes('licensePoolId'=>$licensePoolId, 'hostId'=>$hostId);
1391         if ($err){
1392                 return &_giveErrorFeedback($msg_hash, "cannot fetch software licenses from license pool : ".$res, $session_id);
1393         }
1395         # Parse Opsi result
1396         my $res_hash = &_parse_getSoftwareLicenseUsages($res);
1398         # Create function result message
1399         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1400         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1401         $out_hash->{result} = [$res_hash];
1403         my $endTime = Time::HiRes::time;
1404         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1405         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1406         return ( &create_xml_string($out_hash) );
1409 ################################
1410 # @brief Returns softwareLicenseId, notes, licenseKey, hostId and licensePoolId. Function return is identical to opsi_getSoftwareLicenseUsages
1411 # @param productId Something like 'firefox', 'python' or anything else .
1412 sub opsi_getSoftwareLicenseUsagesForProductId {
1413         my $startTime = Time::HiRes::time;
1414         my ($msg, $msg_hash, $session_id) = @_;
1415         my $header = @{$msg_hash->{'header'}}[0];
1416         my $source = @{$msg_hash->{'source'}}[0];
1418         # Check input sanity
1419         my $productId;
1420         if (&_check_xml_tag_is_ok ($msg_hash, 'productId')) {
1421                 $productId= @{$msg_hash->{'productId'}}[0];
1422         } else {
1423                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1424         }
1426         # Fetch licensePoolId for productId
1427         my ($res, $err) = &_getLicensePoolId('productId'=>$productId);
1428         if ($err){
1429                 my $out_hash = &create_xml_hash("answer_$header", $main::server_address, $source);
1430                 $out_hash->{result} = [];
1431                 return ( &create_xml_string($out_hash) );
1432         }
1433         my $licensePoolId = $res;   # We assume that there is only one pool for each productID!!!
1435         # Fetch softwareLiceceUsages for licensePoolId
1436         ($res, $err) = &_getSoftwareLicenseUsages_listOfHashes('licensePoolId'=>$licensePoolId);
1437         if ($err){
1438                 return &_giveErrorFeedback($msg_hash, "cannot fetch software licenses from license pool : ".$res, $session_id);
1439         }
1440         # Parse Opsi result
1441         my $res_hash = &_parse_getSoftwareLicenseUsages($res);
1443         # Create function result message
1444         my $out_hash = &create_xml_hash("answer_$header", $main::server_address, $source);
1445         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1446         $out_hash->{result} = [$res_hash];
1448         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1449         return ( &create_xml_string($out_hash) );
1452 ################################
1453 # @brief Returns expirationDate, boundToHost, maxInstallation, licenseTyp, licensePoolIds and licenseKeys for a given softwareLicense ID.
1454 # @param softwareLicenseId Identificator of a license.
1455 sub opsi_getSoftwareLicense_hash {
1456         my $startTime = Time::HiRes::time;
1457         my ($msg, $msg_hash, $session_id) = @_;
1458         my $header = @{$msg_hash->{'header'}}[0];
1459         my $source = @{$msg_hash->{'source'}}[0];
1460         my $target = @{$msg_hash->{'target'}}[0];
1461         my $softwareLicenseId;
1462         my $out_hash;
1464         # Check input sanity
1465         if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
1466                 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
1467         } else {
1468                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1469         }
1471         my $callobj = {
1472                 method  => 'getSoftwareLicense_hash',
1473                 params  => [ $softwareLicenseId ],
1474                 id  => 1,
1475         };
1476         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1478         # Check Opsi error
1479         my ($res_error, $res_error_str) = &check_opsi_res($res);
1480         if ($res_error){
1481                 # Create error message
1482                 &main::daemon_log("$session_id ERROR: cannot fetch information for license '$softwareLicenseId': ".$res_error_str, 1);
1483                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1484                 return ( &create_xml_string($out_hash) );
1485         }
1486         
1487         # Create function result message
1488         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1489         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1490         &add_content2xml_hash($out_hash, "expirationDate", $res->result->{'expirationDate'});
1491         &add_content2xml_hash($out_hash, "boundToHost", $res->result->{'boundToHost'});
1492         &add_content2xml_hash($out_hash, "maxInstallations", $res->result->{'maxInstallations'});
1493         &add_content2xml_hash($out_hash, "licenseTyp", $res->result->{'licenseTyp'});
1494         foreach my $licensePoolId ( @{$res->result->{'licensePoolIds'}}) {
1495                 &add_content2xml_hash($out_hash, "licensePoolId", $licensePoolId);
1496                 &add_content2xml_hash($out_hash, $licensePoolId, $res->result->{'licenseKeys'}->{$licensePoolId});
1497         }
1499         my $endTime = Time::HiRes::time;
1500         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1501         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1502         return ( &create_xml_string($out_hash) );
1505 ################################
1506 # @brief Delete licnese pool by license pool ID. A pool can only be deleted if there are no software licenses bound to the pool. 
1507 # The fixed parameter deleteLicenses=True specifies that all software licenses bound to the pool are being deleted. 
1508 # @param licensePoolId The name of the pool. 
1509 sub opsi_deleteLicensePool {
1510         my $startTime = Time::HiRes::time;
1511         my ($msg, $msg_hash, $session_id) = @_;
1512     my $header = @{$msg_hash->{'header'}}[0];
1513     my $source = @{$msg_hash->{'source'}}[0];
1514     my $target = @{$msg_hash->{'target'}}[0];
1515     my $licensePoolId;
1516         my $out_hash;
1518         # Check input sanity
1519         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1520                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1521         } else {
1522                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1523         }
1525         # Fetch softwareLicenseIds used in license pool
1526         # This has to be done because function deleteLicensePool deletes the pool and the corresponding software licenses
1527         # but not the license contracts of the software licenses. In our case each software license has exactly one license contract. 
1528         my $callobj = {
1529                 method  => 'getSoftwareLicenses_listOfHashes',
1530                 params  => [ ],
1531                 id  => 1,
1532         };
1533         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1535         # Keep list of licenseContractIds in mind to delete it after the deletion of the software licenses
1536         my @lCI_toBeDeleted;
1537         foreach my $softwareLicenseHash ( @{$res->result} ) {
1538                 if ((@{$softwareLicenseHash->{'licensePoolIds'}} == 0) || (@{$softwareLicenseHash->{'licensePoolIds'}}[0] ne $licensePoolId)) { 
1539                         next; 
1540                 }  
1541                 push (@lCI_toBeDeleted, $softwareLicenseHash->{'licenseContractId'});
1542         }
1544         # Delete license pool at Opsi server
1545     $callobj = {
1546         method  => 'deleteLicensePool',
1547         params  => [ $licensePoolId, 'deleteLicenses=True'  ],
1548         id  => 1,
1549     };
1550     $res = $main::opsi_client->call($main::opsi_url, $callobj);
1551         my ($res_error, $res_error_str) = &check_opsi_res($res);
1552         if ($res_error){
1553                 # Create error message
1554                 &main::daemon_log("$session_id ERROR: cannot delete license pool at Opsi server: ".$res_error_str, 1);
1555                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1556                 return ( &create_xml_string($out_hash) );
1557         } 
1559         # Delete each license contract connected with the license pool
1560         foreach my $licenseContractId ( @lCI_toBeDeleted ) {
1561                 my $callobj = {
1562                         method  => 'deleteLicenseContract',
1563                         params  => [ $licenseContractId ],
1564                         id  => 1,
1565                 };
1566                 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1567                 my ($res_error, $res_error_str) = &check_opsi_res($res);
1568                 if ($res_error){
1569                         # Create error message
1570                         &main::daemon_log("$session_id ERROR: cannot delete license contract '$licenseContractId' connected with license pool '$licensePoolId' at Opsi server: ".$res_error_str, 1);
1571                         $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1572                         return ( &create_xml_string($out_hash) );
1573                 }
1574         }
1576         # Create function result message
1577         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1578         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1580         my $endTime = Time::HiRes::time;
1581         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1582         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1583         return ( &create_xml_string($out_hash) );
1586 ################################
1587 # @brief Create a license contract, create a software license and add the software license to the license pool
1588 # @param licensePoolId The name of the pool the license should be assigned.
1589 # @param licenseKey The license key.
1590 # @param partner Name of the license partner (optional).
1591 # @param conclusionDate Date of conclusion of license contract (optional)
1592 # @param notificationDate Date of notification that license is running out soon (optional).
1593 # @param notes This is the place for some notes (optional)
1594 # @param softwareLicenseId Identificator of a license (optional).
1595 # @param licenseTyp Typ of a licnese, either "OEM", "VOLUME" or "RETAIL" (optional).
1596 # @param maxInstallations The number of clients use this license (optional). 
1597 # @param boundToHost The name of the client the license is bound to (optional).
1598 # @param expirationDate The date when the license is running down (optional). 
1599 sub opsi_createLicense {
1600         my $startTime = Time::HiRes::time;
1601         my ($msg, $msg_hash, $session_id) = @_;
1602     my $header = @{$msg_hash->{'header'}}[0];
1603     my $source = @{$msg_hash->{'source'}}[0];
1604     my $target = @{$msg_hash->{'target'}}[0];
1605         my $partner = defined $msg_hash->{'partner'} ? @{$msg_hash->{'partner'}}[0] : undef;
1606         my $conclusionDate = defined $msg_hash->{'conclusionDate'} ? @{$msg_hash->{'conclusionDate'}}[0] : undef;
1607         my $notificationDate = defined $msg_hash->{'notificationDate'} ? @{$msg_hash->{'notificationDate'}}[0] : undef;
1608         my $notes = defined $msg_hash->{'notes'} ? @{$msg_hash->{'notes'}}[0] : undef;
1609         my $licenseContractId = undef;
1610         my $softwareLicenseId = defined $msg_hash->{'softwareLicenseId'} ? @{$msg_hash->{'softwareLicenseId'}}[0] : undef;
1611         my $licenseType = defined $msg_hash->{'licenseType'} ? @{$msg_hash->{'licenseType'}}[0] : undef;
1612         my $maxInstallations = defined $msg_hash->{'maxInstallations'} ? @{$msg_hash->{'maxInstallations'}}[0] : undef;
1613         my $boundToHost = defined $msg_hash->{'boundToHost'} ? @{$msg_hash->{'boundToHost'}}[0] : undef;
1614         my $expirationDate = defined $msg_hash->{'expirationDate'} ? @{$msg_hash->{'expirationDate'}}[0] : undef;
1615         my $licensePoolId;
1616         my $licenseKey;
1617         my $out_hash;
1619         # Check input sanity
1620         if (&_check_xml_tag_is_ok ($msg_hash, 'licenseKey')) {
1621                 $licenseKey = @{$msg_hash->{'licenseKey'}}[0];
1622         } else {
1623                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1624         }
1625         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1626                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1627         } else {
1628                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1629         }
1630         if ((defined $licenseType) && (not exists $licenseTyp_hash->{$licenseType})) {
1631                 return &_giveErrorFeedback($msg_hash, "The typ of a license can be either 'OEM', 'VOLUME' or 'RETAIL'.", $session_id);
1632         }
1633         
1634         # Automatically define licenseContractId if ID is not given
1635         if (defined $softwareLicenseId) { 
1636                 $licenseContractId = "c_".$softwareLicenseId;
1637         }
1639         # Create license contract at Opsi server
1640     my $callobj = {
1641         method  => 'createLicenseContract',
1642         params  => [ $licenseContractId, $partner, $conclusionDate, $notificationDate, undef, $notes ],
1643         id  => 1,
1644     };
1645     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1647         # Check Opsi error
1648         my ($res_error, $res_error_str) = &check_opsi_res($res);
1649         if ($res_error){
1650                 # Create error message
1651                 &main::daemon_log("$session_id ERROR: cannot create license contract at Opsi server: ".$res_error_str, 1);
1652                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1653                 return ( &create_xml_string($out_hash) );
1654         }
1655         
1656         $licenseContractId = $res->result;
1658         # Create software license at Opsi server
1659     $callobj = {
1660         method  => 'createSoftwareLicense',
1661         params  => [ $softwareLicenseId, $licenseContractId, $licenseType, $maxInstallations, $boundToHost, $expirationDate ],
1662         id  => 1,
1663     };
1664     $res = $main::opsi_client->call($main::opsi_url, $callobj);
1666         # Check Opsi error
1667         ($res_error, $res_error_str) = &check_opsi_res($res);
1668         if ($res_error){
1669                 # Create error message
1670                 &main::daemon_log("$session_id ERROR: cannot create software license at Opsi server: ".$res_error_str, 1);
1671                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1672                 return ( &create_xml_string($out_hash) );
1673         }
1675         $softwareLicenseId = $res->result;
1677         # Add software license to license pool
1678         $callobj = {
1679         method  => 'addSoftwareLicenseToLicensePool',
1680         params  => [ $softwareLicenseId, $licensePoolId, $licenseKey ],
1681         id  => 1,
1682     };
1683     $res = $main::opsi_client->call($main::opsi_url, $callobj);
1685         # Check Opsi error
1686         ($res_error, $res_error_str) = &check_opsi_res($res);
1687         if ($res_error){
1688                 # Create error message
1689                 &main::daemon_log("$session_id ERROR: cannot add software license to license pool at Opsi server: ".$res_error_str, 1);
1690                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1691                 return ( &create_xml_string($out_hash) );
1692         }
1694         # Create function result message
1695         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1696         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1697         
1698         my $endTime = Time::HiRes::time;
1699         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1700         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1701         return ( &create_xml_string($out_hash) );
1704 ################################
1705 # @brief Assign a software license to a host
1706 # @param hostid Something like client_1.intranet.mydomain.de
1707 # @param licensePoolId The name of the pool.
1708 sub opsi_assignSoftwareLicenseToHost {
1709         my $startTime = Time::HiRes::time;
1710         my ($msg, $msg_hash, $session_id) = @_;
1711     my $header = @{$msg_hash->{'header'}}[0];
1712     my $source = @{$msg_hash->{'source'}}[0];
1713     my $target = @{$msg_hash->{'target'}}[0];
1714         my $hostId;
1715         my $licensePoolId;
1717         # Check input sanity
1718         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1719                 $hostId = @{$msg_hash->{'hostId'}}[0];
1720         } else {
1721                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1722         }
1723         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1724                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1725         } else {
1726                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1727         }
1729         # Assign a software license to a host
1730         my $callobj = {
1731         method  => 'getAndAssignSoftwareLicenseKey',
1732         params  => [ $hostId, $licensePoolId ],
1733         id  => 1,
1734     };
1735     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1737         # Check Opsi error
1738         my ($res_error, $res_error_str) = &check_opsi_res($res);
1739         if ($res_error){
1740                 # Create error message
1741                 &main::daemon_log("$session_id ERROR: cannot assign a software license to a host at Opsi server: ".$res_error_str, 1);
1742                 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1743                 return ( &create_xml_string($out_hash) );
1744         }
1746         # Create function result message
1747         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1748         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1749         
1750         my $endTime = Time::HiRes::time;
1751         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1752         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1753         return ( &create_xml_string($out_hash) );
1756 ################################
1757 # @brief Unassign a software license from a host.
1758 # @param hostid Something like client_1.intranet.mydomain.de
1759 # @param licensePoolId The name of the pool.
1760 sub opsi_unassignSoftwareLicenseFromHost {
1761         my $startTime = Time::HiRes::time;
1762         my ($msg, $msg_hash, $session_id) = @_;
1763     my $header = @{$msg_hash->{'header'}}[0];
1764     my $source = @{$msg_hash->{'source'}}[0];
1765     my $target = @{$msg_hash->{'target'}}[0];
1766         my $hostId;
1767         my $licensePoolId;
1769         # Check input sanity
1770         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1771                 $hostId = @{$msg_hash->{'hostId'}}[0];
1772         } else {
1773                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1774         }
1775         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1776                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1777         } else {
1778                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1779         }
1781         # Unassign a software license from a host
1782         my $callobj = {
1783         method  => 'deleteSoftwareLicenseUsage',
1784         params  => [ $hostId, '', $licensePoolId ],
1785         id  => 1,
1786     };
1787     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1789         # Check Opsi error
1790         my ($res_error, $res_error_str) = &check_opsi_res($res);
1791         if ($res_error){
1792                 # Create error message
1793                 &main::daemon_log("$session_id ERROR: cannot unassign a software license from a host at Opsi server: ".$res_error_str, 1);
1794                 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1795                 return ( &create_xml_string($out_hash) );
1796         }
1798         # Create function result message
1799         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1800         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1801         
1802         my $endTime = Time::HiRes::time;
1803         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1804         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1805         return ( &create_xml_string($out_hash) );
1808 ################################
1809 # @brief Unassign all software licenses from a host
1810 # @param hostid Something like client_1.intranet.mydomain.de
1811 sub opsi_unassignAllSoftwareLicensesFromHost {
1812         my $startTime = Time::HiRes::time;
1813         my ($msg, $msg_hash, $session_id) = @_;
1814     my $header = @{$msg_hash->{'header'}}[0];
1815     my $source = @{$msg_hash->{'source'}}[0];
1816     my $target = @{$msg_hash->{'target'}}[0];
1817         my $hostId;
1819         # Check input sanity
1820         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1821                 $hostId = @{$msg_hash->{'hostId'}}[0];
1822         } else {
1823                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1824         }
1826         # Unassign all software licenses from a host
1827         my $callobj = {
1828         method  => 'deleteAllSoftwareLicenseUsages',
1829         params  => [ $hostId ],
1830         id  => 1,
1831     };
1832     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1834         # Check Opsi error
1835         my ($res_error, $res_error_str) = &check_opsi_res($res);
1836         if ($res_error){
1837                 # Create error message
1838                 &main::daemon_log("$session_id ERROR: cannot unassign a software license from a host at Opsi server: ".$res_error_str, 1);
1839                 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1840                 return ( &create_xml_string($out_hash) );
1841         }
1843         # Create function result message
1844         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1845         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1846         
1847         my $endTime = Time::HiRes::time;
1848         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1849         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1850         return ( &create_xml_string($out_hash) );
1854 ################################
1855 # @brief Returns the assigned licensePoolId and licenses, how often the product is installed and at which host
1856 # and the number of max and remaining installations for a given OPSI product.
1857 # @param productId Identificator of an OPSI product.
1858 sub opsi_getLicenseInformationForProduct {
1859         my $startTime = Time::HiRes::time;
1860     my ($msg, $msg_hash, $session_id) = @_;
1861     my $header = @{$msg_hash->{'header'}}[0];
1862     my $source = @{$msg_hash->{'source'}}[0];
1863         my $productId;
1864         my $out_hash;
1866         # Check input sanity
1867         if (&_check_xml_tag_is_ok ($msg_hash, 'productId')) {
1868                 $productId = @{$msg_hash->{'productId'}}[0];
1869         } else {
1870                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1871         }
1873         # Fetch infos from Opsi server
1874     my $callobj = {
1875         method  => 'getLicensePoolId',
1876         params  => [ $productId ],
1877         id  => 1,
1878     };
1879     #my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1880     my $res = $opsi_client->call($opsi_url, $callobj);
1882         # Check Opsi error
1883         my ($res_error, $res_error_str) = &check_opsi_res($res);
1884         if ($res_error){
1885                 return &_giveErrorFeedback($msg_hash, "cannot get license pool for product '$productId' : ".$res_error_str, $session_id);
1886         } 
1887         
1888         my $licensePoolId = $res->result;
1890         # Fetch statistic information for given pool ID
1891         $callobj = {
1892                 method  => 'getLicenseStatistics_hash',
1893                 params  => [ ],
1894                 id  => 1,
1895         };
1896         $res = $opsi_client->call($opsi_url, $callobj);
1898         # Check Opsi error
1899         ($res_error, $res_error_str) = &check_opsi_res($res);
1900         if ($res_error){
1901                 # Create error message
1902                 &main::daemon_log("$session_id ERROR: cannot get statistic informations for license pools : ".$res_error_str, 1);
1903                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1904                 return ( &create_xml_string($out_hash) );
1905         }
1907         # Create function result message
1908         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1909         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1910         &add_content2xml_hash($out_hash, "licensePoolId", $licensePoolId);
1911         &add_content2xml_hash($out_hash, "licenses", $res->result->{$licensePoolId}->{'licenses'});
1912         &add_content2xml_hash($out_hash, "usageCount", $res->result->{$licensePoolId}->{'usageCount'});
1913         &add_content2xml_hash($out_hash, "maxInstallations", $res->result->{$licensePoolId}->{'maxInstallations'});
1914         &add_content2xml_hash($out_hash, "remainingInstallations", $res->result->{$licensePoolId}->{'remainingInstallations'});
1915         map(&add_content2xml_hash($out_hash, "usedBy", "$_"), @{ $res->result->{$licensePoolId}->{'usedBy'}});
1917         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1918         return ( &create_xml_string($out_hash) );
1922 ################################
1923 # @brief Returns licensePoolId, description, a list of productIds, al list of windowsSoftwareIds and a list of licenses for a given licensePoolId. 
1924 # Each license contains softwareLicenseId, maxInstallations, licenseType, licensePoolIds, licenseKeys, hostIds, expirationDate, boundToHost and licenseContractId.
1925 # The licenseContract contains conclusionDate, expirationDate, notes, notificationDate and partner. 
1926 # @param licensePoolId The name of the pool.
1927 sub opsi_getPool {
1928         my $startTime = Time::HiRes::time;
1929     my ($msg, $msg_hash, $session_id) = @_;
1930     my $header = @{$msg_hash->{'header'}}[0];
1931     my $source = @{$msg_hash->{'source'}}[0];
1933         # Check input sanity
1934         my $licensePoolId;
1935         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1936                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1937         } else {
1938                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1939         }
1941         # Create hash for the answer
1942         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1943         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1945         # Call Opsi
1946         my ($res, $err) = &_getLicensePool_hash( 'licensePoolId'=> $licensePoolId );
1947         if ($err){
1948                 return &_giveErrorFeedback($msg_hash, "cannot get license pool from Opsi server: ".$res, $session_id);
1949         }
1950         # Add data to outgoing hash
1951         &add_content2xml_hash($out_hash, "licensePoolId", $res->{'licensePoolId'});
1952         &add_content2xml_hash($out_hash, "description", $res->{'description'});
1953         map(&add_content2xml_hash($out_hash, "productIds", "$_"), @{ $res->{'productIds'} });
1954         map(&add_content2xml_hash($out_hash, "windowsSoftwareIds", "$_"), @{ $res->{'windowsSoftwareIds'} });
1957         # Call Opsi two times
1958         my ($usages_res, $usages_err) = &_getSoftwareLicenseUsages_listOfHashes('licensePoolId'=>$licensePoolId);
1959         if ($usages_err){
1960                 return &_giveErrorFeedback($msg_hash, "cannot get software license usage information from Opsi server: ".$usages_res, $session_id);
1961         }
1962         my ($licenses_res, $licenses_err) = &_getSoftwareLicenses_listOfHashes();
1963         if ($licenses_err){
1964                 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server: ".$licenses_res, $session_id);
1965         }
1967         # Add data to outgoing hash
1968         # Parse through all software licenses and select those associated to the pool
1969         my $res_hash = { 'hit'=> [] };
1970         foreach my $license ( @$licenses_res) {
1971                 # Each license hash has a list of licensePoolIds so go through this list and search for matching licensePoolIds
1972                 my $found = 0;
1973                 my @licensePoolIds_list = @{$license->{licensePoolIds}};
1974                 foreach my $lPI ( @licensePoolIds_list) {
1975                         if ($lPI eq $licensePoolId) { $found++ }
1976                 }
1977                 if (not $found ) { next; };
1978                 # Found matching licensePoolId
1979                 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
1980                         'licenseKeys' => {},
1981                         'expirationDate' => [$license->{'expirationDate'}],
1982                         'boundToHost' => [$license->{'boundToHost'}],
1983                         'maxInstallations' => [$license->{'maxInstallations'}],
1984                         'licenseType' => [$license->{'licenseType'}],
1985                         'licenseContractId' => [$license->{'licenseContractId'}],
1986                         'licensePoolIds' => [],
1987                         'hostIds' => [],
1988                         };
1989                 foreach my $licensePoolId (@{ $license->{'licensePoolIds'}}) {
1990                         push( @{$license_hash->{'licensePoolIds'}}, $licensePoolId);
1991                         $license_hash->{licenseKeys}->{$licensePoolId} =  [ $license->{'licenseKeys'}->{$licensePoolId} ];
1992                 }
1993                 foreach my $usage (@$usages_res) {
1994                         # Search for hostIds with matching softwareLicenseId
1995                         if ($license->{'softwareLicenseId'} eq $usage->{'softwareLicenseId'}) {
1996                                 push( @{ $license_hash->{hostIds}}, $usage->{hostId});
1997                         }
1998                 }
2000                 # Each softwareLicenseId has one licenseContractId, fetch contract details for each licenseContractId
2001                 my ($lContract_res, $lContract_err) = &_getLicenseContract_hash('licenseContractId'=>$license->{licenseContractId});
2002                 if ($lContract_err){
2003                         return &_giveErrorFeedback($msg_hash, "cannot get software license contract information from Opsi server: ".$licenses_res, $session_id);
2004                 }
2005                 $license_hash->{$license->{'licenseContractId'}} = [];
2006                 my $licenseContract_hash = { 'conclusionDate' => [$lContract_res->{conclusionDate}],
2007                         'notificationDate' => [$lContract_res->{notificationDate}],
2008                         'notes' => [$lContract_res->{notes}],
2009                         'exirationDate' => [$lContract_res->{expirationDate}],
2010                         'partner' => [$lContract_res->{partner}],
2011                 };
2012                 push( @{$license_hash->{licenseContractData}}, $licenseContract_hash );
2014                 push( @{$res_hash->{hit}}, $license_hash );
2015         }
2016         $out_hash->{licenses} = [$res_hash];
2018         my $endTime = Time::HiRes::time;
2019         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2020         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2021     return ( &create_xml_string($out_hash) );
2025 ################################
2026 # @brief Removes at first the software license from license pool and than deletes the software license. 
2027 # Attention, the software license has to exists otherwise it will lead to an Opsi internal server error.
2028 # @param softwareLicenseId Identificator of a license.
2029 # @param licensePoolId The name of the pool.
2030 sub opsi_removeLicense {
2031         my $startTime = Time::HiRes::time;
2032     my ($msg, $msg_hash, $session_id) = @_;
2033     my $header = @{$msg_hash->{'header'}}[0];
2034     my $source = @{$msg_hash->{'source'}}[0];
2036         # Check input sanity
2037         my $softwareLicenseId;
2038         if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
2039                 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
2040         } else {
2041                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2042         }
2043         my $licensePoolId;
2044         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
2045                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
2046         } else {
2047                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2048         }
2049         
2050         # Call Opsi
2051         my ($res, $err) = &_removeSoftwareLicenseFromLicensePool( 'licensePoolId' => $licensePoolId, 'softwareLicenseId' => $softwareLicenseId );
2052         if ($err){
2053                 return &_giveErrorFeedback($msg_hash, "cannot delete software license from pool: ".$res, $session_id);
2054         }
2056         # Call Opsi
2057         ($res, $err) = &_deleteSoftwareLicense( 'softwareLicenseId'=>$softwareLicenseId );
2058         if ($err){
2059                 return &_giveErrorFeedback($msg_hash, "cannot delete software license from Opsi server: ".$res, $session_id);
2060         }
2062         # Create hash for the answer
2063         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2064         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2065         my $endTime = Time::HiRes::time;
2066         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2067         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2068         return ( &create_xml_string($out_hash) );
2072 ################################
2073 # @brief Return softwareLicenseId, maxInstallations, licenseType, licensePoolIds, licenseContractId, expirationDate, boundToHost and a list of productIds.
2074 # @param hostId Something like client_1.intranet.mydomain.de
2075 sub opsi_getReservedLicenses {
2076         my $startTime = Time::HiRes::time;
2077         my ($msg, $msg_hash, $session_id) = @_;
2078         my $header = @{$msg_hash->{'header'}}[0];
2079         my $source = @{$msg_hash->{'source'}}[0];
2081         # Check input sanity
2082         my $hostId;
2083         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
2084                 $hostId = @{$msg_hash->{'hostId'}}[0];
2085         } else {
2086                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2087         }
2089         # Fetch informations from Opsi server
2090         my ($license_res, $license_err) = &_getSoftwareLicenses_listOfHashes();
2091         if ($license_err){
2092                 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server: ".$license_res, $session_id);
2093         }
2095         # Parse result
2096         my $res_hash = { 'hit'=> [] };
2097         foreach my $license ( @$license_res) {
2098                 if ($license->{boundToHost} ne $hostId) { next; }
2100                 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
2101                         'maxInstallations' => [$license->{'maxInstallations'}],
2102                         'boundToHost' => [$license->{'boundToHost'}],
2103                         'expirationDate' => [$license->{'expirationDate'}],
2104                         'licenseContractId' => [$license->{'licenseContractId'}],
2105                         'licenseType' => [$license->{'licenseType'}],
2106                         'licensePoolIds' => [],
2107                         };
2108                 
2109                 foreach my $licensePoolId (@{$license->{'licensePoolIds'}}) {
2110                         # Fetch information for license pools containing a software license which is bound to given host
2111                         my ($pool_res, $pool_err) = &_getLicensePool_hash( 'licensePoolId'=>$licensePoolId );
2112                         if ($pool_err){
2113                                 return &_giveErrorFeedback($msg_hash, "cannot get license pool from Opsi server: ".$pool_res, $session_id);
2114                         }
2116                         # Add licensePool information to result hash
2117                         push (@{$license_hash->{licensePoolIds}}, $licensePoolId);
2118                         $license_hash->{$licensePoolId} = {'productIds'=>[], 'windowsSoftwareIds'=>[]};
2119                         map (push (@{$license_hash->{$licensePoolId}->{productIds}}, $_), @{$pool_res->{productIds}});
2120                         map (push (@{$license_hash->{$licensePoolId}->{windowsSoftwareIds}}, $_), @{$pool_res->{windowsSoftwareIds}});
2121                 }
2122                 push( @{$res_hash->{hit}}, $license_hash );
2123         }
2124         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2125         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2126         $out_hash->{licenses} = [$res_hash];
2128         my $endTime = Time::HiRes::time;
2129         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2130         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2131     return ( &create_xml_string($out_hash) );
2134 ################################
2135 # @brief Bound the given softwareLicenseId to the given host.
2136 # @param hostId Opsi hostId
2137 # @param softwareLicenseId Identificator of a license (optional).
2138 sub opsi_boundHostToLicense {
2139         my $startTime = Time::HiRes::time;
2140         my ($msg, $msg_hash, $session_id) = @_;
2141         my $header = @{$msg_hash->{'header'}}[0];
2142         my $source = @{$msg_hash->{'source'}}[0];
2144         # Check input sanity
2145         my $hostId;
2146         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
2147                 $hostId = @{$msg_hash->{'hostId'}}[0];
2148         } else {
2149                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2150         }
2151         my $softwareLicenseId;
2152         if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
2153                 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
2154         } else {
2155                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2156         }
2158         # Fetch informations from Opsi server
2159         my ($license_res, $license_err) = &_getSoftwareLicenses_listOfHashes();
2160         if ($license_err){
2161                 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server: ".$license_res, $session_id);
2162         }
2164         # Memorize parameter for given softwareLicenseId
2165         my $licenseContractId;
2166         my $licenseType;
2167         my $maxInstallations;
2168         my $boundToHost;
2169         my $expirationDate = "";
2170         my $found;
2171         foreach my $license (@$license_res) {
2172                 if ($license->{softwareLicenseId} ne $softwareLicenseId) { next; }
2173                 $licenseContractId = $license->{licenseContractId};
2174                 $licenseType = $license->{licenseType};
2175                 $maxInstallations = $license->{maxInstallations};
2176                 $expirationDate = $license->{expirationDate};
2177                 $found++;
2178         }
2180         if (not $found) {
2181                 return &_giveErrorFeedback($msg_hash, "no softwarelicenseId found with name '".$softwareLicenseId."'", $session_id);
2182         }
2184         # Set boundToHost option for a given software license
2185         my ($bound_res, $bound_err) = &_createSoftwareLicense('softwareLicenseId'=>$softwareLicenseId, 
2186                         'licenseContractId' => $licenseContractId, 
2187                         'licenseType' => $licenseType, 
2188                         'maxInstallations' => $maxInstallations, 
2189                         'boundToHost' => $hostId, 
2190                         'expirationDate' => $expirationDate);
2191         if ($bound_err) {
2192                 return &_giveErrorFeedback($msg_hash, "cannot set boundToHost for given softwareLicenseId and hostId: ".$bound_res, $session_id);
2193         }
2195         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2196         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2198         my $endTime = Time::HiRes::time;
2199         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2200         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2201     return ( &create_xml_string($out_hash) );
2204 ################################
2205 # @brief Release a software license formerly bound to a host.
2206 # @param softwareLicenseId Identificator of a license.
2207 sub opsi_unboundHostFromLicense {
2208         # This is really mad! Opsi is not able to unbound a lincense from a host. To provide the functionality for GOsa
2209         # 4 rpc calls to Opsi are necessary. First, fetch all data for the given softwareLicenseId, then all details for the associated
2210         # licenseContractId, then delete the softwareLicense and finally recreate the softwareLicense without the boundToHost option. NASTY!
2211         my $startTime = Time::HiRes::time;
2212         my ($msg, $msg_hash, $session_id) = @_;
2213         my $header = @{$msg_hash->{'header'}}[0];
2214         my $source = @{$msg_hash->{'source'}}[0];
2216         # Check input sanity
2217         my $softwareLicenseId;
2218         if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
2219                 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
2220         } else {
2221                 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2222         }
2223         
2224         # Memorize parameter witch are required for this procedure
2225         my $licenseContractId;
2226         my $licenseType;
2227         my $maxInstallations;
2228         my $expirationDate;
2229         my $partner;
2230         my $conclusionDate;
2231         my $notificationDate;
2232         my $notes;
2233         my $licensePoolId;
2234         my $licenseKey;
2236         # Fetch license informations from Opsi server
2237         my ($license_res, $license_err) = &_getSoftwareLicenses_listOfHashes();
2238         if ($license_err){
2239                 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server, required to unbound license from host: ".$license_res, $session_id);
2240         }
2241         my $found = 0;
2242         foreach my $license (@$license_res) {
2243                 if (($found > 0) || ($license->{softwareLicenseId} ne $softwareLicenseId)) { next; }
2244                 $licenseContractId = $license->{licenseContractId};
2245                 $licenseType = $license->{licenseType};
2246                 $maxInstallations = $license->{maxInstallations};
2247                 $expirationDate = $license->{expirationDate};
2248                 $licensePoolId = @{$license->{licensePoolIds}}[0];
2249                 $licenseKey = $license->{licenseKeys}->{$licensePoolId};
2250                 $found++;
2251         }
2252         
2253         # Fetch contract informations from Opsi server
2254         my ($contract_res, $contract_err) = &_getLicenseContract_hash('licenseContractId'=>$licenseContractId);
2255         if ($contract_err){
2256                 return &_giveErrorFeedback($msg_hash, "cannot get contract license information from Opsi server, required to unbound license from host: ".$license_res, $session_id);
2257         }
2258         $partner = $contract_res->{partner};
2259         $conclusionDate = $contract_res->{conclusionDate};
2260         $notificationDate = $contract_res->{notificationDate};
2261         $expirationDate = $contract_res->{expirationDate};
2262         $notes = $contract_res->{notes};
2264         # Delete software license
2265         my ($res, $err) = &_deleteSoftwareLicense( 'softwareLicenseId' => $softwareLicenseId, 'removeFromPools'=> "true" );
2266         if ($err) {
2267                 return &_giveErrorFeedback($msg_hash, "cannot delet license from Opsi server, required to unbound license from host : ".$res, $session_id);
2268         }
2270         # Recreate software license without boundToHost
2271         ($res, $err) = &_createLicenseContract( 'licenseContractId' => $licenseContractId, 'partner' => $partner, 'conclusionDate' => $conclusionDate, 
2272                         'notificationDate' => $notificationDate, 'expirationDate' => $expirationDate, 'notes' => $notes );
2273         if ($err) {
2274                 return &_giveErrorFeedback($msg_hash, "cannot create license contract at Opsi server, required to unbound license from host : ".$res, $session_id);
2275         }
2276         ($res, $err) = &_createSoftwareLicense( 'softwareLicenseId' => $softwareLicenseId, 'licenseContractId' => $licenseContractId, 'licenseType' => $licenseType, 
2277                         'maxInstallations' => $maxInstallations, 'boundToHost' => "", 'expirationDate' => $expirationDate       );
2278         if ($err) {
2279                 return &_giveErrorFeedback($msg_hash, "cannot create software license at Opsi server, required to unbound license from host : ".$res, $session_id);
2280         }
2281         ($res, $err) = &_addSoftwareLicenseToLicensePool( 'softwareLicenseId' => $softwareLicenseId, 'licensePoolId' => $licensePoolId, 'licenseKey' => $licenseKey );
2282         if ($err) {
2283                 return &_giveErrorFeedback($msg_hash, "cannot add software license to license pool at Opsi server, required to unbound license from host : ".$res, $session_id);
2284         }
2286         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2287         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2289         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
2290     return ( &create_xml_string($out_hash) );
2293 ################################
2294 # @brief Returns a list of licenses with softwaerLicenseId, maxInstallations, boundToHost, expirationDate, licenseContractId, licenseType, a list of licensePoolIds with associated licenseKeys
2295 sub opsi_getAllSoftwareLicenses {
2296         my $startTime = Time::HiRes::time;
2297         my ($msg, $msg_hash, $session_id) = @_;
2298         my $header = @{$msg_hash->{'header'}}[0];
2299         my $source = @{$msg_hash->{'source'}}[0];
2301         my ($res, $err) = &_getSoftwareLicenses_listOfHashes();
2302         if ($err) {
2303                 return &_giveErrorFeedback($msg_hash, "cannot fetch software licenses from Opsi server : ".$res, $session_id);
2304         }
2306         # Parse result
2307         my $res_hash = { 'hit'=> [] };
2308         foreach my $license ( @$res) {
2309                 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
2310                         'maxInstallations' => [$license->{'maxInstallations'}],
2311                         'boundToHost' => [$license->{'boundToHost'}],
2312                         'expirationDate' => [$license->{'expirationDate'}],
2313                         'licenseContractId' => [$license->{'licenseContractId'}],
2314                         'licenseType' => [$license->{'licenseType'}],
2315                         'licensePoolIds' => [],
2316                         'licenseKeys'=> {}
2317                         };
2318                 foreach my $licensePoolId (@{$license->{'licensePoolIds'}}) {
2319                         push( @{$license_hash->{'licensePoolIds'}}, $licensePoolId);
2320                         $license_hash->{licenseKeys}->{$licensePoolId} =  [ $license->{'licenseKeys'}->{$licensePoolId} ];
2321                 }
2322                 push( @{$res_hash->{hit}}, $license_hash );
2323         }
2324         
2325         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2326         $out_hash->{licenses} = [$res_hash];
2327         if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2329         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
2330     return ( &create_xml_string($out_hash) );
2334 ################################
2335 # @brief Returns a list of values for a given host. Values: priority, onceScript, licenseRequired, packageVersion, productVersion, advice, setupScript, windowsSoftwareIds, installationStatus, pxeConfigTemplate, name, creationTimestamp, alwaysScript, productId, description, properties, actionRequest, uninstallScript, action, updateScript and productClassNames 
2336 # @param hostId Opsi hostId
2337 sub opsi_get_full_product_host_information {
2338         my $startTime = Time::HiRes::time;
2339         my ($msg, $msg_hash, $session_id) = @_;
2340         my $header = @{$msg_hash->{'header'}}[0];
2341         my $source = @{$msg_hash->{'source'}}[0];
2342         my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
2343         my $hostId;
2345         my ($res, $err) = &_get_full_product_host_information( hostId=>@{$msg_hash->{'hostId'}}[0]);
2346         if ($err) {
2347                 return &_giveErrorFeedback($msg_hash, "cannot fetch full_product_host_information from Opsi server : ".$res, $session_id);
2348         }
2350         # Build return message with twisted target and source
2351         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2352         if (defined $forward_to_gosa) {
2353             &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
2354         }
2355         &add_content2xml_hash($out_hash, "xxx", "");
2357         # Get hostId if defined
2358         if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1))  {
2359             $hostId = @{$msg_hash->{'hostId'}}[0];
2360             &add_content2xml_hash($out_hash, "hostId", $hostId);
2361         }
2363         # Move to XML string
2364         my $xml_msg= &create_xml_string($out_hash);
2365         
2366         # Convert result in something usable
2367         my $replace= "";
2368         foreach my $product ( @$res) {
2370           # Open item
2371           $replace.= "<item>";
2373           # Add flat hash information
2374           my @entries= ( "priority", "onceScript", "licenseRequired", "packageVersion", "productVersion", "advice",
2375                               "setupScript", "windowsSoftwareIds", "installationStatus", "pxeConfigTemplate", "name", "type",
2376                               "creationTimestamp", "alwaysScript", "productId", "description", "actionRequest", "uninstallScript",
2377                               "action", "updateScript", "productClassNames");
2378           foreach my $entry (@entries) {
2379             if (defined $product->{$entry}) {
2380               my $value= $product->{$entry};
2382               if(ref($value) eq 'ARRAY'){
2383                 my $tmp= "";
2384                 foreach my $element (@$value) {
2385                   $tmp.= "<element>$element</element>";
2386                 }
2387                 $replace.= "<$entry>$tmp</$entry>";
2388               } else {
2389                 $replace.= "<$entry>$value</$entry>";
2390               }
2391             }
2392           }
2394           # Add property information
2395           if (defined $product->{'properties'}) {
2396             $replace.= "<properties>";
2397             while ((my $key, my $value) = each(%{$product->{'properties'}})){
2398               $replace.= "<$key>";
2400               while ((my $pkey, my $pvalue) = each(%$value)){
2401                 if(ref($pvalue) eq 'ARRAY'){
2402                   my $tmp= "";
2403                   foreach my $element (@$pvalue) {
2404                     $tmp.= "<element>$element</element>";
2405                   }
2406                   $replace.= "<$pkey>$tmp</$pkey>";
2407                 } else {
2408                   $replace.= "<$pkey>$pvalue</$pkey>";
2409                 }
2410               }
2411               $replace.= "</$key>";
2412             }
2413             $replace.= "</properties>";
2414           }
2416           # Close item
2417           $replace.= "</item>";
2418         }
2420         $xml_msg=~ s/<xxx><\/xxx>/\n$replace/;
2422         &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
2423     return ( $xml_msg );
2427 sub opsi_test {
2428     my ($msg, $msg_hash, $session_id) = @_;
2429     my $header = @{$msg_hash->{'header'}}[0];
2430     my $source = @{$msg_hash->{'source'}}[0];
2431         my $pram1 = @{$msg_hash->{'productId'}}[0];
2434         # Fetch infos from Opsi server
2435     my $callobj = {
2436         method  => 'getLicensePoolId',
2437         params  => [ $pram1 ],
2438         id  => 1,
2439     };
2440     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
2442         return ();
2446 # ----------------------------------------------------------------------------
2447 #  internal methods handling the comunication with Opsi
2448 # ----------------------------------------------------------------------------
2450 ################################
2451 # @brief Checks if there is a specified tag and if the the tag has a content.
2452 sub _check_xml_tag_is_ok {
2453         my ($msg_hash,$tag) = @_;
2454         if (not defined $msg_hash->{$tag}) {
2455                 $_ = "message contains no tag '$tag'";
2456                 return 0;
2457         }
2458         if (ref @{$msg_hash->{$tag}}[0] eq 'HASH') {
2459                 $_ = "message tag '$tag' has no content";
2460                 return  0;
2461         }
2462         return 1;
2465 ################################
2466 # @brief Writes the log line and returns the error message for GOsa.
2467 sub _giveErrorFeedback {
2468         my ($msg_hash, $err_string, $session_id) = @_;
2469         &main::daemon_log("$session_id ERROR: $err_string", 1);
2470         my $out_hash = &main::create_xml_hash("error", $main::server_address, @{$msg_hash->{source}}[0], $err_string);
2471     if (exists $msg_hash->{forward_to_gosa}) {
2472         &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]);
2473     }
2474         return ( &create_xml_string($out_hash) );
2478 ################################
2479 # @brief Perform the call to the Opsi server and measure the time for the call
2480 sub _callOpsi {
2481         my %arg = ('method'=>undef, 'params'=>[], 'id'=>1, @_);
2483         my $callObject = {
2484                 method => $arg{method},
2485                 params => $arg{params},
2486                 id => $arg{id},
2487         };
2489         my $startTime = Time::HiRes::time;
2490         my $opsiResult = $opsi_client->call($opsi_url, $callObject);
2491         my $endTime = Time::HiRes::time;
2492         my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2494         &main::daemon_log("0 DEBUG: time to process opsi call '$arg{method}' : $elapsedTime seconds", 1034); 
2496         return $opsiResult;
2499 sub _getLicensePool_hash {
2500         my %arg = ( 'licensePoolId' => undef, @_ );
2502         if (not defined $arg{licensePoolId} ) { 
2503                 return ("function requires licensePoolId as parameter", 1);
2504         }
2506         my $res = &_callOpsi( method  => 'getLicensePool_hash', params =>[$arg{licensePoolId}], id  => 1 );
2507         my ($res_error, $res_error_str) = &check_opsi_res($res);
2508         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2510         return ($res->result, 0);
2513 sub _getSoftwareLicenses_listOfHashes {
2514         
2515         my $res = &_callOpsi( method  => 'getSoftwareLicenses_listOfHashes' );
2516         my ($res_error, $res_error_str) = &check_opsi_res($res);
2517         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2519         return ($res->result, 0);
2522 sub _getSoftwareLicenseUsages_listOfHashes {
2523         my %arg = ( 'hostId' => "", 'licensePoolId' => "", @_ );
2525         my $res = &_callOpsi( method=>'getSoftwareLicenseUsages_listOfHashes', params=>[ $arg{hostId}, $arg{licensePoolId} ] );
2526         my ($res_error, $res_error_str) = &check_opsi_res($res);
2527         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2529         return ($res->result, 0);
2532 sub _removeSoftwareLicenseFromLicensePool {
2533         my %arg = ( 'softwareLicenseId' => undef, 'licensePoolId' => undef, @_ );
2535         if (not defined $arg{softwareLicenseId} ) { 
2536                 return ("function requires softwareLicenseId as parameter", 1);
2537                 }
2538                 if (not defined $arg{licensePoolId} ) { 
2539                 return ("function requires licensePoolId as parameter", 1);
2540         }
2542         my $res = &_callOpsi( method=>'removeSoftwareLicenseFromLicensePool', params=>[ $arg{softwareLicenseId}, $arg{licensePoolId} ] );
2543         my ($res_error, $res_error_str) = &check_opsi_res($res);
2544         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2546         return ($res->result, 0);
2549 sub _deleteSoftwareLicense {
2550         my %arg = ( 'softwareLicenseId' => undef, 'removeFromPools' => "false", @_ );
2552         if (not defined $arg{softwareLicenseId} ) { 
2553                 return ("function requires softwareLicenseId as parameter", 1);
2554         }
2555         my $removeFromPools = "";
2556         if ((defined $arg{removeFromPools}) && ($arg{removeFromPools} eq "true")) { 
2557                 $removeFromPools = "removeFromPools";
2558         }
2560         my $res = &_callOpsi( method=>'deleteSoftwareLicense', params=>[ $arg{softwareLicenseId}, $removeFromPools ] );
2561         my ($res_error, $res_error_str) = &check_opsi_res($res);
2562         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2564         return ($res->result, 0);
2567 sub _getLicensePoolId {
2568         my %arg = ( 'productId' => undef, @_ );
2569         
2570         if (not defined $arg{productId} ) {
2571                 return ("function requires productId as parameter", 1);
2572         }
2574     my $res = &_callOpsi( method  => 'getLicensePoolId', params  => [ $arg{productId} ] );
2575         my ($res_error, $res_error_str) = &check_opsi_res($res);
2576         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2578         return ($res->result, 0);
2581 sub _getLicenseContract_hash {
2582         my %arg = ( 'licenseContractId' => undef, @_ );
2583         
2584         if (not defined $arg{licenseContractId} ) {
2585                 return ("function requires licenseContractId as parameter", 1);
2586         }
2588     my $res = &_callOpsi( method  => 'getLicenseContract_hash', params  => [ $arg{licenseContractId} ] );
2589         my ($res_error, $res_error_str) = &check_opsi_res($res);
2590         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2592         return ($res->result, 0);
2595 sub _createLicenseContract {
2596         my %arg = (
2597                         'licenseContractId' => undef,
2598                         'partner' => undef,
2599                         'conclusionDate' => undef,
2600                         'notificationDate' => undef,
2601                         'expirationDate' => undef,
2602                         'notes' => undef,
2603                         @_ );
2605         my $res = &_callOpsi( method  => 'createLicenseContract', 
2606                         params  => [ $arg{licenseContractId}, $arg{partner}, $arg{conclusionDate}, $arg{notificationDate}, $arg{expirationDate}, $arg{notes} ],
2607                         );
2608         my ($res_error, $res_error_str) = &check_opsi_res($res);
2609         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2611         return ($res->result, 0);
2614 sub _createSoftwareLicense {
2615         my %arg = (
2616                         'softwareLicenseId' => undef,
2617                         'licenseContractId' => undef,
2618                         'licenseType' => undef,
2619                         'maxInstallations' => undef,
2620                         'boundToHost' => undef,
2621                         'expirationDate' => undef,
2622                         @_ );
2624     my $res = &_callOpsi( method  => 'createSoftwareLicense',
2625         params  => [ $arg{softwareLicenseId}, $arg{licenseContractId}, $arg{licenseType}, $arg{maxInstallations}, $arg{boundToHost}, $arg{expirationDate} ],
2626                 );
2627         my ($res_error, $res_error_str) = &check_opsi_res($res);
2628         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2630         return ($res->result, 0);
2633 sub _addSoftwareLicenseToLicensePool {
2634         my %arg = (
2635             'softwareLicenseId' => undef,
2636             'licensePoolId' => undef,
2637             'licenseKey' => undef,
2638             @_ );
2640         if (not defined $arg{softwareLicenseId} ) {
2641                 return ("function requires softwareLicenseId as parameter", 1);
2642         }
2643         if (not defined $arg{licensePoolId} ) {
2644                 return ("function requires licensePoolId as parameter", 1);
2645         }
2647         my $res = &_callOpsi( method  => 'addSoftwareLicenseToLicensePool', params  => [ $arg{softwareLicenseId}, $arg{licensePoolId}, $arg{licenseKey} ] );
2648         my ($res_error, $res_error_str) = &check_opsi_res($res);
2649         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2651         return ($res->result, 0);
2654 sub _getProductStates_hash {
2655         my %arg = (     'hostId' => undef, @_ );
2657         if (not defined $arg{hostId} ) {
2658                 return ("function requires hostId as parameter", 1);
2659         }
2661         my $res = &_callOpsi( method => 'getProductStates_hash', params => [$arg{hostId}]);
2662         my ($res_error, $res_error_str) = &check_opsi_res($res);
2663         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2665         return ($res->result, 0);
2668 sub _get_full_product_host_information {
2669         my %arg = ( 'hostId' => undef, @_ );
2671         my $res = &_callOpsi( method => 'getFullProductHostInformation_list',  params => [$arg{hostId}]);
2672         my ($res_error, $res_error_str) = &check_opsi_res($res);
2673         if ($res_error){ return ((caller(0))[3]." : ".$res_error_str, 1); }
2675         return ($res->result, 0);
2678 1;