Code

add contract data to returned data of opsi_com.pm::getPool
[gosa.git] / gosa-si / server / events / opsi_com.pm
1 ## @file
2 # @details A GOsa-SI-server event module containing all functions for message handling.
3 # @brief Implementation of an event module for GOsa-SI-server. 
6 package opsi_com;
7 use Exporter;
8 @ISA = qw(Exporter);
9 my @events = (
10     "get_events",
11     "opsi_install_client",
12     "opsi_get_netboot_products",  
13     "opsi_get_local_products",
14     "opsi_get_client_hardware",
15     "opsi_get_client_software",
16     "opsi_get_product_properties",
17     "opsi_set_product_properties",
18     "opsi_list_clients",
19     "opsi_del_client",
20     "opsi_add_client",
21     "opsi_modify_client",
22     "opsi_add_product_to_client",
23     "opsi_del_product_from_client",
24         "opsi_createLicensePool",
25         "opsi_deleteLicensePool",
26         "opsi_createLicense",
27         "opsi_assignSoftwareLicenseToHost",
28         "opsi_unassignSoftwareLicenseFromHost",
29         "opsi_unassignAllSoftwareLicensesFromHost",
30         "opsi_getSoftwareLicense_hash",
31         "opsi_getLicensePool_hash",
32         "opsi_getSoftwareLicenseUsages",
33         "opsi_getSoftwareLicenseUsagesForProductId",
34         "opsi_getLicensePools_listOfHashes",
35         "opsi_getLicenseInformationForProduct",
36         "opsi_getPool",
37         "opsi_removeLicense",
38         "opsi_getReservedLicenses",
39         "opsi_test",
40    );
41 @EXPORT = @events;
43 use strict;
44 use warnings;
45 use GOSA::GosaSupportDaemon;
46 use Data::Dumper;
47 use XML::Quote qw(:all);
49 BEGIN {}
51 END {}
53 # ----------------------------------------------------------------------------
54 #                          D E C L A R A T I O N S
55 # ----------------------------------------------------------------------------
57 my $licenseTyp_hash = { 'OEM'=>'', 'VOLUME'=>'', 'RETAIL'=>''};
61 # ----------------------------------------------------------------------------
62 #                            S U B R O U T I N E S
63 # ----------------------------------------------------------------------------
66 ################################
67 #
68 # @brief A function returning a list of functions which are exported by importing the module.
69 # @return List of all provided functions
70 #
71 sub get_events {
72     return \@events;
73 }
75 ################################
76 #
77 # @brief Checks if there is a specified tag and if the the tag has a content.
78 # @return 0|1
79 #
80 sub _check_xml_tag_is_ok {
81         my ($msg_hash,$tag) = @_;
82         if (not defined $msg_hash->{$tag}) {
83                 $_ = "message contains no tag '$tag'";
84                 return 0;
85         }
86         if (ref @{$msg_hash->{$tag}}[0] eq 'HASH') {
87                 $_ = "message tag '$tag' has no content";
88                 return  0;
89         }
90         return 1;
91 }
93 ################################
94 #
95 # @brief Writes the log line and returns the error message for GOsa.
96 #
97 sub _give_feedback {
98         my ($msg, $msg_hash, $session_id, $error) = @_;
99         &main::daemon_log("$session_id ERROR: $error: ".$msg, 1);
100         my $out_hash = &main::create_xml_hash("error", $main::server_address, @{$msg_hash->{'source'}}[0], $error);
101         return &create_xml_string($out_hash);
104 ## @method opsi_add_product_to_client
105 # Adds an Opsi product to an Opsi client.
106 # @param msg - STRING - xml message with tags hostId and productId
107 # @param msg_hash - HASHREF - message information parsed into a hash
108 # @param session_id - INTEGER - POE session id of the processing of this message
109 # @return out_msg - STRING - feedback to GOsa in success and error case
110 sub opsi_add_product_to_client {
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];
116     my ($hostId, $productId);
117     my $error = 0;
119     # Build return message
120     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
121     if (defined $forward_to_gosa) {
122         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
123     }
125     # Sanity check of needed parameter
126     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
127         $error++;
128         &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
129         &add_content2xml_hash($out_hash, "error", "hostId");
130         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
132     }
133     if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
134         $error++;
135         &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
136         &add_content2xml_hash($out_hash, "error", "productId");
137         &main::daemon_log("$session_id ERROR: no productId specified or procutId tag invalid: $msg", 1); 
138     }
140     if (not $error) {
141         # Get hostId
142         $hostId = @{$msg_hash->{'hostId'}}[0];
143         &add_content2xml_hash($out_hash, "hostId", $hostId);
145         # Get productID
146         $productId = @{$msg_hash->{'productId'}}[0];
147         &add_content2xml_hash($out_hash, "productId", $productId);
149         # Do an action request for all these -> "setup".
150         my $callobj = {
151             method  => 'setProductActionRequest',
152             params  => [ $productId, $hostId, "setup" ],
153             id  => 1, }; 
155         my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
156         my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
157         if ($sres_err){
158             &main::daemon_log("$session_id ERROR: cannot add product: ".$sres_err_string, 1);
159             &add_content2xml_hash($out_hash, "error", $sres_err_string);
160         }
161     } 
163     # return message
164     return ( &create_xml_string($out_hash) );
167 ## @method opsi_del_product_from_client
168 # Deletes an Opsi-product from an Opsi-client. 
169 # @param msg - STRING - xml message with tags hostId and productId
170 # @param msg_hash - HASHREF - message information parsed into a hash
171 # @param session_id - INTEGER - POE session id of the processing of this message
172 # @return out_msg - STRING - feedback to GOsa in success and error case
173 sub opsi_del_product_from_client {
174     my ($msg, $msg_hash, $session_id) = @_;
175     my $header = @{$msg_hash->{'header'}}[0];
176     my $source = @{$msg_hash->{'source'}}[0];
177     my $target = @{$msg_hash->{'target'}}[0];
178     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
179     my ($hostId, $productId);
180     my $error = 0;
181     my ($sres, $sres_err, $sres_err_string);
183     # Build return message
184     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
185     if (defined $forward_to_gosa) {
186         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
187     }
189     # Sanity check of needed parameter
190     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
191         $error++;
192         &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
193         &add_content2xml_hash($out_hash, "error", "hostId");
194         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
196     }
197     if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
198         $error++;
199         &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
200         &add_content2xml_hash($out_hash, "error", "productId");
201         &main::daemon_log("$session_id ERROR: no productId specified or procutId tag invalid: $msg", 1); 
202     }
204     # All parameter available
205     if (not $error) {
206         # Get hostId
207         $hostId = @{$msg_hash->{'hostId'}}[0];
208         &add_content2xml_hash($out_hash, "hostId", $hostId);
210         # Get productID
211         $productId = @{$msg_hash->{'productId'}}[0];
212         &add_content2xml_hash($out_hash, "productId", $productId);
215 # : check the results for more than one entry which is currently installed
216         #$callobj = {
217         #    method  => 'getProductDependencies_listOfHashes',
218         #    params  => [ $productId ],
219         #    id  => 1, };
220         #
221         #my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
222         #my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
223         #if ($sres_err){
224         #  &main::daemon_log("ERROR: cannot perform dependency check: ".$sres_err_string, 1);
225         #  &add_content2xml_hash($out_hash, "error", $sres_err_string);
226         #  return ( &create_xml_string($out_hash) );
227         #}
230         # Check to get product action list 
231         my $callobj = {
232             method  => 'getPossibleProductActions_list',
233             params  => [ $productId ],
234             id  => 1, };
235         $sres = $main::opsi_client->call($main::opsi_url, $callobj);
236         ($sres_err, $sres_err_string) = &check_opsi_res($sres);
237         if ($sres_err){
238             &main::daemon_log("$session_id ERROR: cannot get product action list: ".$sres_err_string, 1);
239             &add_content2xml_hash($out_hash, "error", $sres_err_string);
240             $error++;
241         }
242     }
244     # Check action uninstall of product
245     if (not $error) {
246         my $uninst_possible= 0;
247         foreach my $r (@{$sres->result}) {
248             if ($r eq 'uninstall') {
249                 $uninst_possible= 1;
250             }
251         }
252         if (!$uninst_possible){
253             &main::daemon_log("$session_id ERROR: cannot uninstall product '$productId', product do not has the action 'uninstall'", 1);
254             &add_content2xml_hash($out_hash, "error", "cannot uninstall product '$productId', product do not has the action 'uninstall'");
255             $error++;
256         }
257     }
259     # Set product state to "none"
260     # Do an action request for all these -> "setup".
261     if (not $error) {
262         my $callobj = {
263             method  => 'setProductActionRequest',
264             params  => [ $productId, $hostId, "none" ],
265             id  => 1, 
266         }; 
267         $sres = $main::opsi_client->call($main::opsi_url, $callobj);
268         ($sres_err, $sres_err_string) = &check_opsi_res($sres);
269         if ($sres_err){
270             &main::daemon_log("$session_id ERROR: cannot delete product: ".$sres_err_string, 1);
271             &add_content2xml_hash($out_hash, "error", $sres_err_string);
272         }
273     }
275     # Return message
276     return ( &create_xml_string($out_hash) );
279 ## @method opsi_add_client
280 # Adds an Opsi client to Opsi.
281 # @param msg - STRING - xml message with tags hostId and macaddress
282 # @param msg_hash - HASHREF - message information parsed into a hash
283 # @param session_id - INTEGER - POE session id of the processing of this message
284 # @return out_msg - STRING - feedback to GOsa in success and error case
285 sub opsi_add_client {
286     my ($msg, $msg_hash, $session_id) = @_;
287     my $header = @{$msg_hash->{'header'}}[0];
288     my $source = @{$msg_hash->{'source'}}[0];
289     my $target = @{$msg_hash->{'target'}}[0];
290     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
291     my ($hostId, $mac);
292     my $error = 0;
293     my ($sres, $sres_err, $sres_err_string);
295     # Build return message with twisted target and source
296     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
297     if (defined $forward_to_gosa) {
298         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
299     }
301     # Sanity check of needed parameter
302     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
303         $error++;
304         &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
305         &add_content2xml_hash($out_hash, "error", "hostId");
306         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
307     }
308     if ((not exists $msg_hash->{'macaddress'}) || (@{$msg_hash->{'macaddress'}} != 1) || (@{$msg_hash->{'macaddress'}}[0] eq ref 'HASH'))  {
309         $error++;
310         &add_content2xml_hash($out_hash, "error_string", "no macaddress specified or macaddress tag invalid");
311         &add_content2xml_hash($out_hash, "error", "macaddress");
312         &main::daemon_log("$session_id ERROR: no macaddress specified or macaddress tag invalid: $msg", 1); 
313     }
315     if (not $error) {
316         # Get hostId
317         $hostId = @{$msg_hash->{'hostId'}}[0];
318         &add_content2xml_hash($out_hash, "hostId", $hostId);
320         # Get macaddress
321         $mac = @{$msg_hash->{'macaddress'}}[0];
322         &add_content2xml_hash($out_hash, "macaddress", $mac);
324         my $name= $hostId;
325         $name=~ s/^([^.]+).*$/$1/;
326         my $domain= $hostId;
327         $domain=~ s/^[^.]+\.(.*)$/$1/;
328         my ($description, $notes, $ip);
330         if (defined @{$msg_hash->{'description'}}[0]){
331             $description = @{$msg_hash->{'description'}}[0];
332         }
333         if (defined @{$msg_hash->{'notes'}}[0]){
334             $notes = @{$msg_hash->{'notes'}}[0];
335         }
336         if (defined @{$msg_hash->{'ip'}}[0]){
337             $ip = @{$msg_hash->{'ip'}}[0];
338         }
340         my $callobj;
341         $callobj = {
342             method  => 'createClient',
343             params  => [ $name, $domain, $description, $notes, $ip, $mac ],
344             id  => 1,
345         };
347         $sres = $main::opsi_client->call($main::opsi_url, $callobj);
348         ($sres_err, $sres_err_string) = &check_opsi_res($sres);
349         if ($sres_err){
350             &main::daemon_log("$session_id ERROR: cannot create client: ".$sres_err_string, 1);
351             &add_content2xml_hash($out_hash, "error", $sres_err_string);
352         } else {
353             &main::daemon_log("$session_id INFO: add opsi client '$hostId' with mac '$mac'", 5); 
354         }
355     }
357     # Return message
358     return ( &create_xml_string($out_hash) );
361 ## @method opsi_modify_client
362 # Modifies the parameters description, mac or notes for an Opsi client if the corresponding message tags are given.
363 # @param msg - STRING - xml message with tag hostId and optional description, mac or notes
364 # @param msg_hash - HASHREF - message information parsed into a hash
365 # @param session_id - INTEGER - POE session id of the processing of this message    
366 # @return out_msg - STRING - feedback to GOsa in success and error case
367 sub opsi_modify_client {
368     my ($msg, $msg_hash, $session_id) = @_;
369     my $header = @{$msg_hash->{'header'}}[0];
370     my $source = @{$msg_hash->{'source'}}[0];
371     my $target = @{$msg_hash->{'target'}}[0];
372     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
373     my $hostId;
374     my $error = 0;
375     my ($sres, $sres_err, $sres_err_string);
377     # Build return message with twisted target and source
378     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
379     if (defined $forward_to_gosa) {
380         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
381     }
383     # Sanity check of needed parameter
384     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
385         $error++;
386         &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
387         &add_content2xml_hash($out_hash, "error", "hostId");
388         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
389     }
391     if (not $error) {
392         # Get hostId
393         $hostId = @{$msg_hash->{'hostId'}}[0];
394         &add_content2xml_hash($out_hash, "hostId", $hostId);
395         my $name= $hostId;
396         $name=~ s/^([^.]+).*$/$1/;
397         my $domain= $hostId;
398         $domain=~ s/^[^.]+(.*)$/$1/;
400         # Modify description, notes or mac if defined
401         my ($description, $notes, $mac);
402         my $callobj;
403         if ((exists $msg_hash->{'description'}) && (@{$msg_hash->{'description'}} == 1) ){
404             $description = @{$msg_hash->{'description'}}[0];
405             $callobj = {
406                 method  => 'setHostDescription',
407                 params  => [ $hostId, $description ],
408                 id  => 1,
409             };
410             my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
411             my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
412             if ($sres_err){
413                 &main::daemon_log("ERROR: cannot set description: ".$sres_err_string, 1);
414                 &add_content2xml_hash($out_hash, "error", $sres_err_string);
415             }
416         }
417         if ((exists $msg_hash->{'notes'}) && (@{$msg_hash->{'notes'}} == 1)) {
418             $notes = @{$msg_hash->{'notes'}}[0];
419             $callobj = {
420                 method  => 'setHostNotes',
421                 params  => [ $hostId, $notes ],
422                 id  => 1,
423             };
424             my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
425             my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
426             if ($sres_err){
427                 &main::daemon_log("ERROR: cannot set notes: ".$sres_err_string, 1);
428                 &add_content2xml_hash($out_hash, "error", $sres_err_string);
429             }
430         }
431         if ((exists $msg_hash->{'mac'}) && (@{$msg_hash->{'mac'}} == 1)){
432             $mac = @{$msg_hash->{'mac'}}[0];
433             $callobj = {
434                 method  => 'setMacAddress',
435                 params  => [ $hostId, $mac ],
436                 id  => 1,
437             };
438             my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
439             my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
440             if ($sres_err){
441                 &main::daemon_log("ERROR: cannot set mac address: ".$sres_err_string, 1);
442                 &add_content2xml_hash($out_hash, "error", $sres_err_string);
443             }
444         }
445     }
447     # Return message
448     return ( &create_xml_string($out_hash) );
451     
452 ## @method opsi_get_netboot_products
453 # Get netboot products for specific host.
454 # @param msg - STRING - xml message with tag hostId
455 # @param msg_hash - HASHREF - message information parsed into a hash
456 # @param session_id - INTEGER - POE session id of the processing of this message
457 # @return out_msg - STRING - feedback to GOsa in success and error case
458 sub opsi_get_netboot_products {
459     my ($msg, $msg_hash, $session_id) = @_;
460     my $header = @{$msg_hash->{'header'}}[0];
461     my $source = @{$msg_hash->{'source'}}[0];
462     my $target = @{$msg_hash->{'target'}}[0];
463     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
464     my $hostId;
465     my $xml_msg;
467     # Build return message with twisted target and source
468     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
469     if (defined $forward_to_gosa) {
470         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
471     }
473     # Get hostId if defined
474     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1))  {
475         $hostId = @{$msg_hash->{'hostId'}}[0];
476         &add_content2xml_hash($out_hash, "hostId", $hostId);
477     }
479     &add_content2xml_hash($out_hash, "xxx", "");
480     $xml_msg = &create_xml_string($out_hash);
481     # For hosts, only return the products that are or get installed
482     my $callobj;
483     $callobj = {
484         method  => 'getNetBootProductIds_list',
485         params  => [ ],
486         id  => 1,
487     };
488     &main::daemon_log("$session_id DEBUG: send callobj to opsi_client: ".&opsi_callobj2string($callobj), 7);
489     &main::daemon_log("$session_id DEBUG: opsi_url $main::opsi_url", 7);
490     &main::daemon_log("$session_id DEBUG: waiting for answer from opsi_client!", 7);
491     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
492     &main::daemon_log("$session_id DEBUG: get answer from opsi_client", 7);
493     my %r = ();
494     for (@{$res->result}) { $r{$_} = 1 }
496     if (not &check_opsi_res($res)){
498         if (defined $hostId){
500             $callobj = {
501                 method  => 'getProductStates_hash',
502                 params  => [ $hostId ],
503                 id  => 1,
504             };
506             my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
507             if (not &check_opsi_res($hres)){
508                 my $htmp= $hres->result->{$hostId};
510                 # check state != not_installed or action == setup -> load and add
511                 foreach my $product (@{$htmp}){
513                     if (!defined ($r{$product->{'productId'}})){
514                         next;
515                     }
517                     # Now we've a couple of hashes...
518                     if ($product->{'installationStatus'} ne "not_installed" or
519                             $product->{'actionRequest'} eq "setup"){
520                         my $state= "<state>".$product->{'installationStatus'}."</state><action>".$product->{'actionRequest'}."</action>";
522                         $callobj = {
523                             method  => 'getProduct_hash',
524                             params  => [ $product->{'productId'} ],
525                             id  => 1,
526                         };
528                         my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
529                         if (not &check_opsi_res($sres)){
530                             my $tres= $sres->result;
532                             my $name= xml_quote($tres->{'name'});
533                             my $r= $product->{'productId'};
534                             my $description= xml_quote($tres->{'description'});
535                             $name=~ s/\//\\\//;
536                             $description=~ s/\//\\\//;
537                             $xml_msg=~ s/<xxx><\/xxx>/\n<item><productId>$r<\/productId><name>$name<\/name><description>$description<\/description><\/item>$state<xxx><\/xxx>/;
538                         }
539                     }
540                 }
542             }
544         } else {
545             foreach my $r (@{$res->result}) {
546                 $callobj = {
547                     method  => 'getProduct_hash',
548                     params  => [ $r ],
549                     id  => 1,
550                 };
552                 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
553                 if (not &check_opsi_res($sres)){
554                     my $tres= $sres->result;
556                     my $name= xml_quote($tres->{'name'});
557                     my $description= xml_quote($tres->{'description'});
558                     $name=~ s/\//\\\//;
559                     $description=~ s/\//\\\//;
560                     $xml_msg=~ s/<xxx><\/xxx>/\n<item><productId>$r<\/productId><name>$name<\/name><description>$description<\/description><\/item><xxx><\/xxx>/;
561                 }
562             }
564         }
565     }
566     $xml_msg=~ s/<xxx><\/xxx>//;
568     # Return message
569     return ( $xml_msg );
573 ## @method opsi_get_product_properties
574 # Get product properties for a product and a specific host or gobally for a product.
575 # @param msg - STRING - xml message with tags productId and optional hostId
576 # @param msg_hash - HASHREF - message information parsed into a hash
577 # @param session_id - INTEGER - POE session id of the processing of this message
578 # @return out_msg - STRING - feedback to GOsa in success and error case
579 sub opsi_get_product_properties {
580     my ($msg, $msg_hash, $session_id) = @_;
581     my $header = @{$msg_hash->{'header'}}[0];
582     my $source = @{$msg_hash->{'source'}}[0];
583     my $target = @{$msg_hash->{'target'}}[0];
584     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
585     my ($hostId, $productId);
586     my $xml_msg;
588     # Build return message with twisted target and source
589     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
590     if (defined $forward_to_gosa) {
591         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
592     }
594     # Sanity check of needed parameter
595     if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH'))  {
596         &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
597         &add_content2xml_hash($out_hash, "error", "productId");
598         &main::daemon_log("$session_id ERROR: no productId specified or productId tag invalid: $msg", 1); 
600         # Return message
601         return ( &create_xml_string($out_hash) );
602     }
604     # Get productid
605     $productId = @{$msg_hash->{'productId'}}[0];
606     &add_content2xml_hash($out_hash, "producId", "$productId");
608     # Get hostId if defined
609     if (defined @{$msg_hash->{'hostId'}}[0]){
610       $hostId = @{$msg_hash->{'hostId'}}[0];
611       &add_content2xml_hash($out_hash, "hostId", $hostId);
612     }
614     # Load actions
615     my $callobj = {
616       method  => 'getPossibleProductActions_list',
617       params  => [ $productId ],
618       id  => 1,
619     };
620     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
621     if (not &check_opsi_res($res)){
622       foreach my $action (@{$res->result}){
623         &add_content2xml_hash($out_hash, "action", $action);
624       }
625     }
627     # Add place holder
628     &add_content2xml_hash($out_hash, "xxx", "");
630     # Move to XML string
631     $xml_msg= &create_xml_string($out_hash);
633     # JSON Query
634     if (defined $hostId){
635       $callobj = {
636           method  => 'getProductProperties_hash',
637           params  => [ $productId, $hostId ],
638           id  => 1,
639       };
640     } else {
641       $callobj = {
642           method  => 'getProductProperties_hash',
643           params  => [ $productId ],
644           id  => 1,
645       };
646     }
647     $res = $main::opsi_client->call($main::opsi_url, $callobj);
649     # JSON Query 2
650     $callobj = {
651       method  => 'getProductPropertyDefinitions_listOfHashes',
652       params  => [ $productId ],
653       id  => 1,
654     };
656     # Assemble options
657     my $res2 = $main::opsi_client->call($main::opsi_url, $callobj);
658     my $values = {};
659     my $descriptions = {};
660     if (not &check_opsi_res($res2)){
661         my $r= $res2->result;
663           foreach my $entr (@$r){
664             # Unroll values
665             my $cnv;
666             if (UNIVERSAL::isa( $entr->{'values'}, "ARRAY" )){
667               foreach my $v (@{$entr->{'values'}}){
668                 $cnv.= "<value>$v</value>";
669               }
670             } else {
671               $cnv= $entr->{'values'};
672             }
673             $values->{$entr->{'name'}}= $cnv;
674             $descriptions->{$entr->{'name'}}= "<description>".$entr->{'description'}."</description>";
675           }
676     }
678     if (not &check_opsi_res($res)){
679         my $r= $res->result;
680         foreach my $key (keys %{$r}) {
681             my $item= "\n<item>";
682             my $value= $r->{$key};
683             my $dsc= "";
684             my $vals= "";
685             if (defined $descriptions->{$key}){
686               $dsc= $descriptions->{$key};
687             }
688             if (defined $values->{$key}){
689               $vals= $values->{$key};
690             }
691             $item.= "<$key>$dsc<default>".xml_quote($value)."</default>$vals</$key>";
692             $item.= "</item>";
693             $xml_msg=~ s/<xxx><\/xxx>/$item<xxx><\/xxx>/;
694         }
695     }
697     $xml_msg=~ s/<xxx><\/xxx>//;
699     # Return message
700     return ( $xml_msg );
704 ## @method opsi_set_product_properties
705 # 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.
706 # @param msg - STRING - xml message with tags productId, action, state and optional hostId, action and state
707 # @param msg_hash - HASHREF - message information parsed into a hash
708 # @param session_id - INTEGER - POE session id of the processing of this message
709 # @return out_msg - STRING - feedback to GOsa in success and error case
710 sub opsi_set_product_properties {
711     my ($msg, $msg_hash, $session_id) = @_;
712     my $header = @{$msg_hash->{'header'}}[0];
713     my $source = @{$msg_hash->{'source'}}[0];
714     my $target = @{$msg_hash->{'target'}}[0];
715     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
716     my ($productId, $hostId);
718     # Build return message with twisted target and source
719     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
720     if (defined $forward_to_gosa) {
721         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
722     }
724     # Sanity check of needed parameter
725     if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH'))  {
726         &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
727         &add_content2xml_hash($out_hash, "error", "productId");
728         &main::daemon_log("$session_id ERROR: no productId specified or productId tag invalid: $msg", 1); 
729         return ( &create_xml_string($out_hash) );
730     }
731     if (not exists $msg_hash->{'item'}) {
732         &add_content2xml_hash($out_hash, "error_string", "message needs one xml-tag 'item' and within the xml-tags 'name' and 'value'");
733         &add_content2xml_hash($out_hash, "error", "item");
734         &main::daemon_log("$session_id ERROR: message needs one xml-tag 'item' and within the xml-tags 'name' and 'value': $msg", 1); 
735         return ( &create_xml_string($out_hash) );
736     } else {
737         if ((not exists @{$msg_hash->{'item'}}[0]->{'name'}) || (@{@{$msg_hash->{'item'}}[0]->{'name'}} != 1 )) {
738             &add_content2xml_hash($out_hash, "error_string", "message needs within the xml-tag 'item' one xml-tags 'name'");
739             &add_content2xml_hash($out_hash, "error", "name");
740             &main::daemon_log("$session_id ERROR: message needs within the xml-tag 'item' one xml-tags 'name': $msg", 1); 
741             return ( &create_xml_string($out_hash) );
742         }
743         if ((not exists @{$msg_hash->{'item'}}[0]->{'value'}) || (@{@{$msg_hash->{'item'}}[0]->{'value'}} != 1 )) {
744             &add_content2xml_hash($out_hash, "error_string", "message needs within the xml-tag 'item' one xml-tags 'value'");
745             &add_content2xml_hash($out_hash, "error", "value");
746             &main::daemon_log("$session_id ERROR: message needs within the xml-tag 'item' one xml-tags 'value': $msg", 1); 
747             return ( &create_xml_string($out_hash) );
748         }
749     }
750     # if no hostId is given, set_product_properties will act on globally
751     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} > 1))  {
752         &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
753         &add_content2xml_hash($out_hash, "error", "hostId");
754         &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1); 
755         return ( &create_xml_string($out_hash) );
756     }
758         
759     # Get productId
760     $productId =  @{$msg_hash->{'productId'}}[0];
761     &add_content2xml_hash($out_hash, "productId", $productId);
763     # Get hostId if defined
764     if (exists $msg_hash->{'hostId'}){
765         $hostId = @{$msg_hash->{'hostId'}}[0];
766         &add_content2xml_hash($out_hash, "hostId", $hostId);
767     }
769     # Set product states if requested
770     if (defined @{$msg_hash->{'action'}}[0]){
771         &_set_action($productId, @{$msg_hash->{'action'}}[0], $hostId);
772     }
773     if (defined @{$msg_hash->{'state'}}[0]){
774         &_set_state($productId, @{$msg_hash->{'state'}}[0], $hostId);
775     }
777     # Find properties
778     foreach my $item (@{$msg_hash->{'item'}}){
779         # JSON Query
780         my $callobj;
782         if (defined $hostId){
783             $callobj = {
784                 method  => 'setProductProperty',
785                 params  => [ $productId, $item->{'name'}[0], $item->{'value'}[0], $hostId ],
786                 id  => 1,
787             };
788         } else {
789             $callobj = {
790                 method  => 'setProductProperty',
791                 params  => [ $productId, $item->{'name'}[0], $item->{'value'}[0] ],
792                 id  => 1,
793             };
794         }
796         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
797         my ($res_err, $res_err_string) = &check_opsi_res($res);
799         if ($res_err){
800             &main::daemon_log("$session_id ERROR: communication failed while setting '".$item->{'name'}[0]."': ".$res_err_string, 1);
801             &add_content2xml_hash($out_hash, "error", $res_err_string);
802         }
803     }
806     # Return message
807     return ( &create_xml_string($out_hash) );
811 ## @method opsi_get_client_hardware
812 # Reports client hardware inventory.
813 # @param msg - STRING - xml message with tag hostId
814 # @param msg_hash - HASHREF - message information parsed into a hash
815 # @param session_id - INTEGER - POE session id of the processing of this message
816 # @return out_msg - STRING - feedback to GOsa in success and error case
817 sub opsi_get_client_hardware {
818     my ($msg, $msg_hash, $session_id) = @_;
819     my $header = @{$msg_hash->{'header'}}[0];
820     my $source = @{$msg_hash->{'source'}}[0];
821     my $target = @{$msg_hash->{'target'}}[0];
822     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
823     my $hostId;
824     my $error = 0;
825     my $xml_msg;
827     # Build return message with twisted target and source
828     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
829     if (defined $forward_to_gosa) {
830       &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
831     }
833     # Sanity check of needed parameter
834     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
835         $error++;
836         &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
837         &add_content2xml_hash($out_hash, "error", "hostId");
838         &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1); 
839     }
841     if (not $error) {
843     # Get hostId
844         $hostId = @{$msg_hash->{'hostId'}}[0];
845         &add_content2xml_hash($out_hash, "hostId", "$hostId");
846         &add_content2xml_hash($out_hash, "xxx", "");
847     }    
849     # Move to XML string
850     $xml_msg= &create_xml_string($out_hash);
851     
852     if (not $error) {
854     # JSON Query
855         my $callobj = {
856             method  => 'getHardwareInformation_hash',
857             params  => [ $hostId ],
858             id  => 1,
859         };
861         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
862         if (not &check_opsi_res($res)){
863             my $result= $res->result;
864             if (ref $result eq "HASH") {
865                 foreach my $r (keys %{$result}){
866                     my $item= "\n<item><id>".xml_quote($r)."</id>";
867                     my $value= $result->{$r};
868                     foreach my $sres (@{$value}){
870                         foreach my $dres (keys %{$sres}){
871                             if (defined $sres->{$dres}){
872                                 $item.= "<$dres>".xml_quote($sres->{$dres})."</$dres>";
873                             }
874                         }
876                     }
877                     $item.= "</item>";
878                     $xml_msg=~ s%<xxx></xxx>%$item<xxx></xxx>%;
880                 }
881             }
882         }
884         $xml_msg=~ s/<xxx><\/xxx>//;
886     }
888     # Return message
889     return ( $xml_msg );
893 ## @method opsi_list_clients
894 # Reports all Opsi clients. 
895 # @param msg - STRING - xml message 
896 # @param msg_hash - HASHREF - message information parsed into a hash
897 # @param session_id - INTEGER - POE session id of the processing of this message
898 # @return out_msg - STRING - feedback to GOsa in success and error case
899 sub opsi_list_clients {
900     my ($msg, $msg_hash, $session_id) = @_;
901     my $header = @{$msg_hash->{'header'}}[0];
902     my $source = @{$msg_hash->{'source'}}[0];
903     my $target = @{$msg_hash->{'target'}}[0];
904     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
906     # Build return message with twisted target and source
907     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
908     if (defined $forward_to_gosa) {
909       &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
910     }
911     &add_content2xml_hash($out_hash, "xxx", "");
913     # Move to XML string
914     my $xml_msg= &create_xml_string($out_hash);
916     # JSON Query
917     my $callobj = {
918         method  => 'getClients_listOfHashes',
919         params  => [ ],
920         id  => 1,
921     };
922     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
923     if (not &check_opsi_res($res)){
924         foreach my $host (@{$res->result}){
925             my $item= "\n<item><name>".$host->{'hostId'}."</name>";
926             if (defined($host->{'description'})){
927                 $item.= "<description>".xml_quote($host->{'description'})."</description>";
928             }
929             if (defined($host->{'notes'})){
930                 $item.= "<notes>".xml_quote($host->{'notes'})."</notes>";
931             }
932             if (defined($host->{'lastSeen'})){
933                 $item.= "<lastSeen>".xml_quote($host->{'lastSeen'})."</lastSeen>";
934             }
936             $callobj = {
937               method  => 'getIpAddress',
938               params  => [ $host->{'hostId'} ],
939               id  => 1,
940             };
941             my $sres= $main::opsi_client->call($main::opsi_url, $callobj);
942             if ( not &check_opsi_res($sres)){
943               $item.= "<ip>".xml_quote($sres->result)."</ip>";
944             }
946             $callobj = {
947               method  => 'getMacAddress',
948               params  => [ $host->{'hostId'} ],
949               id  => 1,
950             };
951             $sres= $main::opsi_client->call($main::opsi_url, $callobj);
952             if ( not &check_opsi_res($sres)){
953                 $item.= "<mac>".xml_quote($sres->result)."</mac>";
954             }
955             $item.= "</item>";
956             $xml_msg=~ s%<xxx></xxx>%$item<xxx></xxx>%;
957         }
958     }
960     $xml_msg=~ s/<xxx><\/xxx>//;
961     return ( $xml_msg );
966 ## @method opsi_get_client_software
967 # Reports client software inventory.
968 # @param msg - STRING - xml message with tag hostId
969 # @param msg_hash - HASHREF - message information parsed into a hash
970 # @param session_id - INTEGER - POE session id of the processing of this message
971 # @return out_msg - STRING - feedback to GOsa in success and error case
972 sub opsi_get_client_software {
973     my ($msg, $msg_hash, $session_id) = @_;
974     my $header = @{$msg_hash->{'header'}}[0];
975     my $source = @{$msg_hash->{'source'}}[0];
976     my $target = @{$msg_hash->{'target'}}[0];
977     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
978     my $error = 0;
979     my $hostId;
980     my $xml_msg;
982     # Build return message with twisted target and source
983     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
984     if (defined $forward_to_gosa) {
985       &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
986     }
988     # Sanity check of needed parameter
989     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
990         $error++;
991         &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
992         &add_content2xml_hash($out_hash, "error", "hostId");
993         &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1); 
994     }
996     if (not $error) {
998     # Get hostId
999         $hostId = @{$msg_hash->{'hostId'}}[0];
1000         &add_content2xml_hash($out_hash, "hostId", "$hostId");
1001         &add_content2xml_hash($out_hash, "xxx", "");
1002     }
1004     $xml_msg= &create_xml_string($out_hash);
1006     if (not $error) {
1008     # JSON Query
1009         my $callobj = {
1010             method  => 'getSoftwareInformation_hash',
1011             params  => [ $hostId ],
1012             id  => 1,
1013         };
1015         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1016         if (not &check_opsi_res($res)){
1017             my $result= $res->result;
1018         }
1020         $xml_msg=~ s/<xxx><\/xxx>//;
1022     }
1024     # Return message
1025     return ( $xml_msg );
1029 ## @method opsi_get_local_products
1030 # Reports product for given hostId or globally.
1031 # @param msg - STRING - xml message with optional tag hostId
1032 # @param msg_hash - HASHREF - message information parsed into a hash
1033 # @param session_id - INTEGER - POE session id of the processing of this message
1034 # @return out_msg - STRING - feedback to GOsa in success and error case
1035 sub opsi_get_local_products {
1036     my ($msg, $msg_hash, $session_id) = @_;
1037     my $header = @{$msg_hash->{'header'}}[0];
1038     my $source = @{$msg_hash->{'source'}}[0];
1039     my $target = @{$msg_hash->{'target'}}[0];
1040     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1041     my $hostId;
1043     # Build return message with twisted target and source
1044     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1045     if (defined $forward_to_gosa) {
1046         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1047     }
1048     &add_content2xml_hash($out_hash, "xxx", "");
1050     # Get hostId if defined
1051     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1))  {
1052         $hostId = @{$msg_hash->{'hostId'}}[0];
1053         &add_content2xml_hash($out_hash, "hostId", $hostId);
1054     }
1056     # Move to XML string
1057     my $xml_msg= &create_xml_string($out_hash);
1059     # For hosts, only return the products that are or get installed
1060     my $callobj;
1061     $callobj = {
1062         method  => 'getLocalBootProductIds_list',
1063         params  => [ ],
1064         id  => 1,
1065     };
1067     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1068     my %r = ();
1069     for (@{$res->result}) { $r{$_} = 1 }
1071     if (not &check_opsi_res($res)){
1073         if (defined $hostId){
1074             $callobj = {
1075                 method  => 'getProductStates_hash',
1076                 params  => [ $hostId ],
1077                 id  => 1,
1078             };
1080             my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
1081             if (not &check_opsi_res($hres)){
1082                 my $htmp= $hres->result->{$hostId};
1084                 # Check state != not_installed or action == setup -> load and add
1085                 foreach my $product (@{$htmp}){
1087                     if (!defined ($r{$product->{'productId'}})){
1088                         next;
1089                     }
1091                     # Now we've a couple of hashes...
1092                     if ($product->{'installationStatus'} ne "not_installed" or
1093                             $product->{'actionRequest'} eq "setup"){
1094                         my $state= "<state>".$product->{'installationStatus'}."</state><action>".$product->{'actionRequest'}."</action>";
1096                         $callobj = {
1097                             method  => 'getProduct_hash',
1098                             params  => [ $product->{'productId'} ],
1099                             id  => 1,
1100                         };
1102                         my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
1103                         if (not &check_opsi_res($sres)){
1104                             my $tres= $sres->result;
1106                             my $name= xml_quote($tres->{'name'});
1107                             my $r= $product->{'productId'};
1108                             my $description= xml_quote($tres->{'description'});
1109                             $name=~ s/\//\\\//;
1110                             $description=~ s/\//\\\//;
1111                             $xml_msg=~ s/<xxx><\/xxx>/\n<item><productId>$r<\/productId><name>$name<\/name><description>$description<\/description><\/item>$state<xxx><\/xxx>/;
1112                         }
1114                     }
1115                 }
1117             }
1119         } else {
1120             foreach my $r (@{$res->result}) {
1121                 $callobj = {
1122                     method  => 'getProduct_hash',
1123                     params  => [ $r ],
1124                     id  => 1,
1125                 };
1127                 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
1128                 if (not &check_opsi_res($sres)){
1129                     my $tres= $sres->result;
1131                     my $name= xml_quote($tres->{'name'});
1132                     my $description= xml_quote($tres->{'description'});
1133                     $name=~ s/\//\\\//;
1134                     $description=~ s/\//\\\//;
1135                     $xml_msg=~ s/<xxx><\/xxx>/\n<item><productId>$r<\/productId><name>$name<\/name><description>$description<\/description><\/item><xxx><\/xxx>/;
1136                 }
1138             }
1140         }
1141     }
1143     $xml_msg=~ s/<xxx><\/xxx>//;
1145     # Retrun Message
1146     return ( $xml_msg );
1150 ## @method opsi_del_client
1151 # Deletes a client from Opsi.
1152 # @param msg - STRING - xml message with tag hostId
1153 # @param msg_hash - HASHREF - message information parsed into a hash
1154 # @param session_id - INTEGER - POE session id of the processing of this message
1155 # @return out_msg - STRING - feedback to GOsa in success and error case
1156 sub opsi_del_client {
1157     my ($msg, $msg_hash, $session_id) = @_;
1158     my $header = @{$msg_hash->{'header'}}[0];
1159     my $source = @{$msg_hash->{'source'}}[0];
1160     my $target = @{$msg_hash->{'target'}}[0];
1161     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1162     my $hostId;
1163     my $error = 0;
1165     # Build return message with twisted target and source
1166     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1167     if (defined $forward_to_gosa) {
1168       &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1169     }
1171     # Sanity check of needed parameter
1172     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
1173         $error++;
1174         &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
1175         &add_content2xml_hash($out_hash, "error", "hostId");
1176         &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1); 
1177     }
1179     if (not $error) {
1181     # Get hostId
1182         $hostId = @{$msg_hash->{'hostId'}}[0];
1183         &add_content2xml_hash($out_hash, "hostId", "$hostId");
1185     # JSON Query
1186         my $callobj = {
1187             method  => 'deleteClient',
1188             params  => [ $hostId ],
1189             id  => 1,
1190         };
1191         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1192     }
1194     # Move to XML string
1195     my $xml_msg= &create_xml_string($out_hash);
1197     # Return message
1198     return ( $xml_msg );
1202 ## @method opsi_install_client
1203 # Set a client in Opsi to install and trigger a wake on lan message (WOL).  
1204 # @param msg - STRING - xml message with tags hostId, macaddress
1205 # @param msg_hash - HASHREF - message information parsed into a hash
1206 # @param session_id - INTEGER - POE session id of the processing of this message
1207 # @return out_msg - STRING - feedback to GOsa in success and error case
1208 sub opsi_install_client {
1209     my ($msg, $msg_hash, $session_id) = @_;
1210     my $header = @{$msg_hash->{'header'}}[0];
1211     my $source = @{$msg_hash->{'source'}}[0];
1212     my $target = @{$msg_hash->{'target'}}[0];
1213     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1216     my ($hostId, $macaddress);
1218     my $error = 0;
1219     my @out_msg_l;
1221     # Build return message with twisted target and source
1222     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1223     if (defined $forward_to_gosa) {
1224         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1225     }
1227     # Sanity check of needed parameter
1228     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH'))  {
1229         $error++;
1230         &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
1231         &add_content2xml_hash($out_hash, "error", "hostId");
1232         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
1233     }
1234     if ((not exists $msg_hash->{'macaddress'}) || (@{$msg_hash->{'macaddress'}} != 1) || (@{$msg_hash->{'macaddress'}}[0] eq ref 'HASH') )  {
1235         $error++;
1236         &add_content2xml_hash($out_hash, "error_string", "no macaddress specified or macaddress tag invalid");
1237         &add_content2xml_hash($out_hash, "error", "macaddress");
1238         &main::daemon_log("$session_id ERROR: no macaddress specified or macaddress tag invalid: $msg", 1); 
1239     } else {
1240         if ((exists $msg_hash->{'macaddress'}) && 
1241                 ($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)) {  
1242             $macaddress = $1; 
1243         } else { 
1244             $error ++; 
1245             &add_content2xml_hash($out_hash, "error_string", "given mac address is not correct");
1246             &add_content2xml_hash($out_hash, "error", "macaddress");
1247             &main::daemon_log("$session_id ERROR: given mac address is not correct: $msg", 1); 
1248         }
1249     }
1251     if (not $error) {
1253     # Get hostId
1254         $hostId = @{$msg_hash->{'hostId'}}[0];
1255         &add_content2xml_hash($out_hash, "hostId", "$hostId");
1257         # Load all products for this host with status != "not_installed" or actionRequest != "none"
1258         my $callobj = {
1259             method  => 'getProductStates_hash',
1260             params  => [ $hostId ],
1261             id  => 1,
1262         };
1264         my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
1265         if (not &check_opsi_res($hres)){
1266             my $htmp= $hres->result->{$hostId};
1268             # check state != not_installed or action == setup -> load and add
1269             foreach my $product (@{$htmp}){
1270                 # Now we've a couple of hashes...
1271                 if ($product->{'installationStatus'} ne "not_installed" or
1272                         $product->{'actionRequest'} ne "none"){
1274                     # Do an action request for all these -> "setup".
1275                     $callobj = {
1276                         method  => 'setProductActionRequest',
1277                         params  => [ $product->{'productId'}, $hostId, "setup" ],
1278                         id  => 1,
1279                     };
1280                     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1281                     my ($res_err, $res_err_string) = &check_opsi_res($res);
1282                     if ($res_err){
1283                         &main::daemon_log("$session_id ERROR: cannot set product action request for '$hostId': ".$product->{'productId'}, 1);
1284                     } else {
1285                         &main::daemon_log("$session_id INFO: requesting 'setup' for '".$product->{'productId'}."' on $hostId", 1);
1286                     }
1287                 }
1288             }
1289         }
1290         push(@out_msg_l, &create_xml_string($out_hash));
1291     
1293     # Build wakeup message for client
1294         if (not $error) {
1295             my $wakeup_hash = &create_xml_hash("trigger_wake", "GOSA", "KNOWN_SERVER");
1296             &add_content2xml_hash($wakeup_hash, 'macaddress', $macaddress);
1297             my $wakeup_msg = &create_xml_string($wakeup_hash);
1298             push(@out_msg_l, $wakeup_msg);
1300             # invoke trigger wake for this gosa-si-server
1301             &main::server_server_com::trigger_wake($wakeup_msg, $wakeup_hash, $session_id);
1302         }
1303     }
1304     
1305     # Return messages
1306     return @out_msg_l;
1310 ## @method _set_action
1311 # Set action for an Opsi client
1312 # @param product - STRING - Opsi product
1313 # @param action - STRING - action
1314 # @param hostId - STRING - Opsi hostId
1315 sub _set_action {
1316   my $product= shift;
1317   my $action = shift;
1318   my $hostId = shift;
1319   my $callobj;
1321   $callobj = {
1322     method  => 'setProductActionRequest',
1323     params  => [ $product, $hostId, $action],
1324     id  => 1,
1325   };
1327   $main::opsi_client->call($main::opsi_url, $callobj);
1330 ## @method _set_state
1331 # Set state for an Opsi client
1332 # @param product - STRING - Opsi product
1333 # @param action - STRING - state
1334 # @param hostId - STRING - Opsi hostId
1335 sub _set_state {
1336   my $product = shift;
1337   my $state = shift;
1338   my $hostId = shift;
1339   my $callobj;
1341   $callobj = {
1342     method  => 'setProductState',
1343     params  => [ $product, $hostId, $state ],
1344     id  => 1,
1345   };
1347   $main::opsi_client->call($main::opsi_url, $callobj);
1350 ################################
1352 # @brief Create a license pool at Opsi server.
1353 # @param licensePoolId The name of the pool (optional). 
1354 # @param description The description of the pool (optional).
1355 # @param productIds A list of assigned porducts of the pool (optional). 
1356 # @param windowsSoftwareIds A list of windows software IDs associated to the pool (optional). 
1358 sub opsi_createLicensePool {
1359     my ($msg, $msg_hash, $session_id) = @_;
1360     my $header = @{$msg_hash->{'header'}}[0];
1361     my $source = @{$msg_hash->{'source'}}[0];
1362     my $target = @{$msg_hash->{'target'}}[0];
1363         my $out_hash;
1364         my $licensePoolId = defined $msg_hash->{'licensePoolId'} ? @{$msg_hash->{'licensePoolId'}}[0] : undef;
1365         my $description = defined $msg_hash->{'description'} ? @{$msg_hash->{'description'}}[0] : undef;
1366         my @productIds = defined $msg_hash->{'productIds'} ? $msg_hash->{'productIds'} : undef;
1367         my @windowsSoftwareIds = defined $msg_hash->{'windowsSoftwareIds'} ? $msg_hash->{'windowsSoftwareIds'} : undef;
1369         # Create license Pool
1370     my $callobj = {
1371         method  => 'createLicensePool',
1372         params  => [ $licensePoolId, $description, @productIds, @windowsSoftwareIds],
1373         id  => 1,
1374     };
1375     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1377         # Check Opsi error
1378         my ($res_error, $res_error_str) = &check_opsi_res($res);
1379         if ($res_error){
1380                 # Create error message
1381                 &main::daemon_log("$session_id ERROR: cannot create license pool at Opsi server: ".$res_error_str, 1);
1382                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1383                 return ( &create_xml_string($out_hash) );
1384         }
1386         # Create function result message
1387         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source, $res->result);
1389         return ( &create_xml_string($out_hash) );
1392 ################################
1394 # @brief Return licensePoolId, description, productIds and windowsSoftwareIds for all found license pools.
1396 sub opsi_getLicensePools_listOfHashes {
1397     my ($msg, $msg_hash, $session_id) = @_;
1398     my $header = @{$msg_hash->{'header'}}[0];
1399     my $source = @{$msg_hash->{'source'}}[0];
1400         my $out_hash;
1402         # Fetch infos from Opsi server
1403     my $callobj = {
1404         method  => 'getLicensePools_listOfHashes',
1405         params  => [ ],
1406         id  => 1,
1407     };
1408     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1410         # Check Opsi error
1411         my ($res_error, $res_error_str) = &check_opsi_res($res);
1412         if ($res_error){
1413                 # Create error message
1414                 &main::daemon_log("$session_id ERROR: cannot get license pool ID list from Opsi server: ".$res_error_str, 1);
1415                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1416                 return ( &create_xml_string($out_hash) );
1417         }
1419         # Create function result message
1420         my $res_hash = { 'hit'=> [] };
1421         foreach my $licensePool ( @{$res->result}) {
1422                 my $licensePool_hash = { 'licensePoolId' => [$licensePool->{'licensePoolId'}],
1423                         'description' => [$licensePool->{'description'}],
1424                         'productIds' => $licensePool->{'productIds'},
1425                         'windowsSoftwareIds' => $licensePool->{'windowsSoftwareIds'},
1426                         };
1427                 push( @{$res_hash->{hit}}, $licensePool_hash );
1428         }
1430         # Create function result message
1431         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1432         $out_hash->{result} = [$res_hash];
1434         return ( &create_xml_string($out_hash) );
1437 ################################
1439 # @brief Return productIds, windowsSoftwareIds and description for a given licensePoolId
1440 # @param licensePoolId The name of the pool. 
1442 sub opsi_getLicensePool_hash {
1443     my ($msg, $msg_hash, $session_id) = @_;
1444     my $header = @{$msg_hash->{'header'}}[0];
1445     my $source = @{$msg_hash->{'source'}}[0];
1446     my $target = @{$msg_hash->{'target'}}[0];
1447     my $licensePoolId;
1448         my $out_hash;
1450         # Check input sanity
1451         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1452                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1453         } else {
1454                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1455         }
1457         # Fetch infos from Opsi server
1458     my $callobj = {
1459         method  => 'getLicensePool_hash',
1460         params  => [ $licensePoolId ],
1461         id  => 1,
1462     };
1463     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1465         # Check Opsi error
1466         my ($res_error, $res_error_str) = &check_opsi_res($res);
1467         if ($res_error){
1468                 # Create error message
1469                 &main::daemon_log("$session_id ERROR: cannot get license pool from Opsi server: ".$res_error_str, 1);
1470                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source);
1471                 &add_content2xml_hash($out_hash, "error", $res_error_str);
1472                 return ( &create_xml_string($out_hash) );
1473         }
1475         # Create function result message
1476         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1477         &add_content2xml_hash($out_hash, "licensePoolId", $res->result->{'licensePoolId'});
1478         &add_content2xml_hash($out_hash, "description", $res->result->{'description'});
1479         map(&add_content2xml_hash($out_hash, "productIds", "$_"), @{ $res->result->{'productIds'} });
1480         map(&add_content2xml_hash($out_hash, "windowsSoftwareIds", "$_"), @{ $res->result->{'windowsSoftwareIds'} });
1482         return ( &create_xml_string($out_hash) );
1485 sub _parse_getSoftwareLicenseUsages {
1486         my $res = shift;
1488         # Parse Opsi result
1489         my $tmp_licensePool_cache = {};
1490         my $res_hash = { 'hit'=> [] };
1491         foreach my $license ( @{$res}) {
1492                 my $tmp_licensePool = $license->{'licensePoolId'};
1493                 if (not exists $tmp_licensePool_cache->{$tmp_licensePool}) {
1494                         # Fetch missing informations from Opsi and cache the results for a possible later usage
1495                         my ($res, $err) = &_getLicensePool_hash('licensePoolId'=>$tmp_licensePool);
1496                         if (not $err) {
1497                                 $tmp_licensePool_cache->{$tmp_licensePool} = $res;
1498                         }
1499                 }
1500                 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
1501                         'notes' => [$license->{'notes'}],
1502                         'licenseKey' => [$license->{'licenseKey'}],
1503                         'hostId' => [$license->{'hostId'}],
1504                         'licensePoolId' => [$tmp_licensePool],
1505                         };
1506                 if (exists $tmp_licensePool_cache->{$tmp_licensePool}) {
1507                         $license_hash->{$tmp_licensePool} = {'productIds'=>[], 'windowsSoftwareIds'=>[]};
1508                         map (push (@{$license_hash->{$tmp_licensePool}->{productIds}}, $_), @{$tmp_licensePool_cache->{$tmp_licensePool}->{productIds}});
1509                         map (push (@{$license_hash->{$tmp_licensePool}->{windowsSoftwareIds}}, $_), @{$tmp_licensePool_cache->{$tmp_licensePool}->{windowsSoftwareIds}});
1510                 }
1511                 push( @{$res_hash->{hit}}, $license_hash );
1512         }
1514         return $res_hash;
1517 ################################
1519 # @brief Returns softwareLicenseId, notes, licenseKey, hostId and licensePoolId for optional given licensePoolId and hostId
1520 # @param hostid Something like client_1.intranet.mydomain.de (optional).
1521 # @param licensePoolId The name of the pool (optional). 
1522
1523 sub opsi_getSoftwareLicenseUsages {
1524         my ($msg, $msg_hash, $session_id) = @_;
1525         my $header = @{$msg_hash->{'header'}}[0];
1526         my $source = @{$msg_hash->{'source'}}[0];
1527         my $target = @{$msg_hash->{'target'}}[0];
1528         my $licensePoolId = defined $msg_hash->{'licensePoolId'} ? @{$msg_hash->{'licensePoolId'}}[0] : undef;
1529         my $hostId = defined $msg_hash->{'hostId'} ? @{$msg_hash->{'hostId'}}[0] : undef;
1530         my $out_hash;
1532         my ($res, $err) = &_getSoftwareLicenseUsages_listOfHashes('licensePoolId'=>$licensePoolId, 'hostId'=>$hostId);
1533         if ($err){
1534                 return &_giveErrorFeedback($msg_hash, "cannot fetch software licenses from license pool : ".$res, $session_id);
1535         }
1537         # Parse Opsi result
1538         my $res_hash = &_parse_getSoftwareLicenseUsages($res);
1540         # Create function result message
1541         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1542         $out_hash->{result} = [$res_hash];
1544         return ( &create_xml_string($out_hash) );
1547 ################################
1549 # @brief Returns softwareLicenseId, notes, licenseKey, hostId and licensePoolId. Function return is identical to opsi_getSoftwareLicenseUsages
1550 # @param productId Something like 'firefox', 'python' or anything else .
1551
1552 sub opsi_getSoftwareLicenseUsagesForProductId {
1553         my ($msg, $msg_hash, $session_id) = @_;
1554         my $header = @{$msg_hash->{'header'}}[0];
1555         my $source = @{$msg_hash->{'source'}}[0];
1557         # Check input sanity
1558         my $productId;
1559         if (&_check_xml_tag_is_ok ($msg_hash, 'productId')) {
1560                 $productId= @{$msg_hash->{'productId'}}[0];
1561         } else {
1562                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1563         }
1565         # Fetch licensePoolId for productId
1566         my ($res, $err) = &_getLicensePoolId('productId'=>$productId);
1567         if ($err){
1568                 return &_giveErrorFeedback($msg_hash, "cannot fetch licensePoolId for given productId : ".$res, $session_id);
1569         }
1571         my $licensePoolId;
1573         # Fetch softwareLiceceUsages for licensePoolId
1574         ($res, $err) = &_getSoftwareLicenseUsages_listOfHashes('licensePoolId'=>$licensePoolId);
1575         if ($err){
1576                 return &_giveErrorFeedback($msg_hash, "cannot fetch software licenses from license pool : ".$res, $session_id);
1577         }
1579         # Parse Opsi result
1580         my $res_hash = &_parse_getSoftwareLicenseUsages($res);
1582         # Create function result message
1583         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1584         $out_hash->{result} = [$res_hash];
1586         return ( &create_xml_string($out_hash) );
1589 ################################
1591 # @brief Returns expirationDate, boundToHost, maxInstallation, licenseTyp, licensePoolIds and licenseKeys for a given softwareLicense ID.
1592 # @param softwareLicenseId Identificator of a license.
1594 sub opsi_getSoftwareLicense_hash {
1595         my ($msg, $msg_hash, $session_id) = @_;
1596         my $header = @{$msg_hash->{'header'}}[0];
1597         my $source = @{$msg_hash->{'source'}}[0];
1598         my $target = @{$msg_hash->{'target'}}[0];
1599         my $softwareLicenseId;
1600         my $out_hash;
1602         # Check input sanity
1603         if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
1604                 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
1605         } else {
1606                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1607         }
1609         my $callobj = {
1610                 method  => 'getSoftwareLicense_hash',
1611                 params  => [ $softwareLicenseId ],
1612                 id  => 1,
1613         };
1614         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1616         # Check Opsi error
1617         my ($res_error, $res_error_str) = &check_opsi_res($res);
1618         if ($res_error){
1619                 # Create error message
1620                 &main::daemon_log("$session_id ERROR: cannot fetch information for license '$softwareLicenseId': ".$res_error_str, 1);
1621                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1622                 return ( &create_xml_string($out_hash) );
1623         }
1624         
1625         # Create function result message
1626         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1627         &add_content2xml_hash($out_hash, "expirationDate", $res->result->{'expirationDate'});
1628         &add_content2xml_hash($out_hash, "boundToHost", $res->result->{'boundToHost'});
1629         &add_content2xml_hash($out_hash, "maxInstallations", $res->result->{'maxInstallations'});
1630         &add_content2xml_hash($out_hash, "licenseTyp", $res->result->{'licenseTyp'});
1631         foreach my $licensePoolId ( @{$res->result->{'licensePoolIds'}}) {
1632                 &add_content2xml_hash($out_hash, "licensePoolId", $licensePoolId);
1633                 &add_content2xml_hash($out_hash, $licensePoolId, $res->result->{'licenseKeys'}->{$licensePoolId});
1634         }
1636         return ( &create_xml_string($out_hash) );
1639 ################################
1641 # @brief Delete licnese pool by license pool ID. A pool can only be deleted if there are no software licenses bound to the pool. 
1642 # The fixed parameter deleteLicenses=True specifies that all software licenses bound to the pool are being deleted. 
1643 # @param licensePoolId The name of the pool. 
1645 sub opsi_deleteLicensePool {
1646         my ($msg, $msg_hash, $session_id) = @_;
1647     my $header = @{$msg_hash->{'header'}}[0];
1648     my $source = @{$msg_hash->{'source'}}[0];
1649     my $target = @{$msg_hash->{'target'}}[0];
1650     my $licensePoolId;
1651         my $out_hash;
1653         # Check input sanity
1654         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1655                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1656         } else {
1657                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1658         }
1660         # Fetch softwareLicenseIds used in license pool
1661         # This has to be done because function deleteLicensePool deletes the pool and the corresponding software licenses
1662         # but not the license contracts of the software licenses. In our case each software license has exactly one license contract. 
1663         my $callobj = {
1664                 method  => 'getSoftwareLicenses_listOfHashes',
1665                 params  => [ ],
1666                 id  => 1,
1667         };
1668         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1670         # Keep list of licenseContractIds in mind to delete it after the deletion of the software licenses
1671         my @lCI_toBeDeleted;
1672         foreach my $softwareLicenseHash ( @{$res->result} ) {
1673                 if ((@{$softwareLicenseHash->{'licensePoolIds'}} == 0) || (@{$softwareLicenseHash->{'licensePoolIds'}}[0] ne $licensePoolId)) { 
1674                         next; 
1675                 }  
1676                 push (@lCI_toBeDeleted, $softwareLicenseHash->{'licenseContractId'});
1677         }
1679         # Delete license pool at Opsi server
1680     $callobj = {
1681         method  => 'deleteLicensePool',
1682         params  => [ $licensePoolId, 'deleteLicenses=True'  ],
1683         id  => 1,
1684     };
1685     $res = $main::opsi_client->call($main::opsi_url, $callobj);
1686         my ($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 delete 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         # Delete each license contract connected with the license pool
1695         foreach my $licenseContractId ( @lCI_toBeDeleted ) {
1696                 my $callobj = {
1697                         method  => 'deleteLicenseContract',
1698                         params  => [ $licenseContractId ],
1699                         id  => 1,
1700                 };
1701                 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1702                 my ($res_error, $res_error_str) = &check_opsi_res($res);
1703                 if ($res_error){
1704                         # Create error message
1705                         &main::daemon_log("$session_id ERROR: cannot delete license contract '$licenseContractId' connected with license pool '$licensePoolId' at Opsi server: ".$res_error_str, 1);
1706                         $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1707                         return ( &create_xml_string($out_hash) );
1708                 }
1709         }
1711         # Create function result message
1712         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1713         
1714         return ( &create_xml_string($out_hash) );
1717 ################################
1719 # @brief Create a license contract, create a software license and add the software license to the license pool
1720 # @param licensePoolId The name of the pool the license should be assigned.
1721 # @param licenseKey The license key.
1722 # @param partner Name of the license partner (optional).
1723 # @param conclusionDate Date of conclusion of license contract (optional)
1724 # @param notificationDate Date of notification that license is running out soon (optional).
1725 # @param notes This is the place for some notes (optional)
1726 # @param softwareLicenseId Identificator of a license (optional).
1727 # @param licenseTyp Typ of a licnese, either "OEM", "VOLUME" or "RETAIL" (optional).
1728 # @param maxInstallations The number of clients use this license (optional). 
1729 # @param boundToHost The name of the client the license is bound to (optional).
1730 # @param expirationDate The date when the license is running down (optional). 
1732 sub opsi_createLicense {
1733         my ($msg, $msg_hash, $session_id) = @_;
1734     my $header = @{$msg_hash->{'header'}}[0];
1735     my $source = @{$msg_hash->{'source'}}[0];
1736     my $target = @{$msg_hash->{'target'}}[0];
1737         my $partner = defined $msg_hash->{'partner'} ? @{$msg_hash->{'partner'}}[0] : undef;
1738         my $conclusionDate = defined $msg_hash->{'conclusionDate'} ? @{$msg_hash->{'conclusionDate'}}[0] : undef;
1739         my $notificationDate = defined $msg_hash->{'notificationDate'} ? @{$msg_hash->{'notificationDate'}}[0] : undef;
1740         my $notes = defined $msg_hash->{'notes'} ? @{$msg_hash->{'notes'}}[0] : undef;
1741         my $licenseContractId;
1742         my $softwareLicenseId = defined $msg_hash->{'licenseId'} ? @{$msg_hash->{'licenseId'}}[0] : undef;
1743         my $licenseType = defined $msg_hash->{'licenseType'} ? @{$msg_hash->{'licenseType'}}[0] : undef;
1744         my $maxInstallations = defined $msg_hash->{'maxInstallations'} ? @{$msg_hash->{'maxInstallations'}}[0] : undef;
1745         my $boundToHost = defined $msg_hash->{'boundToHost'} ? @{$msg_hash->{'boundToHost'}}[0] : undef;
1746         my $expirationDate = defined $msg_hash->{'expirationDate'} ? @{$msg_hash->{'expirationDate'}}[0] : undef;
1747         my $licensePoolId;
1748         my $licenseKey;
1749         my $out_hash;
1751         # Check input sanity
1752         if (&_check_xml_tag_is_ok ($msg_hash, 'licenseKey')) {
1753                 $licenseKey = @{$msg_hash->{'licenseKey'}}[0];
1754         } else {
1755                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1756         }
1757         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1758                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1759         } else {
1760                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1761         }
1762         if ((defined $licenseType) && (not exists $licenseTyp_hash->{$licenseType})) {
1763                 return ( &_give_feedback($msg, $msg_hash, $session_id, "The typ of a license can be either 'OEM', 'VOLUME' or 'RETAIL'."));
1764         }
1766         # Create license contract at Opsi server
1767     my $callobj = {
1768         method  => 'createLicenseContract',
1769         params  => [ undef, $partner, $conclusionDate, $notificationDate, undef, $notes ],
1770         id  => 1,
1771     };
1772     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1774         # Check Opsi error
1775         my ($res_error, $res_error_str) = &check_opsi_res($res);
1776         if ($res_error){
1777                 # Create error message
1778                 &main::daemon_log("$session_id ERROR: cannot create license contract at Opsi server: ".$res_error_str, 1);
1779                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1780                 return ( &create_xml_string($out_hash) );
1781         }
1782         
1783         $licenseContractId = $res->result;
1785         # Create software license at Opsi server
1786     $callobj = {
1787         method  => 'createSoftwareLicense',
1788         params  => [ $softwareLicenseId, $licenseContractId, $licenseType, $maxInstallations, $boundToHost, $expirationDate ],
1789         id  => 1,
1790     };
1791     $res = $main::opsi_client->call($main::opsi_url, $callobj);
1793         # Check Opsi error
1794         ($res_error, $res_error_str) = &check_opsi_res($res);
1795         if ($res_error){
1796                 # Create error message
1797                 &main::daemon_log("$session_id ERROR: cannot create software license at Opsi server: ".$res_error_str, 1);
1798                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1799                 return ( &create_xml_string($out_hash) );
1800         }
1802         $softwareLicenseId = $res->result;
1804         # Add software license to license pool
1805         $callobj = {
1806         method  => 'addSoftwareLicenseToLicensePool',
1807         params  => [ $softwareLicenseId, $licensePoolId, $licenseKey ],
1808         id  => 1,
1809     };
1810     $res = $main::opsi_client->call($main::opsi_url, $callobj);
1812         # Check Opsi error
1813         ($res_error, $res_error_str) = &check_opsi_res($res);
1814         if ($res_error){
1815                 # Create error message
1816                 &main::daemon_log("$session_id ERROR: cannot add software license to license pool at Opsi server: ".$res_error_str, 1);
1817                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1818                 return ( &create_xml_string($out_hash) );
1819         }
1821         # Create function result message
1822         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1823         
1824         return ( &create_xml_string($out_hash) );
1827 ################################
1829 # @brief Assign a software license to a host
1830 # @param hostid Something like client_1.intranet.mydomain.de
1831 # @param licensePoolId The name of the pool.
1833 sub opsi_assignSoftwareLicenseToHost {
1834         my ($msg, $msg_hash, $session_id) = @_;
1835     my $header = @{$msg_hash->{'header'}}[0];
1836     my $source = @{$msg_hash->{'source'}}[0];
1837     my $target = @{$msg_hash->{'target'}}[0];
1838         my $hostId;
1839         my $licensePoolId;
1841         # Check input sanity
1842         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1843                 $hostId = @{$msg_hash->{'hostId'}}[0];
1844         } else {
1845                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1846         }
1847         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1848                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1849         } else {
1850                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1851         }
1853         # Assign a software license to a host
1854         my $callobj = {
1855         method  => 'getAndAssignSoftwareLicenseKey',
1856         params  => [ $hostId, $licensePoolId ],
1857         id  => 1,
1858     };
1859     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1861         # Check Opsi error
1862         my ($res_error, $res_error_str) = &check_opsi_res($res);
1863         if ($res_error){
1864                 # Create error message
1865                 &main::daemon_log("$session_id ERROR: cannot assign a software license to a host at Opsi server: ".$res_error_str, 1);
1866                 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1867                 return ( &create_xml_string($out_hash) );
1868         }
1870         # Create function result message
1871         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1872         
1873         return ( &create_xml_string($out_hash) );
1876 ################################
1878 # @brief Unassign a software license from a host.
1879 # @param hostid Something like client_1.intranet.mydomain.de
1880 # @param licensePoolId The name of the pool.
1882 sub opsi_unassignSoftwareLicenseFromHost {
1883         my ($msg, $msg_hash, $session_id) = @_;
1884     my $header = @{$msg_hash->{'header'}}[0];
1885     my $source = @{$msg_hash->{'source'}}[0];
1886     my $target = @{$msg_hash->{'target'}}[0];
1887         my $hostId;
1888         my $licensePoolId;
1890         # Check input sanity
1891         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1892                 $hostId = @{$msg_hash->{'hostId'}}[0];
1893         } else {
1894                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1895         }
1896         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1897                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1898         } else {
1899                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1900         }
1902         # Unassign a software license from a host
1903         my $callobj = {
1904         method  => 'deleteSoftwareLicenseUsage',
1905         params  => [ $hostId, '', $licensePoolId ],
1906         id  => 1,
1907     };
1908     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1910         # Check Opsi error
1911         my ($res_error, $res_error_str) = &check_opsi_res($res);
1912         if ($res_error){
1913                 # Create error message
1914                 &main::daemon_log("$session_id ERROR: cannot unassign a software license from a host at Opsi server: ".$res_error_str, 1);
1915                 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1916                 return ( &create_xml_string($out_hash) );
1917         }
1919         # Create function result message
1920         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1921         
1922         return ( &create_xml_string($out_hash) );
1925 ################################
1927 # @brief Unassign all software licenses from a host
1928 # @param hostid Something like client_1.intranet.mydomain.de
1930 sub opsi_unassignAllSoftwareLicensesFromHost {
1931         my ($msg, $msg_hash, $session_id) = @_;
1932     my $header = @{$msg_hash->{'header'}}[0];
1933     my $source = @{$msg_hash->{'source'}}[0];
1934     my $target = @{$msg_hash->{'target'}}[0];
1935         my $hostId;
1937         # Check input sanity
1938         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1939                 $hostId = @{$msg_hash->{'hostId'}}[0];
1940         } else {
1941                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1942         }
1944         # Unassign all software licenses from a host
1945         my $callobj = {
1946         method  => 'deleteAllSoftwareLicenseUsages',
1947         params  => [ $hostId ],
1948         id  => 1,
1949     };
1950     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1952         # Check Opsi error
1953         my ($res_error, $res_error_str) = &check_opsi_res($res);
1954         if ($res_error){
1955                 # Create error message
1956                 &main::daemon_log("$session_id ERROR: cannot unassign a software license from a host at Opsi server: ".$res_error_str, 1);
1957                 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1958                 return ( &create_xml_string($out_hash) );
1959         }
1961         # Create function result message
1962         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1963         
1964         return ( &create_xml_string($out_hash) );
1968 ################################
1970 # @brief Returns the assigned licensePoolId and licenses, how often the product is installed and at which host
1971 # and the number of max and remaining installations for a given OPSI product.
1972 # @param productId Identificator of an OPSI product.
1973 #       
1974 sub opsi_getLicenseInformationForProduct {
1975     my ($msg, $msg_hash, $session_id) = @_;
1976     my $header = @{$msg_hash->{'header'}}[0];
1977     my $source = @{$msg_hash->{'source'}}[0];
1978         my $productId;
1979         my $out_hash;
1981         # Check input sanity
1982         if (&_check_xml_tag_is_ok ($msg_hash, 'productId')) {
1983                 $productId = @{$msg_hash->{'productId'}}[0];
1984         } else {
1985                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1986         }
1988         # Fetch infos from Opsi server
1989     my $callobj = {
1990         method  => 'getLicensePoolId',
1991         params  => [ $productId ],
1992         id  => 1,
1993     };
1994     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1996         # Check Opsi error
1997         my ($res_error, $res_error_str) = &check_opsi_res($res);
1998         if ($res_error){
1999                 return &_giveErrorFeedback($msg_hash, "cannot get license pool for product '$productId' : ".$res_error_str, $session_id);
2000         } 
2001         
2002         my $licensePoolId = $res->result;
2004         # Fetch statistic information for given pool ID
2005         $callobj = {
2006                 method  => 'getLicenseStatistics_hash',
2007                 params  => [ ],
2008                 id  => 1,
2009         };
2010         $res = $main::opsi_client->call($main::opsi_url, $callobj);
2012         # Check Opsi error
2013         ($res_error, $res_error_str) = &check_opsi_res($res);
2014         if ($res_error){
2015                 # Create error message
2016                 &main::daemon_log("$session_id ERROR: cannot get statistic informations for license pools : ".$res_error_str, 1);
2017                 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
2018                 return ( &create_xml_string($out_hash) );
2019         }
2021         # Create function result message
2022         $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2023         &add_content2xml_hash($out_hash, "licensePoolId", $licensePoolId);
2024         &add_content2xml_hash($out_hash, "licenses", $res->result->{$licensePoolId}->{'licenses'});
2025         &add_content2xml_hash($out_hash, "usageCount", $res->result->{$licensePoolId}->{'usageCount'});
2026         &add_content2xml_hash($out_hash, "maxInstallations", $res->result->{$licensePoolId}->{'maxInstallations'});
2027         &add_content2xml_hash($out_hash, "remainingInstallations", $res->result->{$licensePoolId}->{'remainingInstallations'});
2028         map(&add_content2xml_hash($out_hash, "usedBy", "$_"), @{ $res->result->{$licensePoolId}->{'usedBy'}});
2030         return ( &create_xml_string($out_hash) );
2034 ################################
2036 # @brief
2037 # @param 
2038 #       
2039 sub opsi_getPool {
2040     my ($msg, $msg_hash, $session_id) = @_;
2041     my $header = @{$msg_hash->{'header'}}[0];
2042     my $source = @{$msg_hash->{'source'}}[0];
2044         # Check input sanity
2045         my $licensePoolId;
2046         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
2047                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
2048         } else {
2049                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
2050         }
2052         # Create hash for the answer
2053         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2055         # Call Opsi
2056         my ($res, $err) = &_getLicensePool_hash( 'licensePoolId'=> $licensePoolId );
2057         if ($err){
2058                 return &_giveErrorFeedback($msg_hash, "cannot get license pool from Opsi server: ".$res, $session_id);
2059         }
2060         # Add data to outgoing hash
2061         &add_content2xml_hash($out_hash, "licensePoolId", $res->{'licensePoolId'});
2062         &add_content2xml_hash($out_hash, "description", $res->{'description'});
2063         map(&add_content2xml_hash($out_hash, "productIds", "$_"), @{ $res->{'productIds'} });
2064         map(&add_content2xml_hash($out_hash, "windowsSoftwareIds", "$_"), @{ $res->{'windowsSoftwareIds'} });
2067         # Call Opsi two times
2068         my ($usages_res, $usages_err) = &_getSoftwareLicenseUsages_listOfHashes('licensePoolId'=>$licensePoolId);
2069         if ($usages_err){
2070                 return &_giveErrorFeedback($msg_hash, "cannot get software license usage information from Opsi server: ".$usages_res, $session_id);
2071         }
2072         my ($licenses_res, $licenses_err) = &_getSoftwareLicenses_listOfHashes();
2073         if ($licenses_err){
2074                 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server: ".$licenses_res, $session_id);
2075         }
2077         # Add data to outgoing hash
2078         # Parse through all software licenses and select those associated to the pool
2079         my $res_hash = { 'hit'=> [] };
2080         foreach my $license ( @$licenses_res) {
2081                 # Each license hash has a list of licensePoolIds so go through this list and search for matching licensePoolIds
2082                 my $found = 0;
2083                 my @licensePoolIds_list = @{$license->{licensePoolIds}};
2084                 foreach my $lPI ( @licensePoolIds_list) {
2085                         if ($lPI eq $licensePoolId) { $found++ }
2086                 }
2087                 if (not $found ) { next; };
2088                 # Found matching licensePoolId
2089                 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
2090                         'licenseKeys' => {},
2091                         'expirationDate' => [$license->{'expirationDate'}],
2092                         'boundToHost' => [$license->{'boundToHost'}],
2093                         'maxInstallations' => [$license->{'maxInstallations'}],
2094                         'licenseType' => [$license->{'licenseType'}],
2095                         'licenseContractId' => [$license->{'licenseContractId'}],
2096                         'licensePoolIds' => [],
2097                         'hostIds' => [],
2098                         };
2099                 foreach my $licensePoolId (@{ $license->{'licensePoolIds'}}) {
2100                         push( @{$license_hash->{'licensePoolIds'}}, $licensePoolId);
2101                         $license_hash->{licenseKeys}->{$licensePoolId} =  [ $license->{'licenseKeys'}->{$licensePoolId} ];
2102                 }
2103                 foreach my $usage (@$usages_res) {
2104                         # Search for hostIds with matching softwareLicenseId
2105                         if ($license->{'softwareLicenseId'} eq $usage->{'softwareLicenseId'}) {
2106                                 push( @{ $license_hash->{hostIds}}, $usage->{hostId});
2107                         }
2108                 }
2110                 # Each softwareLicenseId has one licenseContractId, fetch contract details for each licenseContractId
2111                 my ($lContract_res, $lContract_err) = &_getLicenseContract_hash('licenseContractId'=>$license->{licenseContractId});
2112                 if ($lContract_err){
2113                         return &_giveErrorFeedback($msg_hash, "cannot get software license contract information from Opsi server: ".$licenses_res, $session_id);
2114                 }
2116                 $license_hash->{$license->{'licenseContractId'}} = [];
2117                 my $licenseContract_hash = { 'conclusionDate' => [$lContract_res->{conclusionDate}],
2118                         'notificationDate' => [$lContract_res->{notificationDate}],
2119                         'notes' => [$lContract_res->{notes}],
2120                         'exirationDate' => [$lContract_res->{expirationDate}],
2121                         'partner' => [$lContract_res->{partner}],
2122                 };
2123                 
2124                 push( @{$license_hash->{licenseContractData}}, $licenseContract_hash );
2126 print STDERR Dumper $license_hash;
2128                 push( @{$res_hash->{hit}}, $license_hash );
2129         }
2130         $out_hash->{licenses} = [$res_hash];
2132     return ( &create_xml_string($out_hash) );
2136 ################################
2138 # @brief Removes at first the software license from license pool and than deletes the software license. 
2139 # Attention, the software license has to exists otherwise it will lead to an Opsi internal server error.
2140 # @param softwareLicenseId 
2141 # @param licensePoolId
2143 sub opsi_removeLicense {
2144     my ($msg, $msg_hash, $session_id) = @_;
2145     my $header = @{$msg_hash->{'header'}}[0];
2146     my $source = @{$msg_hash->{'source'}}[0];
2148         # Check input sanity
2149         my $softwareLicenseId;
2150         if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
2151                 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
2152         } else {
2153                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
2154         }
2155         my $licensePoolId;
2156         if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
2157                 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
2158         } else {
2159                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
2160         }
2161         
2162         # Call Opsi
2163         my ($res, $err) = &_removeSoftwareLicenseFromLicensePool( 'licensePoolId' => $licensePoolId, 'softwareLicenseId' => $softwareLicenseId );
2164         if ($err){
2165                 return &_giveErrorFeedback($msg_hash, "cannot delete software license from pool: ".$res, $session_id);
2166         }
2168         # Call Opsi
2169         ($res, $err) = &_deleteSoftwareLicense( 'softwareLicenseId'=>$softwareLicenseId );
2170         if ($err){
2171                 return &_giveErrorFeedback($msg_hash, "cannot delete software license from Opsi server: ".$res, $session_id);
2172         }
2174         # Create hash for the answer
2175         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2176         return ( &create_xml_string($out_hash) );
2180 ################################
2182 # @brief
2183 # @param 
2185 sub opsi_getReservedLicenses {
2186         my ($msg, $msg_hash, $session_id) = @_;
2187         my $header = @{$msg_hash->{'header'}}[0];
2188         my $source = @{$msg_hash->{'source'}}[0];
2190         # Check input sanity
2191         my $hostId;
2192         if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
2193                 $hostId = @{$msg_hash->{'hostId'}}[0];
2194         } else {
2195                 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
2196         }
2198         # Fetch informations from Opsi server
2199         my ($license_res, $license_err) = &_getSoftwareLicenses_listOfHashes();
2200         if ($license_err){
2201                 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server: ".$license_res, $session_id);
2202         }
2205         # Parse result
2206         my $res_hash = { 'hit'=> [] };
2207         foreach my $license ( @$license_res) {
2208                 if ($license->{boundToHost} ne $hostId) { next; }
2210                 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
2211                         'maxInstallations' => [$license->{'maxInstallations'}],
2212                         'boundToHost' => [$license->{'boundToHost'}],
2213                         'expirationDate' => [$license->{'expirationDate'}],
2214                         'licenseContractId' => [$license->{'licenseContractId'}],
2215                         'licenseType' => [$license->{'licenseType'}],
2216                         'licensePoolIds' => [],
2217                         };
2218                 
2219                 foreach my $licensePoolId (@{$license->{'licensePoolIds'}}) {
2220                         # Fetch information for license pools containing a software license which is bound to given host
2221                         my ($pool_res, $pool_err) = &_getLicensePool_hash( 'licensePoolId'=>$licensePoolId );
2222                         if ($pool_err){
2223                                 return &_giveErrorFeedback($msg_hash, "cannot get license pool from Opsi server: ".$pool_res, $session_id);
2224                         }
2226                         # Add licensePool information to result hash
2227                         push (@{$license_hash->{licensePoolIds}}, $licensePoolId);
2228                         $license_hash->{$licensePoolId} = {'productIds'=>[], 'windowsSoftwareIds'=>[]};
2229                         map (push (@{$license_hash->{$licensePoolId}->{productIds}}, $_), @{$pool_res->{productIds}});
2230                         map (push (@{$license_hash->{$licensePoolId}->{windowsSoftwareIds}}, $_), @{$pool_res->{windowsSoftwareIds}});
2231                 }
2232                 push( @{$res_hash->{hit}}, $license_hash );
2233         }
2234         my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2235         $out_hash->{licenses} = [$res_hash];
2236     return ( &create_xml_string($out_hash) );
2238         return;
2241 sub opsi_test {
2242     my ($msg, $msg_hash, $session_id) = @_;
2243     my $header = @{$msg_hash->{'header'}}[0];
2244     my $source = @{$msg_hash->{'source'}}[0];
2245         my $pram1 = @{$msg_hash->{'productId'}}[0];
2247 print STDERR Dumper $pram1;
2249         # Fetch infos from Opsi server
2250     my $callobj = {
2251         method  => 'getLicensePoolId',
2252         params  => [ $pram1 ],
2253         id  => 1,
2254     };
2255     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
2257         print STDERR Dumper $res;
2258         return ();
2261 sub _giveErrorFeedback {
2262         my ($msg_hash, $err_string, $session_id) = @_;
2263         &main::daemon_log("$session_id ERROR: $err_string", 1);
2264         my $out_hash = &main::create_xml_hash("error", $main::server_address, @{$msg_hash->{source}}[0], $err_string);
2265         return ( &create_xml_string($out_hash) );
2269 sub _getLicensePool_hash {
2270         my %arg = (
2271                 'licensePoolId' => undef,
2272                 @_,
2273         );
2275         if (not defined $arg{licensePoolId} ) { 
2276                 return ("function requires licensePoolId as parameter", 1);
2277         }
2279         # Fetch pool infos from Opsi server
2280     my $callobj = {
2281         method  => 'getLicensePool_hash',
2282         params  => [ $arg{licensePoolId} ],
2283         id  => 1,
2284     };
2285     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
2287         # Check Opsi error
2288         my ($res_error, $res_error_str) = &check_opsi_res($res);
2289         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2291         return ($res->result, 0);
2294 sub _getSoftwareLicenses_listOfHashes {
2295         # Fetch licenses associated to the given pool
2296         my $callobj = {
2297                 method  => 'getSoftwareLicenses_listOfHashes',
2298                 params  => [ ],
2299                 id  => 1,
2300         };
2301         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
2303         # Check Opsi error
2304         my ($res_error, $res_error_str) = &check_opsi_res($res);
2305         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2307         return ($res->result, 0);
2310 sub _getSoftwareLicenseUsages_listOfHashes {
2311         my %arg = (
2312                         'hostId' => "",
2313                         'licensePoolId' => "",
2314                         @_,
2315                         );
2317         # Fetch pool infos from Opsi server
2318         my $callobj = {
2319                 method  => 'getSoftwareLicenseUsages_listOfHashes',
2320                 params  => [ $arg{hostId}, $arg{licensePoolId} ],
2321                 id  => 1,
2322         };
2323         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
2325         # Check Opsi error
2326         my ($res_error, $res_error_str) = &check_opsi_res($res);
2327         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2329         return ($res->result, 0);
2332 sub _removeSoftwareLicenseFromLicensePool {
2333         my %arg = (
2334                 'softwareLicenseId' => undef,
2335                 'licensePoolId' => undef,
2336                 @_,
2337                 );
2339         if (not defined $arg{softwareLicenseId} ) { 
2340                 return ("function requires softwareLicenseId as parameter", 1);
2341                 }
2342                 if (not defined $arg{licensePoolId} ) { 
2343                 return ("function requires licensePoolId as parameter", 1);
2344         }
2346         # Remove software license from license pool
2347         my $callobj = {
2348                 method  => 'removeSoftwareLicenseFromLicensePool',
2349                 params  => [ $arg{softwareLicenseId}, $arg{licensePoolId} ],
2350                 id  => 1,
2351         };
2352         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
2354         # Check Opsi error
2355         my ($res_error, $res_error_str) = &check_opsi_res($res);
2356         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2358         return ($res->result, 0);
2361 sub _deleteSoftwareLicense {
2362         my %arg = (
2363                 'softwareLicenseId' => undef,
2364                 'removeFromPools' => "",
2365                 @_,
2366                 );
2368         if (not defined $arg{softwareLicenseId} ) { 
2369                 return ("function requires softwareLicenseId as parameter", 1);
2370         }
2372         # Fetch
2373         my $callobj = {
2374                 method  => 'deleteSoftwareLicense',
2375                 params  => [ $arg{softwareLicenseId}, $arg{removeFromPools} ],
2376                 id  => 1,
2377         };
2378         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
2380         # Check Opsi error
2381         my ($res_error, $res_error_str) = &check_opsi_res($res);
2382         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2384         return ($res->result, 0);
2387 sub _getLicensePoolId {
2388         my %arg = (
2389                         'productId' => undef,
2390                         @_,
2391                         );
2392         
2393         if (not defined $arg{productId} ) {
2394                 return ("function requires productId as parameter", 1);
2395         }
2397     my $callobj = {
2398         method  => 'getLicensePoolId',
2399         params  => [ $arg{productId} ],
2400         id  => 1,
2401     };
2402     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
2404         # Check Opsi error
2405         my ($res_error, $res_error_str) = &check_opsi_res($res);
2406         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2408         return ($res->result, 0);
2411 sub _getLicenseContract_hash {
2412         my %arg = (
2413                         'licenseContractId' => undef,
2414                         @_,
2415                         );
2416         
2417         if (not defined $arg{licenseContractId} ) {
2418                 return ("function requires licenseContractId as parameter", 1);
2419         }
2421     my $callobj = {
2422         method  => 'getLicenseContract_hash',
2423         params  => [ $arg{licenseContractId} ],
2424         id  => 1,
2425     };
2426     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
2428         # Check Opsi error
2429         my ($res_error, $res_error_str) = &check_opsi_res($res);
2430         if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2432         return ($res->result, 0);
2437 1;