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);
102 }
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) );
165 }
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) );
277 }
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) );
359 }
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) );
449 }
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 );
570 }
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 );
701 }
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 }
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) );
808 }
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);
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 );
890 }
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 );
962 }
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 );
1026 }
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 );
1147 }
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 );
1199 }
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));
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 }
1305 # Return messages
1306 return @out_msg_l;
1307 }
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);
1328 }
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);
1348 }
1350 ################################
1351 #
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).
1357 #
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) );
1390 }
1392 ################################
1393 #
1394 # @brief Return licensePoolId, description, productIds and windowsSoftwareIds for all found license pools.
1395 #
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) );
1435 }
1437 ################################
1438 #
1439 # @brief Return productIds, windowsSoftwareIds and description for a given licensePoolId
1440 # @param licensePoolId The name of the pool.
1441 #
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) );
1483 }
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;
1515 }
1517 ################################
1518 #
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) );
1545 }
1547 ################################
1548 #
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) );
1587 }
1589 ################################
1590 #
1591 # @brief Returns expirationDate, boundToHost, maxInstallation, licenseTyp, licensePoolIds and licenseKeys for a given softwareLicense ID.
1592 # @param softwareLicenseId Identificator of a license.
1593 #
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 }
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) );
1637 }
1639 ################################
1640 #
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.
1644 #
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);
1714 return ( &create_xml_string($out_hash) );
1715 }
1717 ################################
1718 #
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).
1731 #
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 => [ "c_".$softwareLicenseId, $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 }
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);
1824 return ( &create_xml_string($out_hash) );
1825 }
1827 ################################
1828 #
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.
1832 #
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);
1873 return ( &create_xml_string($out_hash) );
1874 }
1876 ################################
1877 #
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.
1881 #
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);
1922 return ( &create_xml_string($out_hash) );
1923 }
1925 ################################
1926 #
1927 # @brief Unassign all software licenses from a host
1928 # @param hostid Something like client_1.intranet.mydomain.de
1929 #
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);
1964 return ( &create_xml_string($out_hash) );
1965 }
1968 ################################
1969 #
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 }
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) );
2031 }
2034 ################################
2035 #
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 }
2115 $license_hash->{$license->{'licenseContractId'}} = [];
2116 my $licenseContract_hash = { 'conclusionDate' => [$lContract_res->{conclusionDate}],
2117 'notificationDate' => [$lContract_res->{notificationDate}],
2118 'notes' => [$lContract_res->{notes}],
2119 'exirationDate' => [$lContract_res->{expirationDate}],
2120 'partner' => [$lContract_res->{partner}],
2121 };
2122 push( @{$license_hash->{licenseContractData}}, $licenseContract_hash );
2124 push( @{$res_hash->{hit}}, $license_hash );
2125 }
2126 $out_hash->{licenses} = [$res_hash];
2128 return ( &create_xml_string($out_hash) );
2129 }
2132 ################################
2133 #
2134 # @brief Removes at first the software license from license pool and than deletes the software license.
2135 # Attention, the software license has to exists otherwise it will lead to an Opsi internal server error.
2136 # @param softwareLicenseId
2137 # @param licensePoolId
2138 #
2139 sub opsi_removeLicense {
2140 my ($msg, $msg_hash, $session_id) = @_;
2141 my $header = @{$msg_hash->{'header'}}[0];
2142 my $source = @{$msg_hash->{'source'}}[0];
2144 # Check input sanity
2145 my $softwareLicenseId;
2146 if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
2147 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
2148 } else {
2149 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
2150 }
2151 my $licensePoolId;
2152 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
2153 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
2154 } else {
2155 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
2156 }
2158 # Call Opsi
2159 my ($res, $err) = &_removeSoftwareLicenseFromLicensePool( 'licensePoolId' => $licensePoolId, 'softwareLicenseId' => $softwareLicenseId );
2160 if ($err){
2161 return &_giveErrorFeedback($msg_hash, "cannot delete software license from pool: ".$res, $session_id);
2162 }
2164 # Call Opsi
2165 ($res, $err) = &_deleteSoftwareLicense( 'softwareLicenseId'=>$softwareLicenseId );
2166 if ($err){
2167 return &_giveErrorFeedback($msg_hash, "cannot delete software license from Opsi server: ".$res, $session_id);
2168 }
2170 # Create hash for the answer
2171 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2172 return ( &create_xml_string($out_hash) );
2173 }
2176 ################################
2177 #
2178 # @brief
2179 # @param
2180 #
2181 sub opsi_getReservedLicenses {
2182 my ($msg, $msg_hash, $session_id) = @_;
2183 my $header = @{$msg_hash->{'header'}}[0];
2184 my $source = @{$msg_hash->{'source'}}[0];
2186 # Check input sanity
2187 my $hostId;
2188 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
2189 $hostId = @{$msg_hash->{'hostId'}}[0];
2190 } else {
2191 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
2192 }
2194 # Fetch informations from Opsi server
2195 my ($license_res, $license_err) = &_getSoftwareLicenses_listOfHashes();
2196 if ($license_err){
2197 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server: ".$license_res, $session_id);
2198 }
2201 # Parse result
2202 my $res_hash = { 'hit'=> [] };
2203 foreach my $license ( @$license_res) {
2204 if ($license->{boundToHost} ne $hostId) { next; }
2206 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
2207 'maxInstallations' => [$license->{'maxInstallations'}],
2208 'boundToHost' => [$license->{'boundToHost'}],
2209 'expirationDate' => [$license->{'expirationDate'}],
2210 'licenseContractId' => [$license->{'licenseContractId'}],
2211 'licenseType' => [$license->{'licenseType'}],
2212 'licensePoolIds' => [],
2213 };
2215 foreach my $licensePoolId (@{$license->{'licensePoolIds'}}) {
2216 # Fetch information for license pools containing a software license which is bound to given host
2217 my ($pool_res, $pool_err) = &_getLicensePool_hash( 'licensePoolId'=>$licensePoolId );
2218 if ($pool_err){
2219 return &_giveErrorFeedback($msg_hash, "cannot get license pool from Opsi server: ".$pool_res, $session_id);
2220 }
2222 # Add licensePool information to result hash
2223 push (@{$license_hash->{licensePoolIds}}, $licensePoolId);
2224 $license_hash->{$licensePoolId} = {'productIds'=>[], 'windowsSoftwareIds'=>[]};
2225 map (push (@{$license_hash->{$licensePoolId}->{productIds}}, $_), @{$pool_res->{productIds}});
2226 map (push (@{$license_hash->{$licensePoolId}->{windowsSoftwareIds}}, $_), @{$pool_res->{windowsSoftwareIds}});
2227 }
2228 push( @{$res_hash->{hit}}, $license_hash );
2229 }
2230 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2231 $out_hash->{licenses} = [$res_hash];
2232 return ( &create_xml_string($out_hash) );
2234 return;
2235 }
2237 sub opsi_test {
2238 my ($msg, $msg_hash, $session_id) = @_;
2239 my $header = @{$msg_hash->{'header'}}[0];
2240 my $source = @{$msg_hash->{'source'}}[0];
2241 my $pram1 = @{$msg_hash->{'productId'}}[0];
2243 print STDERR Dumper $pram1;
2245 # Fetch infos from Opsi server
2246 my $callobj = {
2247 method => 'getLicensePoolId',
2248 params => [ $pram1 ],
2249 id => 1,
2250 };
2251 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
2253 print STDERR Dumper $res;
2254 return ();
2255 }
2257 sub _giveErrorFeedback {
2258 my ($msg_hash, $err_string, $session_id) = @_;
2259 &main::daemon_log("$session_id ERROR: $err_string", 1);
2260 my $out_hash = &main::create_xml_hash("error", $main::server_address, @{$msg_hash->{source}}[0], $err_string);
2261 return ( &create_xml_string($out_hash) );
2262 }
2265 sub _getLicensePool_hash {
2266 my %arg = (
2267 'licensePoolId' => undef,
2268 @_,
2269 );
2271 if (not defined $arg{licensePoolId} ) {
2272 return ("function requires licensePoolId as parameter", 1);
2273 }
2275 # Fetch pool infos from Opsi server
2276 my $callobj = {
2277 method => 'getLicensePool_hash',
2278 params => [ $arg{licensePoolId} ],
2279 id => 1,
2280 };
2281 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
2283 # Check Opsi error
2284 my ($res_error, $res_error_str) = &check_opsi_res($res);
2285 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2287 return ($res->result, 0);
2288 }
2290 sub _getSoftwareLicenses_listOfHashes {
2291 # Fetch licenses associated to the given pool
2292 my $callobj = {
2293 method => 'getSoftwareLicenses_listOfHashes',
2294 params => [ ],
2295 id => 1,
2296 };
2297 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
2299 # Check Opsi error
2300 my ($res_error, $res_error_str) = &check_opsi_res($res);
2301 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2303 return ($res->result, 0);
2304 }
2306 sub _getSoftwareLicenseUsages_listOfHashes {
2307 my %arg = (
2308 'hostId' => "",
2309 'licensePoolId' => "",
2310 @_,
2311 );
2313 # Fetch pool infos from Opsi server
2314 my $callobj = {
2315 method => 'getSoftwareLicenseUsages_listOfHashes',
2316 params => [ $arg{hostId}, $arg{licensePoolId} ],
2317 id => 1,
2318 };
2319 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
2321 # Check Opsi error
2322 my ($res_error, $res_error_str) = &check_opsi_res($res);
2323 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2325 return ($res->result, 0);
2326 }
2328 sub _removeSoftwareLicenseFromLicensePool {
2329 my %arg = (
2330 'softwareLicenseId' => undef,
2331 'licensePoolId' => undef,
2332 @_,
2333 );
2335 if (not defined $arg{softwareLicenseId} ) {
2336 return ("function requires softwareLicenseId as parameter", 1);
2337 }
2338 if (not defined $arg{licensePoolId} ) {
2339 return ("function requires licensePoolId as parameter", 1);
2340 }
2342 # Remove software license from license pool
2343 my $callobj = {
2344 method => 'removeSoftwareLicenseFromLicensePool',
2345 params => [ $arg{softwareLicenseId}, $arg{licensePoolId} ],
2346 id => 1,
2347 };
2348 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
2350 # Check Opsi error
2351 my ($res_error, $res_error_str) = &check_opsi_res($res);
2352 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2354 return ($res->result, 0);
2355 }
2357 sub _deleteSoftwareLicense {
2358 my %arg = (
2359 'softwareLicenseId' => undef,
2360 'removeFromPools' => "",
2361 @_,
2362 );
2364 if (not defined $arg{softwareLicenseId} ) {
2365 return ("function requires softwareLicenseId as parameter", 1);
2366 }
2368 # Fetch
2369 my $callobj = {
2370 method => 'deleteSoftwareLicense',
2371 params => [ $arg{softwareLicenseId}, $arg{removeFromPools} ],
2372 id => 1,
2373 };
2374 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
2376 # Check Opsi error
2377 my ($res_error, $res_error_str) = &check_opsi_res($res);
2378 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2380 return ($res->result, 0);
2381 }
2383 sub _getLicensePoolId {
2384 my %arg = (
2385 'productId' => undef,
2386 @_,
2387 );
2389 if (not defined $arg{productId} ) {
2390 return ("function requires productId as parameter", 1);
2391 }
2393 my $callobj = {
2394 method => 'getLicensePoolId',
2395 params => [ $arg{productId} ],
2396 id => 1,
2397 };
2398 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
2400 # Check Opsi error
2401 my ($res_error, $res_error_str) = &check_opsi_res($res);
2402 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2404 return ($res->result, 0);
2405 }
2407 sub _getLicenseContract_hash {
2408 my %arg = (
2409 'licenseContractId' => undef,
2410 @_,
2411 );
2413 if (not defined $arg{licenseContractId} ) {
2414 return ("function requires licenseContractId as parameter", 1);
2415 }
2417 my $callobj = {
2418 method => 'getLicenseContract_hash',
2419 params => [ $arg{licenseContractId} ],
2420 id => 1,
2421 };
2422 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
2424 # Check Opsi error
2425 my ($res_error, $res_error_str) = &check_opsi_res($res);
2426 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2428 return ($res->result, 0);
2430 }
2433 1;