1 ## @file
2 # @details A GOsa-SI-server event module containing all functions for message handling.
3 # @brief Implementation of an event module for GOsa-SI-server.
6 package opsi_com;
7 use Exporter;
8 @ISA = qw(Exporter);
9 my @events = (
10 "get_events",
11 "opsi_install_client",
12 "opsi_get_netboot_products",
13 "opsi_get_local_products",
14 "opsi_get_client_hardware",
15 "opsi_get_client_software",
16 "opsi_get_product_properties",
17 "opsi_set_product_properties",
18 "opsi_list_clients",
19 "opsi_del_client",
20 "opsi_add_client",
21 "opsi_modify_client",
22 "opsi_add_product_to_client",
23 "opsi_del_product_from_client",
24 "opsi_createLicensePool",
25 "opsi_deleteLicensePool",
26 "opsi_createLicense",
27 "opsi_assignSoftwareLicenseToHost",
28 "opsi_unassignSoftwareLicenseFromHost",
29 "opsi_unassignAllSoftwareLicensesFromHost",
30 "opsi_getSoftwareLicense_hash",
31 "opsi_getLicensePool_hash",
32 "opsi_getSoftwareLicenseUsages_listOfHashes",
33 "opsi_getLicensePools_listOfHashes",
34 "opsi_getLicenseInformationForProduct",
35 "opsi_test",
36 );
37 @EXPORT = @events;
39 use strict;
40 use warnings;
41 use GOSA::GosaSupportDaemon;
42 use Data::Dumper;
43 use XML::Quote qw(:all);
45 BEGIN {}
47 END {}
49 # ----------------------------------------------------------------------------
50 # D E C L A R A T I O N S
51 # ----------------------------------------------------------------------------
53 my $licenseTyp_hash = { 'OEM'=>'', 'VOLUME'=>'', 'RETAIL'=>''};
57 # ----------------------------------------------------------------------------
58 # S U B R O U T I N E S
59 # ----------------------------------------------------------------------------
62 ################################
63 #
64 # @brief A function returning a list of functions which are exported by importing the module.
65 # @return List of all provided functions
66 #
67 sub get_events {
68 return \@events;
69 }
71 ################################
72 #
73 # @brief Checks if there is a specified tag and if the the tag has a content.
74 # @return 0|1
75 #
76 sub _check_xml_tag_is_ok {
77 my ($msg_hash,$tag) = @_;
78 if (not defined $msg_hash->{$tag}) {
79 $_ = "message contains no tag '$tag'";
80 return 0;
81 }
82 if (ref @{$msg_hash->{$tag}}[0] eq 'HASH') {
83 $_ = "message tag '$tag' has no content";
84 return 0;
85 }
86 return 1;
87 }
89 ################################
90 #
91 # @brief Writes the log line and returns the error message for GOsa.
92 #
93 sub _give_feedback {
94 my ($msg, $msg_hash, $session_id, $error) = @_;
95 &main::daemon_log("$session_id ERROR: $error: ".$msg, 1);
96 my $out_hash = &main::create_xml_hash("error_".@{$msg_hash->{'header'}}[0], $main::server_address, @{$msg_hash->{'source'}}[0], $error);
97 return &create_xml_string($out_hash);
98 }
100 ## @method opsi_add_product_to_client
101 # Adds an Opsi product to an Opsi client.
102 # @param msg - STRING - xml message with tags hostId and productId
103 # @param msg_hash - HASHREF - message information parsed into a hash
104 # @param session_id - INTEGER - POE session id of the processing of this message
105 # @return out_msg - STRING - feedback to GOsa in success and error case
106 sub opsi_add_product_to_client {
107 my ($msg, $msg_hash, $session_id) = @_;
108 my $header = @{$msg_hash->{'header'}}[0];
109 my $source = @{$msg_hash->{'source'}}[0];
110 my $target = @{$msg_hash->{'target'}}[0];
111 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
112 my ($hostId, $productId);
113 my $error = 0;
115 # Build return message
116 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
117 if (defined $forward_to_gosa) {
118 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
119 }
121 # Sanity check of needed parameter
122 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
123 $error++;
124 &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
125 &add_content2xml_hash($out_hash, "error", "hostId");
126 &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1);
128 }
129 if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
130 $error++;
131 &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
132 &add_content2xml_hash($out_hash, "error", "productId");
133 &main::daemon_log("$session_id ERROR: no productId specified or procutId tag invalid: $msg", 1);
134 }
136 if (not $error) {
137 # Get hostId
138 $hostId = @{$msg_hash->{'hostId'}}[0];
139 &add_content2xml_hash($out_hash, "hostId", $hostId);
141 # Get productID
142 $productId = @{$msg_hash->{'productId'}}[0];
143 &add_content2xml_hash($out_hash, "productId", $productId);
145 # Do an action request for all these -> "setup".
146 my $callobj = {
147 method => 'setProductActionRequest',
148 params => [ $productId, $hostId, "setup" ],
149 id => 1, };
151 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
152 my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
153 if ($sres_err){
154 &main::daemon_log("$session_id ERROR: cannot add product: ".$sres_err_string, 1);
155 &add_content2xml_hash($out_hash, "error", $sres_err_string);
156 }
157 }
159 # return message
160 return ( &create_xml_string($out_hash) );
161 }
163 ## @method opsi_del_product_from_client
164 # Deletes an Opsi-product from an Opsi-client.
165 # @param msg - STRING - xml message with tags hostId and productId
166 # @param msg_hash - HASHREF - message information parsed into a hash
167 # @param session_id - INTEGER - POE session id of the processing of this message
168 # @return out_msg - STRING - feedback to GOsa in success and error case
169 sub opsi_del_product_from_client {
170 my ($msg, $msg_hash, $session_id) = @_;
171 my $header = @{$msg_hash->{'header'}}[0];
172 my $source = @{$msg_hash->{'source'}}[0];
173 my $target = @{$msg_hash->{'target'}}[0];
174 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
175 my ($hostId, $productId);
176 my $error = 0;
177 my ($sres, $sres_err, $sres_err_string);
179 # Build return message
180 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
181 if (defined $forward_to_gosa) {
182 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
183 }
185 # Sanity check of needed parameter
186 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
187 $error++;
188 &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
189 &add_content2xml_hash($out_hash, "error", "hostId");
190 &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1);
192 }
193 if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
194 $error++;
195 &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
196 &add_content2xml_hash($out_hash, "error", "productId");
197 &main::daemon_log("$session_id ERROR: no productId specified or procutId tag invalid: $msg", 1);
198 }
200 # All parameter available
201 if (not $error) {
202 # Get hostId
203 $hostId = @{$msg_hash->{'hostId'}}[0];
204 &add_content2xml_hash($out_hash, "hostId", $hostId);
206 # Get productID
207 $productId = @{$msg_hash->{'productId'}}[0];
208 &add_content2xml_hash($out_hash, "productId", $productId);
211 #TODO : check the results for more than one entry which is currently installed
212 #$callobj = {
213 # method => 'getProductDependencies_listOfHashes',
214 # params => [ $productId ],
215 # id => 1, };
216 #
217 #my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
218 #my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
219 #if ($sres_err){
220 # &main::daemon_log("ERROR: cannot perform dependency check: ".$sres_err_string, 1);
221 # &add_content2xml_hash($out_hash, "error", $sres_err_string);
222 # return ( &create_xml_string($out_hash) );
223 #}
226 # Check to get product action list
227 my $callobj = {
228 method => 'getPossibleProductActions_list',
229 params => [ $productId ],
230 id => 1, };
231 $sres = $main::opsi_client->call($main::opsi_url, $callobj);
232 ($sres_err, $sres_err_string) = &check_opsi_res($sres);
233 if ($sres_err){
234 &main::daemon_log("$session_id ERROR: cannot get product action list: ".$sres_err_string, 1);
235 &add_content2xml_hash($out_hash, "error", $sres_err_string);
236 $error++;
237 }
238 }
240 # Check action uninstall of product
241 if (not $error) {
242 my $uninst_possible= 0;
243 foreach my $r (@{$sres->result}) {
244 if ($r eq 'uninstall') {
245 $uninst_possible= 1;
246 }
247 }
248 if (!$uninst_possible){
249 &main::daemon_log("$session_id ERROR: cannot uninstall product '$productId', product do not has the action 'uninstall'", 1);
250 &add_content2xml_hash($out_hash, "error", "cannot uninstall product '$productId', product do not has the action 'uninstall'");
251 $error++;
252 }
253 }
255 # Set product state to "none"
256 # Do an action request for all these -> "setup".
257 if (not $error) {
258 my $callobj = {
259 method => 'setProductActionRequest',
260 params => [ $productId, $hostId, "none" ],
261 id => 1,
262 };
263 $sres = $main::opsi_client->call($main::opsi_url, $callobj);
264 ($sres_err, $sres_err_string) = &check_opsi_res($sres);
265 if ($sres_err){
266 &main::daemon_log("$session_id ERROR: cannot delete product: ".$sres_err_string, 1);
267 &add_content2xml_hash($out_hash, "error", $sres_err_string);
268 }
269 }
271 # Return message
272 return ( &create_xml_string($out_hash) );
273 }
275 ## @method opsi_add_client
276 # Adds an Opsi client to Opsi.
277 # @param msg - STRING - xml message with tags hostId and macaddress
278 # @param msg_hash - HASHREF - message information parsed into a hash
279 # @param session_id - INTEGER - POE session id of the processing of this message
280 # @return out_msg - STRING - feedback to GOsa in success and error case
281 sub opsi_add_client {
282 my ($msg, $msg_hash, $session_id) = @_;
283 my $header = @{$msg_hash->{'header'}}[0];
284 my $source = @{$msg_hash->{'source'}}[0];
285 my $target = @{$msg_hash->{'target'}}[0];
286 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
287 my ($hostId, $mac);
288 my $error = 0;
289 my ($sres, $sres_err, $sres_err_string);
291 # Build return message with twisted target and source
292 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
293 if (defined $forward_to_gosa) {
294 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
295 }
297 # Sanity check of needed parameter
298 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
299 $error++;
300 &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
301 &add_content2xml_hash($out_hash, "error", "hostId");
302 &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1);
303 }
304 if ((not exists $msg_hash->{'macaddress'}) || (@{$msg_hash->{'macaddress'}} != 1) || (@{$msg_hash->{'macaddress'}}[0] eq ref 'HASH')) {
305 $error++;
306 &add_content2xml_hash($out_hash, "error_string", "no macaddress specified or macaddress tag invalid");
307 &add_content2xml_hash($out_hash, "error", "macaddress");
308 &main::daemon_log("$session_id ERROR: no macaddress specified or macaddress tag invalid: $msg", 1);
309 }
311 if (not $error) {
312 # Get hostId
313 $hostId = @{$msg_hash->{'hostId'}}[0];
314 &add_content2xml_hash($out_hash, "hostId", $hostId);
316 # Get macaddress
317 $mac = @{$msg_hash->{'macaddress'}}[0];
318 &add_content2xml_hash($out_hash, "macaddress", $mac);
320 my $name= $hostId;
321 $name=~ s/^([^.]+).*$/$1/;
322 my $domain= $hostId;
323 $domain=~ s/^[^.]+\.(.*)$/$1/;
324 my ($description, $notes, $ip);
326 if (defined @{$msg_hash->{'description'}}[0]){
327 $description = @{$msg_hash->{'description'}}[0];
328 }
329 if (defined @{$msg_hash->{'notes'}}[0]){
330 $notes = @{$msg_hash->{'notes'}}[0];
331 }
332 if (defined @{$msg_hash->{'ip'}}[0]){
333 $ip = @{$msg_hash->{'ip'}}[0];
334 }
336 my $callobj;
337 $callobj = {
338 method => 'createClient',
339 params => [ $name, $domain, $description, $notes, $ip, $mac ],
340 id => 1,
341 };
343 $sres = $main::opsi_client->call($main::opsi_url, $callobj);
344 ($sres_err, $sres_err_string) = &check_opsi_res($sres);
345 if ($sres_err){
346 &main::daemon_log("$session_id ERROR: cannot create client: ".$sres_err_string, 1);
347 &add_content2xml_hash($out_hash, "error", $sres_err_string);
348 } else {
349 &main::daemon_log("$session_id INFO: add opsi client '$hostId' with mac '$mac'", 5);
350 }
351 }
353 # Return message
354 return ( &create_xml_string($out_hash) );
355 }
357 ## @method opsi_modify_client
358 # Modifies the parameters description, mac or notes for an Opsi client if the corresponding message tags are given.
359 # @param msg - STRING - xml message with tag hostId and optional description, mac or notes
360 # @param msg_hash - HASHREF - message information parsed into a hash
361 # @param session_id - INTEGER - POE session id of the processing of this message
362 # @return out_msg - STRING - feedback to GOsa in success and error case
363 sub opsi_modify_client {
364 my ($msg, $msg_hash, $session_id) = @_;
365 my $header = @{$msg_hash->{'header'}}[0];
366 my $source = @{$msg_hash->{'source'}}[0];
367 my $target = @{$msg_hash->{'target'}}[0];
368 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
369 my $hostId;
370 my $error = 0;
371 my ($sres, $sres_err, $sres_err_string);
373 # Build return message with twisted target and source
374 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
375 if (defined $forward_to_gosa) {
376 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
377 }
379 # Sanity check of needed parameter
380 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
381 $error++;
382 &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
383 &add_content2xml_hash($out_hash, "error", "hostId");
384 &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1);
385 }
387 if (not $error) {
388 # Get hostId
389 $hostId = @{$msg_hash->{'hostId'}}[0];
390 &add_content2xml_hash($out_hash, "hostId", $hostId);
391 my $name= $hostId;
392 $name=~ s/^([^.]+).*$/$1/;
393 my $domain= $hostId;
394 $domain=~ s/^[^.]+(.*)$/$1/;
396 # Modify description, notes or mac if defined
397 my ($description, $notes, $mac);
398 my $callobj;
399 if ((exists $msg_hash->{'description'}) && (@{$msg_hash->{'description'}} == 1) ){
400 $description = @{$msg_hash->{'description'}}[0];
401 $callobj = {
402 method => 'setHostDescription',
403 params => [ $hostId, $description ],
404 id => 1,
405 };
406 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
407 my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
408 if ($sres_err){
409 &main::daemon_log("ERROR: cannot set description: ".$sres_err_string, 1);
410 &add_content2xml_hash($out_hash, "error", $sres_err_string);
411 }
412 }
413 if ((exists $msg_hash->{'notes'}) && (@{$msg_hash->{'notes'}} == 1)) {
414 $notes = @{$msg_hash->{'notes'}}[0];
415 $callobj = {
416 method => 'setHostNotes',
417 params => [ $hostId, $notes ],
418 id => 1,
419 };
420 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
421 my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
422 if ($sres_err){
423 &main::daemon_log("ERROR: cannot set notes: ".$sres_err_string, 1);
424 &add_content2xml_hash($out_hash, "error", $sres_err_string);
425 }
426 }
427 if ((exists $msg_hash->{'mac'}) && (@{$msg_hash->{'mac'}} == 1)){
428 $mac = @{$msg_hash->{'mac'}}[0];
429 $callobj = {
430 method => 'setMacAddress',
431 params => [ $hostId, $mac ],
432 id => 1,
433 };
434 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
435 my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
436 if ($sres_err){
437 &main::daemon_log("ERROR: cannot set mac address: ".$sres_err_string, 1);
438 &add_content2xml_hash($out_hash, "error", $sres_err_string);
439 }
440 }
441 }
443 # Return message
444 return ( &create_xml_string($out_hash) );
445 }
448 ## @method opsi_get_netboot_products
449 # Get netboot products for specific host.
450 # @param msg - STRING - xml message with tag hostId
451 # @param msg_hash - HASHREF - message information parsed into a hash
452 # @param session_id - INTEGER - POE session id of the processing of this message
453 # @return out_msg - STRING - feedback to GOsa in success and error case
454 sub opsi_get_netboot_products {
455 my ($msg, $msg_hash, $session_id) = @_;
456 my $header = @{$msg_hash->{'header'}}[0];
457 my $source = @{$msg_hash->{'source'}}[0];
458 my $target = @{$msg_hash->{'target'}}[0];
459 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
460 my $hostId;
461 my $xml_msg;
463 # Build return message with twisted target and source
464 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
465 if (defined $forward_to_gosa) {
466 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
467 }
469 # Get hostId if defined
470 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1)) {
471 $hostId = @{$msg_hash->{'hostId'}}[0];
472 &add_content2xml_hash($out_hash, "hostId", $hostId);
473 }
475 &add_content2xml_hash($out_hash, "xxx", "");
476 $xml_msg = &create_xml_string($out_hash);
477 # For hosts, only return the products that are or get installed
478 my $callobj;
479 $callobj = {
480 method => 'getNetBootProductIds_list',
481 params => [ ],
482 id => 1,
483 };
484 &main::daemon_log("$session_id DEBUG: send callobj to opsi_client: ".&opsi_callobj2string($callobj), 7);
485 &main::daemon_log("$session_id DEBUG: opsi_url $main::opsi_url", 7);
486 &main::daemon_log("$session_id DEBUG: waiting for answer from opsi_client!", 7);
487 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
488 &main::daemon_log("$session_id DEBUG: get answer from opsi_client", 7);
489 my %r = ();
490 for (@{$res->result}) { $r{$_} = 1 }
492 if (not &check_opsi_res($res)){
494 if (defined $hostId){
496 $callobj = {
497 method => 'getProductStates_hash',
498 params => [ $hostId ],
499 id => 1,
500 };
502 my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
503 if (not &check_opsi_res($hres)){
504 my $htmp= $hres->result->{$hostId};
506 # check state != not_installed or action == setup -> load and add
507 foreach my $product (@{$htmp}){
509 if (!defined ($r{$product->{'productId'}})){
510 next;
511 }
513 # Now we've a couple of hashes...
514 if ($product->{'installationStatus'} ne "not_installed" or
515 $product->{'actionRequest'} eq "setup"){
516 my $state= "<state>".$product->{'installationStatus'}."</state><action>".$product->{'actionRequest'}."</action>";
518 $callobj = {
519 method => 'getProduct_hash',
520 params => [ $product->{'productId'} ],
521 id => 1,
522 };
524 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
525 if (not &check_opsi_res($sres)){
526 my $tres= $sres->result;
528 my $name= xml_quote($tres->{'name'});
529 my $r= $product->{'productId'};
530 my $description= xml_quote($tres->{'description'});
531 $name=~ s/\//\\\//;
532 $description=~ s/\//\\\//;
533 $xml_msg=~ s/<xxx><\/xxx>/\n<item><productId>$r<\/productId><name>$name<\/name><description>$description<\/description><\/item>$state<xxx><\/xxx>/;
534 }
535 }
536 }
538 }
540 } else {
541 foreach my $r (@{$res->result}) {
542 $callobj = {
543 method => 'getProduct_hash',
544 params => [ $r ],
545 id => 1,
546 };
548 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
549 if (not &check_opsi_res($sres)){
550 my $tres= $sres->result;
552 my $name= xml_quote($tres->{'name'});
553 my $description= xml_quote($tres->{'description'});
554 $name=~ s/\//\\\//;
555 $description=~ s/\//\\\//;
556 $xml_msg=~ s/<xxx><\/xxx>/\n<item><productId>$r<\/productId><name>$name<\/name><description>$description<\/description><\/item><xxx><\/xxx>/;
557 }
558 }
560 }
561 }
562 $xml_msg=~ s/<xxx><\/xxx>//;
564 # Return message
565 return ( $xml_msg );
566 }
569 ## @method opsi_get_product_properties
570 # Get product properties for a product and a specific host or gobally for a product.
571 # @param msg - STRING - xml message with tags productId and optional hostId
572 # @param msg_hash - HASHREF - message information parsed into a hash
573 # @param session_id - INTEGER - POE session id of the processing of this message
574 # @return out_msg - STRING - feedback to GOsa in success and error case
575 sub opsi_get_product_properties {
576 my ($msg, $msg_hash, $session_id) = @_;
577 my $header = @{$msg_hash->{'header'}}[0];
578 my $source = @{$msg_hash->{'source'}}[0];
579 my $target = @{$msg_hash->{'target'}}[0];
580 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
581 my ($hostId, $productId);
582 my $xml_msg;
584 # Build return message with twisted target and source
585 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
586 if (defined $forward_to_gosa) {
587 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
588 }
590 # Sanity check of needed parameter
591 if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
592 &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
593 &add_content2xml_hash($out_hash, "error", "productId");
594 &main::daemon_log("$session_id ERROR: no productId specified or productId tag invalid: $msg", 1);
596 # Return message
597 return ( &create_xml_string($out_hash) );
598 }
600 # Get productid
601 $productId = @{$msg_hash->{'productId'}}[0];
602 &add_content2xml_hash($out_hash, "producId", "$productId");
604 # Get hostId if defined
605 if (defined @{$msg_hash->{'hostId'}}[0]){
606 $hostId = @{$msg_hash->{'hostId'}}[0];
607 &add_content2xml_hash($out_hash, "hostId", $hostId);
608 }
610 # Load actions
611 my $callobj = {
612 method => 'getPossibleProductActions_list',
613 params => [ $productId ],
614 id => 1,
615 };
616 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
617 if (not &check_opsi_res($res)){
618 foreach my $action (@{$res->result}){
619 &add_content2xml_hash($out_hash, "action", $action);
620 }
621 }
623 # Add place holder
624 &add_content2xml_hash($out_hash, "xxx", "");
626 # Move to XML string
627 $xml_msg= &create_xml_string($out_hash);
629 # JSON Query
630 if (defined $hostId){
631 $callobj = {
632 method => 'getProductProperties_hash',
633 params => [ $productId, $hostId ],
634 id => 1,
635 };
636 } else {
637 $callobj = {
638 method => 'getProductProperties_hash',
639 params => [ $productId ],
640 id => 1,
641 };
642 }
643 $res = $main::opsi_client->call($main::opsi_url, $callobj);
645 # JSON Query 2
646 $callobj = {
647 method => 'getProductPropertyDefinitions_listOfHashes',
648 params => [ $productId ],
649 id => 1,
650 };
652 # Assemble options
653 my $res2 = $main::opsi_client->call($main::opsi_url, $callobj);
654 my $values = {};
655 my $descriptions = {};
656 if (not &check_opsi_res($res2)){
657 my $r= $res2->result;
659 foreach my $entr (@$r){
660 # Unroll values
661 my $cnv;
662 if (UNIVERSAL::isa( $entr->{'values'}, "ARRAY" )){
663 foreach my $v (@{$entr->{'values'}}){
664 $cnv.= "<value>$v</value>";
665 }
666 } else {
667 $cnv= $entr->{'values'};
668 }
669 $values->{$entr->{'name'}}= $cnv;
670 $descriptions->{$entr->{'name'}}= "<description>".$entr->{'description'}."</description>";
671 }
672 }
674 if (not &check_opsi_res($res)){
675 my $r= $res->result;
676 foreach my $key (keys %{$r}) {
677 my $item= "\n<item>";
678 my $value= $r->{$key};
679 my $dsc= "";
680 my $vals= "";
681 if (defined $descriptions->{$key}){
682 $dsc= $descriptions->{$key};
683 }
684 if (defined $values->{$key}){
685 $vals= $values->{$key};
686 }
687 $item.= "<$key>$dsc<default>".xml_quote($value)."</default>$vals</$key>";
688 $item.= "</item>";
689 $xml_msg=~ s/<xxx><\/xxx>/$item<xxx><\/xxx>/;
690 }
691 }
693 $xml_msg=~ s/<xxx><\/xxx>//;
695 # Return message
696 return ( $xml_msg );
697 }
700 ## @method opsi_set_product_properties
701 # 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.
702 # @param msg - STRING - xml message with tags productId, action, state and optional hostId, action and state
703 # @param msg_hash - HASHREF - message information parsed into a hash
704 # @param session_id - INTEGER - POE session id of the processing of this message
705 # @return out_msg - STRING - feedback to GOsa in success and error case
706 sub opsi_set_product_properties {
707 my ($msg, $msg_hash, $session_id) = @_;
708 my $header = @{$msg_hash->{'header'}}[0];
709 my $source = @{$msg_hash->{'source'}}[0];
710 my $target = @{$msg_hash->{'target'}}[0];
711 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
712 my ($productId, $hostId);
714 # Build return message with twisted target and source
715 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
716 if (defined $forward_to_gosa) {
717 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
718 }
720 # Sanity check of needed parameter
721 if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
722 &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
723 &add_content2xml_hash($out_hash, "error", "productId");
724 &main::daemon_log("$session_id ERROR: no productId specified or productId tag invalid: $msg", 1);
725 return ( &create_xml_string($out_hash) );
726 }
727 if (not exists $msg_hash->{'item'}) {
728 &add_content2xml_hash($out_hash, "error_string", "message needs one xml-tag 'item' and within the xml-tags 'name' and 'value'");
729 &add_content2xml_hash($out_hash, "error", "item");
730 &main::daemon_log("$session_id ERROR: message needs one xml-tag 'item' and within the xml-tags 'name' and 'value': $msg", 1);
731 return ( &create_xml_string($out_hash) );
732 } else {
733 if ((not exists @{$msg_hash->{'item'}}[0]->{'name'}) || (@{@{$msg_hash->{'item'}}[0]->{'name'}} != 1 )) {
734 &add_content2xml_hash($out_hash, "error_string", "message needs within the xml-tag 'item' one xml-tags 'name'");
735 &add_content2xml_hash($out_hash, "error", "name");
736 &main::daemon_log("$session_id ERROR: message needs within the xml-tag 'item' one xml-tags 'name': $msg", 1);
737 return ( &create_xml_string($out_hash) );
738 }
739 if ((not exists @{$msg_hash->{'item'}}[0]->{'value'}) || (@{@{$msg_hash->{'item'}}[0]->{'value'}} != 1 )) {
740 &add_content2xml_hash($out_hash, "error_string", "message needs within the xml-tag 'item' one xml-tags 'value'");
741 &add_content2xml_hash($out_hash, "error", "value");
742 &main::daemon_log("$session_id ERROR: message needs within the xml-tag 'item' one xml-tags 'value': $msg", 1);
743 return ( &create_xml_string($out_hash) );
744 }
745 }
746 # if no hostId is given, set_product_properties will act on globally
747 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} > 1)) {
748 &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
749 &add_content2xml_hash($out_hash, "error", "hostId");
750 &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1);
751 return ( &create_xml_string($out_hash) );
752 }
755 # Get productId
756 $productId = @{$msg_hash->{'productId'}}[0];
757 &add_content2xml_hash($out_hash, "productId", $productId);
759 # Get hostId if defined
760 if (exists $msg_hash->{'hostId'}){
761 $hostId = @{$msg_hash->{'hostId'}}[0];
762 &add_content2xml_hash($out_hash, "hostId", $hostId);
763 }
765 # Set product states if requested
766 if (defined @{$msg_hash->{'action'}}[0]){
767 &_set_action($productId, @{$msg_hash->{'action'}}[0], $hostId);
768 }
769 if (defined @{$msg_hash->{'state'}}[0]){
770 &_set_state($productId, @{$msg_hash->{'state'}}[0], $hostId);
771 }
773 # Find properties
774 foreach my $item (@{$msg_hash->{'item'}}){
775 # JSON Query
776 my $callobj;
778 if (defined $hostId){
779 $callobj = {
780 method => 'setProductProperty',
781 params => [ $productId, $item->{'name'}[0], $item->{'value'}[0], $hostId ],
782 id => 1,
783 };
784 } else {
785 $callobj = {
786 method => 'setProductProperty',
787 params => [ $productId, $item->{'name'}[0], $item->{'value'}[0] ],
788 id => 1,
789 };
790 }
792 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
793 my ($res_err, $res_err_string) = &check_opsi_res($res);
795 if ($res_err){
796 &main::daemon_log("$session_id ERROR: communication failed while setting '".$item->{'name'}[0]."': ".$res_err_string, 1);
797 &add_content2xml_hash($out_hash, "error", $res_err_string);
798 }
799 }
802 # Return message
803 return ( &create_xml_string($out_hash) );
804 }
807 ## @method opsi_get_client_hardware
808 # Reports client hardware inventory.
809 # @param msg - STRING - xml message with tag hostId
810 # @param msg_hash - HASHREF - message information parsed into a hash
811 # @param session_id - INTEGER - POE session id of the processing of this message
812 # @return out_msg - STRING - feedback to GOsa in success and error case
813 sub opsi_get_client_hardware {
814 my ($msg, $msg_hash, $session_id) = @_;
815 my $header = @{$msg_hash->{'header'}}[0];
816 my $source = @{$msg_hash->{'source'}}[0];
817 my $target = @{$msg_hash->{'target'}}[0];
818 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
819 my $hostId;
820 my $error = 0;
821 my $xml_msg;
823 # Build return message with twisted target and source
824 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
825 if (defined $forward_to_gosa) {
826 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
827 }
829 # Sanity check of needed parameter
830 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
831 $error++;
832 &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
833 &add_content2xml_hash($out_hash, "error", "hostId");
834 &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1);
835 }
837 if (not $error) {
839 # Get hostId
840 $hostId = @{$msg_hash->{'hostId'}}[0];
841 &add_content2xml_hash($out_hash, "hostId", "$hostId");
842 &add_content2xml_hash($out_hash, "xxx", "");
843 }
845 # Move to XML string
846 $xml_msg= &create_xml_string($out_hash);
848 if (not $error) {
850 # JSON Query
851 my $callobj = {
852 method => 'getHardwareInformation_hash',
853 params => [ $hostId ],
854 id => 1,
855 };
857 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
858 if (not &check_opsi_res($res)){
859 my $result= $res->result;
860 if (ref $result eq "HASH") {
861 foreach my $r (keys %{$result}){
862 my $item= "\n<item><id>".xml_quote($r)."</id>";
863 my $value= $result->{$r};
864 foreach my $sres (@{$value}){
866 foreach my $dres (keys %{$sres}){
867 if (defined $sres->{$dres}){
868 $item.= "<$dres>".xml_quote($sres->{$dres})."</$dres>";
869 }
870 }
872 }
873 $item.= "</item>";
874 $xml_msg=~ s%<xxx></xxx>%$item<xxx></xxx>%;
876 }
877 }
878 }
880 $xml_msg=~ s/<xxx><\/xxx>//;
882 }
884 # Return message
885 return ( $xml_msg );
886 }
889 ## @method opsi_list_clients
890 # Reports all Opsi clients.
891 # @param msg - STRING - xml message
892 # @param msg_hash - HASHREF - message information parsed into a hash
893 # @param session_id - INTEGER - POE session id of the processing of this message
894 # @return out_msg - STRING - feedback to GOsa in success and error case
895 sub opsi_list_clients {
896 my ($msg, $msg_hash, $session_id) = @_;
897 my $header = @{$msg_hash->{'header'}}[0];
898 my $source = @{$msg_hash->{'source'}}[0];
899 my $target = @{$msg_hash->{'target'}}[0];
900 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
902 # Build return message with twisted target and source
903 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
904 if (defined $forward_to_gosa) {
905 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
906 }
907 &add_content2xml_hash($out_hash, "xxx", "");
909 # Move to XML string
910 my $xml_msg= &create_xml_string($out_hash);
912 # JSON Query
913 my $callobj = {
914 method => 'getClients_listOfHashes',
915 params => [ ],
916 id => 1,
917 };
918 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
919 if (not &check_opsi_res($res)){
920 foreach my $host (@{$res->result}){
921 my $item= "\n<item><name>".$host->{'hostId'}."</name>";
922 if (defined($host->{'description'})){
923 $item.= "<description>".xml_quote($host->{'description'})."</description>";
924 }
925 if (defined($host->{'notes'})){
926 $item.= "<notes>".xml_quote($host->{'notes'})."</notes>";
927 }
928 if (defined($host->{'lastSeen'})){
929 $item.= "<lastSeen>".xml_quote($host->{'lastSeen'})."</lastSeen>";
930 }
932 $callobj = {
933 method => 'getIpAddress',
934 params => [ $host->{'hostId'} ],
935 id => 1,
936 };
937 my $sres= $main::opsi_client->call($main::opsi_url, $callobj);
938 if ( not &check_opsi_res($sres)){
939 $item.= "<ip>".xml_quote($sres->result)."</ip>";
940 }
942 $callobj = {
943 method => 'getMacAddress',
944 params => [ $host->{'hostId'} ],
945 id => 1,
946 };
947 $sres= $main::opsi_client->call($main::opsi_url, $callobj);
948 if ( not &check_opsi_res($sres)){
949 $item.= "<mac>".xml_quote($sres->result)."</mac>";
950 }
951 $item.= "</item>";
952 $xml_msg=~ s%<xxx></xxx>%$item<xxx></xxx>%;
953 }
954 }
956 $xml_msg=~ s/<xxx><\/xxx>//;
957 return ( $xml_msg );
958 }
962 ## @method opsi_get_client_software
963 # Reports client software inventory.
964 # @param msg - STRING - xml message with tag hostId
965 # @param msg_hash - HASHREF - message information parsed into a hash
966 # @param session_id - INTEGER - POE session id of the processing of this message
967 # @return out_msg - STRING - feedback to GOsa in success and error case
968 sub opsi_get_client_software {
969 my ($msg, $msg_hash, $session_id) = @_;
970 my $header = @{$msg_hash->{'header'}}[0];
971 my $source = @{$msg_hash->{'source'}}[0];
972 my $target = @{$msg_hash->{'target'}}[0];
973 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
974 my $error = 0;
975 my $hostId;
976 my $xml_msg;
978 # Build return message with twisted target and source
979 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
980 if (defined $forward_to_gosa) {
981 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
982 }
984 # Sanity check of needed parameter
985 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
986 $error++;
987 &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
988 &add_content2xml_hash($out_hash, "error", "hostId");
989 &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1);
990 }
992 if (not $error) {
994 # Get hostId
995 $hostId = @{$msg_hash->{'hostId'}}[0];
996 &add_content2xml_hash($out_hash, "hostId", "$hostId");
997 &add_content2xml_hash($out_hash, "xxx", "");
998 }
1000 $xml_msg= &create_xml_string($out_hash);
1002 if (not $error) {
1004 # JSON Query
1005 my $callobj = {
1006 method => 'getSoftwareInformation_hash',
1007 params => [ $hostId ],
1008 id => 1,
1009 };
1011 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1012 if (not &check_opsi_res($res)){
1013 my $result= $res->result;
1014 }
1016 $xml_msg=~ s/<xxx><\/xxx>//;
1018 }
1020 # Return message
1021 return ( $xml_msg );
1022 }
1025 ## @method opsi_get_local_products
1026 # Reports product for given hostId or globally.
1027 # @param msg - STRING - xml message with optional tag hostId
1028 # @param msg_hash - HASHREF - message information parsed into a hash
1029 # @param session_id - INTEGER - POE session id of the processing of this message
1030 # @return out_msg - STRING - feedback to GOsa in success and error case
1031 sub opsi_get_local_products {
1032 my ($msg, $msg_hash, $session_id) = @_;
1033 my $header = @{$msg_hash->{'header'}}[0];
1034 my $source = @{$msg_hash->{'source'}}[0];
1035 my $target = @{$msg_hash->{'target'}}[0];
1036 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1037 my $hostId;
1039 # Build return message with twisted target and source
1040 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1041 if (defined $forward_to_gosa) {
1042 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1043 }
1044 &add_content2xml_hash($out_hash, "xxx", "");
1046 # Get hostId if defined
1047 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1)) {
1048 $hostId = @{$msg_hash->{'hostId'}}[0];
1049 &add_content2xml_hash($out_hash, "hostId", $hostId);
1050 }
1052 # Move to XML string
1053 my $xml_msg= &create_xml_string($out_hash);
1055 # For hosts, only return the products that are or get installed
1056 my $callobj;
1057 $callobj = {
1058 method => 'getLocalBootProductIds_list',
1059 params => [ ],
1060 id => 1,
1061 };
1063 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1064 my %r = ();
1065 for (@{$res->result}) { $r{$_} = 1 }
1067 if (not &check_opsi_res($res)){
1069 if (defined $hostId){
1070 $callobj = {
1071 method => 'getProductStates_hash',
1072 params => [ $hostId ],
1073 id => 1,
1074 };
1076 my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
1077 if (not &check_opsi_res($hres)){
1078 my $htmp= $hres->result->{$hostId};
1080 # Check state != not_installed or action == setup -> load and add
1081 foreach my $product (@{$htmp}){
1083 if (!defined ($r{$product->{'productId'}})){
1084 next;
1085 }
1087 # Now we've a couple of hashes...
1088 if ($product->{'installationStatus'} ne "not_installed" or
1089 $product->{'actionRequest'} eq "setup"){
1090 my $state= "<state>".$product->{'installationStatus'}."</state><action>".$product->{'actionRequest'}."</action>";
1092 $callobj = {
1093 method => 'getProduct_hash',
1094 params => [ $product->{'productId'} ],
1095 id => 1,
1096 };
1098 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
1099 if (not &check_opsi_res($sres)){
1100 my $tres= $sres->result;
1102 my $name= xml_quote($tres->{'name'});
1103 my $r= $product->{'productId'};
1104 my $description= xml_quote($tres->{'description'});
1105 $name=~ s/\//\\\//;
1106 $description=~ s/\//\\\//;
1107 $xml_msg=~ s/<xxx><\/xxx>/\n<item><productId>$r<\/productId><name>$name<\/name><description>$description<\/description><\/item>$state<xxx><\/xxx>/;
1108 }
1110 }
1111 }
1113 }
1115 } else {
1116 foreach my $r (@{$res->result}) {
1117 $callobj = {
1118 method => 'getProduct_hash',
1119 params => [ $r ],
1120 id => 1,
1121 };
1123 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
1124 if (not &check_opsi_res($sres)){
1125 my $tres= $sres->result;
1127 my $name= xml_quote($tres->{'name'});
1128 my $description= xml_quote($tres->{'description'});
1129 $name=~ s/\//\\\//;
1130 $description=~ s/\//\\\//;
1131 $xml_msg=~ s/<xxx><\/xxx>/\n<item><productId>$r<\/productId><name>$name<\/name><description>$description<\/description><\/item><xxx><\/xxx>/;
1132 }
1134 }
1136 }
1137 }
1139 $xml_msg=~ s/<xxx><\/xxx>//;
1141 # Retrun Message
1142 return ( $xml_msg );
1143 }
1146 ## @method opsi_del_client
1147 # Deletes a client from Opsi.
1148 # @param msg - STRING - xml message with tag hostId
1149 # @param msg_hash - HASHREF - message information parsed into a hash
1150 # @param session_id - INTEGER - POE session id of the processing of this message
1151 # @return out_msg - STRING - feedback to GOsa in success and error case
1152 sub opsi_del_client {
1153 my ($msg, $msg_hash, $session_id) = @_;
1154 my $header = @{$msg_hash->{'header'}}[0];
1155 my $source = @{$msg_hash->{'source'}}[0];
1156 my $target = @{$msg_hash->{'target'}}[0];
1157 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1158 my $hostId;
1159 my $error = 0;
1161 # Build return message with twisted target and source
1162 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1163 if (defined $forward_to_gosa) {
1164 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1165 }
1167 # Sanity check of needed parameter
1168 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
1169 $error++;
1170 &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
1171 &add_content2xml_hash($out_hash, "error", "hostId");
1172 &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1);
1173 }
1175 if (not $error) {
1177 # Get hostId
1178 $hostId = @{$msg_hash->{'hostId'}}[0];
1179 &add_content2xml_hash($out_hash, "hostId", "$hostId");
1181 # JSON Query
1182 my $callobj = {
1183 method => 'deleteClient',
1184 params => [ $hostId ],
1185 id => 1,
1186 };
1187 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1188 }
1190 # Move to XML string
1191 my $xml_msg= &create_xml_string($out_hash);
1193 # Return message
1194 return ( $xml_msg );
1195 }
1198 ## @method opsi_install_client
1199 # Set a client in Opsi to install and trigger a wake on lan message (WOL).
1200 # @param msg - STRING - xml message with tags hostId, macaddress
1201 # @param msg_hash - HASHREF - message information parsed into a hash
1202 # @param session_id - INTEGER - POE session id of the processing of this message
1203 # @return out_msg - STRING - feedback to GOsa in success and error case
1204 sub opsi_install_client {
1205 my ($msg, $msg_hash, $session_id) = @_;
1206 my $header = @{$msg_hash->{'header'}}[0];
1207 my $source = @{$msg_hash->{'source'}}[0];
1208 my $target = @{$msg_hash->{'target'}}[0];
1209 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1212 my ($hostId, $macaddress);
1214 my $error = 0;
1215 my @out_msg_l;
1217 # Build return message with twisted target and source
1218 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1219 if (defined $forward_to_gosa) {
1220 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1221 }
1223 # Sanity check of needed parameter
1224 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
1225 $error++;
1226 &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
1227 &add_content2xml_hash($out_hash, "error", "hostId");
1228 &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1);
1229 }
1230 if ((not exists $msg_hash->{'macaddress'}) || (@{$msg_hash->{'macaddress'}} != 1) || (@{$msg_hash->{'macaddress'}}[0] eq ref 'HASH') ) {
1231 $error++;
1232 &add_content2xml_hash($out_hash, "error_string", "no macaddress specified or macaddress tag invalid");
1233 &add_content2xml_hash($out_hash, "error", "macaddress");
1234 &main::daemon_log("$session_id ERROR: no macaddress specified or macaddress tag invalid: $msg", 1);
1235 } else {
1236 if ((exists $msg_hash->{'macaddress'}) &&
1237 ($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)) {
1238 $macaddress = $1;
1239 } else {
1240 $error ++;
1241 &add_content2xml_hash($out_hash, "error_string", "given mac address is not correct");
1242 &add_content2xml_hash($out_hash, "error", "macaddress");
1243 &main::daemon_log("$session_id ERROR: given mac address is not correct: $msg", 1);
1244 }
1245 }
1247 if (not $error) {
1249 # Get hostId
1250 $hostId = @{$msg_hash->{'hostId'}}[0];
1251 &add_content2xml_hash($out_hash, "hostId", "$hostId");
1253 # Load all products for this host with status != "not_installed" or actionRequest != "none"
1254 my $callobj = {
1255 method => 'getProductStates_hash',
1256 params => [ $hostId ],
1257 id => 1,
1258 };
1260 my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
1261 if (not &check_opsi_res($hres)){
1262 my $htmp= $hres->result->{$hostId};
1264 # check state != not_installed or action == setup -> load and add
1265 foreach my $product (@{$htmp}){
1266 # Now we've a couple of hashes...
1267 if ($product->{'installationStatus'} ne "not_installed" or
1268 $product->{'actionRequest'} ne "none"){
1270 # Do an action request for all these -> "setup".
1271 $callobj = {
1272 method => 'setProductActionRequest',
1273 params => [ $product->{'productId'}, $hostId, "setup" ],
1274 id => 1,
1275 };
1276 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1277 my ($res_err, $res_err_string) = &check_opsi_res($res);
1278 if ($res_err){
1279 &main::daemon_log("$session_id ERROR: cannot set product action request for '$hostId': ".$product->{'productId'}, 1);
1280 } else {
1281 &main::daemon_log("$session_id INFO: requesting 'setup' for '".$product->{'productId'}."' on $hostId", 1);
1282 }
1283 }
1284 }
1285 }
1286 push(@out_msg_l, &create_xml_string($out_hash));
1289 # Build wakeup message for client
1290 if (not $error) {
1291 my $wakeup_hash = &create_xml_hash("trigger_wake", "GOSA", "KNOWN_SERVER");
1292 &add_content2xml_hash($wakeup_hash, 'macaddress', $macaddress);
1293 my $wakeup_msg = &create_xml_string($wakeup_hash);
1294 push(@out_msg_l, $wakeup_msg);
1296 # invoke trigger wake for this gosa-si-server
1297 &main::server_server_com::trigger_wake($wakeup_msg, $wakeup_hash, $session_id);
1298 }
1299 }
1301 # Return messages
1302 return @out_msg_l;
1303 }
1306 ## @method _set_action
1307 # Set action for an Opsi client
1308 # @param product - STRING - Opsi product
1309 # @param action - STRING - action
1310 # @param hostId - STRING - Opsi hostId
1311 sub _set_action {
1312 my $product= shift;
1313 my $action = shift;
1314 my $hostId = shift;
1315 my $callobj;
1317 $callobj = {
1318 method => 'setProductActionRequest',
1319 params => [ $product, $hostId, $action],
1320 id => 1,
1321 };
1323 $main::opsi_client->call($main::opsi_url, $callobj);
1324 }
1326 ## @method _set_state
1327 # Set state for an Opsi client
1328 # @param product - STRING - Opsi product
1329 # @param action - STRING - state
1330 # @param hostId - STRING - Opsi hostId
1331 sub _set_state {
1332 my $product = shift;
1333 my $state = shift;
1334 my $hostId = shift;
1335 my $callobj;
1337 $callobj = {
1338 method => 'setProductState',
1339 params => [ $product, $hostId, $state ],
1340 id => 1,
1341 };
1343 $main::opsi_client->call($main::opsi_url, $callobj);
1344 }
1346 # TODO
1347 ################################
1348 #
1349 # @brief Create a license pool at Opsi server.
1350 # @param licensePoolId The name of the pool (optional).
1351 # @param description The description of the pool (optional).
1352 # @param productIds A list of assigned porducts of the pool (optional).
1353 # @param windowsSoftwareIds A list of windows software IDs associated to the pool (optional).
1354 #
1355 sub opsi_createLicensePool {
1356 my ($msg, $msg_hash, $session_id) = @_;
1357 my $header = @{$msg_hash->{'header'}}[0];
1358 my $source = @{$msg_hash->{'source'}}[0];
1359 my $target = @{$msg_hash->{'target'}}[0];
1360 my $out_hash;
1361 my $licensePoolId = defined $msg_hash->{'licensePoolId'} ? @{$msg_hash->{'licensePoolId'}}[0] : undef;
1362 my $description = defined $msg_hash->{'description'} ? @{$msg_hash->{'description'}}[0] : undef;
1363 my @productIds = defined $msg_hash->{'productIds'} ? $msg_hash->{'productIds'} : undef;
1364 my @windowsSoftwareIds = defined $msg_hash->{'windowsSoftwareIds'} ? $msg_hash->{'windowsSoftwareIds'} : undef;
1366 # Create license Pool
1367 my $callobj = {
1368 method => 'createLicensePool',
1369 params => [ $licensePoolId, $description, @productIds, @windowsSoftwareIds],
1370 id => 1,
1371 };
1372 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1374 # Check Opsi error
1375 my ($res_error, $res_error_str) = &check_opsi_res($res);
1376 if ($res_error){
1377 # Create error message
1378 &main::daemon_log("$session_id ERROR: cannot create license pool at Opsi server: ".$res_error_str, 1);
1379 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1380 return ( &create_xml_string($out_hash) );
1381 }
1383 # Create function result message
1384 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source, $res->result);
1386 return ( &create_xml_string($out_hash) );
1387 }
1389 ################################
1390 #
1391 # @brief Return licensePoolId, description, productIds and windowsSoftwareIds for all found license pools.
1392 #
1393 sub opsi_getLicensePools_listOfHashes {
1394 my ($msg, $msg_hash, $session_id) = @_;
1395 my $header = @{$msg_hash->{'header'}}[0];
1396 my $source = @{$msg_hash->{'source'}}[0];
1397 my $out_hash;
1399 # Fetch infos from Opsi server
1400 my $callobj = {
1401 method => 'getLicensePools_listOfHashes',
1402 params => [ ],
1403 id => 1,
1404 };
1405 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1407 # Check Opsi error
1408 my ($res_error, $res_error_str) = &check_opsi_res($res);
1409 if ($res_error){
1410 # Create error message
1411 &main::daemon_log("$session_id ERROR: cannot get license pool ID list from Opsi server: ".$res_error_str, 1);
1412 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1413 return ( &create_xml_string($out_hash) );
1414 }
1416 # Create function result message
1417 my $res_hash = { 'hit'=> [] };
1418 foreach my $licensePool ( @{$res->result}) {
1419 my $licensePool_hash = { 'licensePoolId' => [$licensePool->{'licensePoolId'}],
1420 'description' => [$licensePool->{'description'}],
1421 'productIds' => $licensePool->{'productIds'},
1422 'windowsSoftwareIds' => $licensePool->{'windowsSoftwareIds'},
1423 };
1424 push( @{$res_hash->{hit}}, $licensePool_hash );
1425 }
1427 # Create function result message
1428 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1429 $out_hash->{result} = [$res_hash];
1431 return ( &create_xml_string($out_hash) );
1432 }
1434 ################################
1435 #
1436 # @brief Return productIds, windowsSoftwareIds and description for a given licensePoolId
1437 # @param licensePoolId The name of the pool.
1438 #
1439 sub opsi_getLicensePool_hash {
1440 my ($msg, $msg_hash, $session_id) = @_;
1441 my $header = @{$msg_hash->{'header'}}[0];
1442 my $source = @{$msg_hash->{'source'}}[0];
1443 my $target = @{$msg_hash->{'target'}}[0];
1444 my $licensePoolId;
1445 my $out_hash;
1447 # Check input sanity
1448 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1449 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1450 } else {
1451 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1452 }
1454 # Fetch infos from Opsi server
1455 my $callobj = {
1456 method => 'getLicensePool_hash',
1457 params => [ $licensePoolId ],
1458 id => 1,
1459 };
1460 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1462 # Check Opsi error
1463 my ($res_error, $res_error_str) = &check_opsi_res($res);
1464 if ($res_error){
1465 # Create error message
1466 &main::daemon_log("$session_id ERROR: cannot get license pool from Opsi server: ".$res_error_str, 1);
1467 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source);
1468 &add_content2xml_hash($out_hash, "error", $res_error_str);
1469 return ( &create_xml_string($out_hash) );
1470 }
1472 # Create function result message
1473 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1474 &add_content2xml_hash($out_hash, "licensePoolId", $res->result->{'licensePoolId'});
1475 &add_content2xml_hash($out_hash, "description", $res->result->{'description'});
1476 map(&add_content2xml_hash($out_hash, "productIds", "$_"), @{ $res->result->{'productIds'} });
1477 map(&add_content2xml_hash($out_hash, "windowsSoftwareIds", "$_"), @{ $res->result->{'windowsSoftwareIds'} });
1479 return ( &create_xml_string($out_hash) );
1480 }
1482 ################################
1483 #
1484 # @brief Returns softwareLicenseId, notes, licenseKey, hostId and licensePoolId for optional given licensePoolId and hostId
1485 # @param hostid Something like client_1.intranet.mydomain.de (optional).
1486 # @param licensePoolId The name of the pool (optional).
1487 #
1488 sub opsi_getSoftwareLicenseUsages_listOfHashes {
1489 my ($msg, $msg_hash, $session_id) = @_;
1490 my $header = @{$msg_hash->{'header'}}[0];
1491 my $source = @{$msg_hash->{'source'}}[0];
1492 my $target = @{$msg_hash->{'target'}}[0];
1493 my $licensePoolId = defined $msg_hash->{'licensePoolId'} ? @{$msg_hash->{'licensePoolId'}}[0] : undef;
1494 my $hostId = defined $msg_hash->{'hostId'} ? @{$msg_hash->{'hostId'}}[0] : undef;
1495 my $out_hash;
1497 # Fetch information from Opsi server
1498 my $callobj = {
1499 method => 'getSoftwareLicenseUsages_listOfHashes',
1500 params => [ $hostId, $licensePoolId ],
1501 id => 1,
1502 };
1503 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1505 # Check Opsi error
1506 my ($res_error, $res_error_str) = &check_opsi_res($res);
1507 if ($res_error){
1508 # Create error message
1509 &main::daemon_log("$session_id ERROR: cannot fetch software licenses from license pool '$licensePoolId': ".$res_error_str, 1);
1510 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1511 return ( &create_xml_string($out_hash) );
1512 }
1514 # Parse Opsi result
1515 my $res_hash = { 'hit'=> [] };
1516 foreach my $license ( @{$res->result}) {
1517 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
1518 'notes' => [$license->{'notes'}],
1519 'licenseKey' => [$license->{'licenseKey'}],
1520 'hostId' => [$license->{'hostId'}],
1521 'licensePoolId' => [$license->{'licensePoolId'}],
1522 };
1523 push( @{$res_hash->{hit}}, $license_hash );
1524 }
1526 # Create function result message
1527 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1528 $out_hash->{result} = [$res_hash];
1530 return ( &create_xml_string($out_hash) );
1531 }
1533 ################################
1534 #
1535 # @brief Returns expirationDate, boundToHost, maxInstallation, licenseTyp, licensePoolIds and licenseKeys for a given softwareLicense ID.
1536 # @param softwareLicenseId Identificator of a license.
1537 #
1538 sub opsi_getSoftwareLicense_hash {
1539 my ($msg, $msg_hash, $session_id) = @_;
1540 my $header = @{$msg_hash->{'header'}}[0];
1541 my $source = @{$msg_hash->{'source'}}[0];
1542 my $target = @{$msg_hash->{'target'}}[0];
1543 my $softwareLicenseId;
1544 my $out_hash;
1546 # Check input sanity
1547 if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
1548 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
1549 } else {
1550 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1551 }
1553 my $callobj = {
1554 method => 'getSoftwareLicense_hash',
1555 params => [ $softwareLicenseId ],
1556 id => 1,
1557 };
1558 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1560 # Check Opsi error
1561 my ($res_error, $res_error_str) = &check_opsi_res($res);
1562 if ($res_error){
1563 # Create error message
1564 &main::daemon_log("$session_id ERROR: cannot fetch information for license '$softwareLicenseId': ".$res_error_str, 1);
1565 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1566 return ( &create_xml_string($out_hash) );
1567 }
1569 # Create function result message
1570 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1571 &add_content2xml_hash($out_hash, "expirationDate", $res->result->{'expirationDate'});
1572 &add_content2xml_hash($out_hash, "boundToHost", $res->result->{'boundToHost'});
1573 &add_content2xml_hash($out_hash, "maxInstallations", $res->result->{'maxInstallations'});
1574 &add_content2xml_hash($out_hash, "licenseTyp", $res->result->{'licenseTyp'});
1575 foreach my $licensePoolId ( @{$res->result->{'licensePoolIds'}}) {
1576 &add_content2xml_hash($out_hash, "licensePoolId", $licensePoolId);
1577 &add_content2xml_hash($out_hash, $licensePoolId, $res->result->{'licenseKeys'}->{$licensePoolId});
1578 }
1580 return ( &create_xml_string($out_hash) );
1581 }
1583 ################################
1584 #
1585 # @brief Delete licnese pool by license pool ID. A pool can only be deleted if there are no software licenses bound to the pool.
1586 # The fixed parameter deleteLicenses=True specifies that all software licenses bound to the pool are being deleted.
1587 # @param licensePoolId The name of the pool.
1588 #
1589 sub opsi_deleteLicensePool {
1590 my ($msg, $msg_hash, $session_id) = @_;
1591 my $header = @{$msg_hash->{'header'}}[0];
1592 my $source = @{$msg_hash->{'source'}}[0];
1593 my $target = @{$msg_hash->{'target'}}[0];
1594 my $licensePoolId;
1595 my $out_hash;
1597 # Check input sanity
1598 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1599 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1600 } else {
1601 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1602 }
1604 # Fetch softwareLicenseIds used in license pool
1605 # This has to be done because function deleteLicensePool deletes the pool and the corresponding software licenses
1606 # but not the license contracts of the software licenses. In our case each software license has exactly one license contract.
1607 my $callobj = {
1608 method => 'getSoftwareLicenses_listOfHashes',
1609 params => [ ],
1610 id => 1,
1611 };
1612 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1614 # Keep list of licenseContractIds in mind to delete it after the deletion of the software licenses
1615 my @lCI_toBeDeleted;
1616 foreach my $softwareLicenseHash ( @{$res->result} ) {
1617 if ((@{$softwareLicenseHash->{'licensePoolIds'}} == 0) || (@{$softwareLicenseHash->{'licensePoolIds'}}[0] ne $licensePoolId)) {
1618 next;
1619 }
1620 push (@lCI_toBeDeleted, $softwareLicenseHash->{'licenseContractId'});
1621 }
1623 # Delete license pool at Opsi server
1624 $callobj = {
1625 method => 'deleteLicensePool',
1626 params => [ $licensePoolId, 'deleteLicenses=True' ],
1627 id => 1,
1628 };
1629 $res = $main::opsi_client->call($main::opsi_url, $callobj);
1630 my ($res_error, $res_error_str) = &check_opsi_res($res);
1631 if ($res_error){
1632 # Create error message
1633 &main::daemon_log("$session_id ERROR: cannot delete license pool at Opsi server: ".$res_error_str, 1);
1634 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1635 return ( &create_xml_string($out_hash) );
1636 }
1638 # Delete each license contract connected with the license pool
1639 foreach my $licenseContractId ( @lCI_toBeDeleted ) {
1640 my $callobj = {
1641 method => 'deleteLicenseContract',
1642 params => [ $licenseContractId ],
1643 id => 1,
1644 };
1645 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1646 my ($res_error, $res_error_str) = &check_opsi_res($res);
1647 if ($res_error){
1648 # Create error message
1649 &main::daemon_log("$session_id ERROR: cannot delete license contract '$licenseContractId' connected with license pool '$licensePoolId' at Opsi server: ".$res_error_str, 1);
1650 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1651 return ( &create_xml_string($out_hash) );
1652 }
1653 }
1655 # Create function result message
1656 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1658 return ( &create_xml_string($out_hash) );
1659 }
1661 ################################
1662 #
1663 # @brief Create a license contract, create a software license and add the software license to the license pool
1664 # @param licensePoolId The name of the pool the license should be assigned.
1665 # @param licenseKey The license key.
1666 # @param partner Name of the license partner (optional).
1667 # @param conclusionDate Date of conclusion of license contract (optional)
1668 # @param notificationDate Date of notification that license is running out soon (optional).
1669 # @param notes This is the place for some notes (optional)
1670 # @param softwareLicenseId Identificator of a license (optional).
1671 # @param licenseTyp Typ of a licnese, either "OEM", "VOLUME" or "RETAIL" (optional).
1672 # @param maxInstallations The number of clients use this license (optional).
1673 # @param boundToHost The name of the client the license is bound to (optional).
1674 # @param expirationDate The date when the license is running down (optional).
1675 #
1676 sub opsi_createLicense {
1677 my ($msg, $msg_hash, $session_id) = @_;
1678 my $header = @{$msg_hash->{'header'}}[0];
1679 my $source = @{$msg_hash->{'source'}}[0];
1680 my $target = @{$msg_hash->{'target'}}[0];
1681 my $partner = defined $msg_hash->{'partner'} ? @{$msg_hash->{'partner'}}[0] : undef;
1682 my $conclusionDate = defined $msg_hash->{'conclusionDate'} ? @{$msg_hash->{'conclusionDate'}}[0] : undef;
1683 my $notificationDate = defined $msg_hash->{'notificationDate'} ? @{$msg_hash->{'notificationDate'}}[0] : undef;
1684 my $notes = defined $msg_hash->{'notes'} ? @{$msg_hash->{'notes'}}[0] : undef;
1685 my $licenseContractId;
1686 my $softwareLicenseId = defined $msg_hash->{'licenseId'} ? @{$msg_hash->{'licenseId'}}[0] : undef;
1687 my $licenseType = defined $msg_hash->{'licenseType'} ? @{$msg_hash->{'licenseType'}}[0] : undef;
1688 my $maxInstallations = defined $msg_hash->{'maxInstallations'} ? @{$msg_hash->{'maxInstallations'}}[0] : undef;
1689 my $boundToHost = defined $msg_hash->{'boundToHost'} ? @{$msg_hash->{'boundToHost'}}[0] : undef;
1690 my $expirationDate = defined $msg_hash->{'expirationDate'} ? @{$msg_hash->{'expirationDate'}}[0] : undef;
1691 my $licensePoolId;
1692 my $licenseKey;
1693 my $out_hash;
1695 # Check input sanity
1696 if (&_check_xml_tag_is_ok ($msg_hash, 'licenseKey')) {
1697 $licenseKey = @{$msg_hash->{'licenseKey'}}[0];
1698 } else {
1699 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1700 }
1701 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1702 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1703 } else {
1704 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1705 }
1706 if ((defined $licenseType) && (not exists $licenseTyp_hash->{$licenseType})) {
1707 return ( &_give_feedback($msg, $msg_hash, $session_id, "The typ of a license can be either 'OEM', 'VOLUME' or 'RETAIL'."));
1708 }
1710 # Create license contract at Opsi server
1711 my $callobj = {
1712 method => 'createLicenseContract',
1713 params => [ undef, $partner, $conclusionDate, $notificationDate, undef, $notes ],
1714 id => 1,
1715 };
1716 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1718 # Check Opsi error
1719 my ($res_error, $res_error_str) = &check_opsi_res($res);
1720 if ($res_error){
1721 # Create error message
1722 &main::daemon_log("$session_id ERROR: cannot create license contract at Opsi server: ".$res_error_str, 1);
1723 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1724 return ( &create_xml_string($out_hash) );
1725 }
1727 $licenseContractId = $res->result;
1729 # Create software license at Opsi server
1730 $callobj = {
1731 method => 'createSoftwareLicense',
1732 params => [ $softwareLicenseId, $licenseContractId, $licenseType, $maxInstallations, $boundToHost, $expirationDate ],
1733 id => 1,
1734 };
1735 $res = $main::opsi_client->call($main::opsi_url, $callobj);
1737 # Check Opsi error
1738 ($res_error, $res_error_str) = &check_opsi_res($res);
1739 if ($res_error){
1740 # Create error message
1741 &main::daemon_log("$session_id ERROR: cannot create software license at Opsi server: ".$res_error_str, 1);
1742 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1743 return ( &create_xml_string($out_hash) );
1744 }
1746 $softwareLicenseId = $res->result;
1748 # Add software license to license pool
1749 $callobj = {
1750 method => 'addSoftwareLicenseToLicensePool',
1751 params => [ $softwareLicenseId, $licensePoolId, $licenseKey ],
1752 id => 1,
1753 };
1754 $res = $main::opsi_client->call($main::opsi_url, $callobj);
1756 # Check Opsi error
1757 ($res_error, $res_error_str) = &check_opsi_res($res);
1758 if ($res_error){
1759 # Create error message
1760 &main::daemon_log("$session_id ERROR: cannot add software license to license pool at Opsi server: ".$res_error_str, 1);
1761 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1762 return ( &create_xml_string($out_hash) );
1763 }
1765 # Create function result message
1766 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1768 return ( &create_xml_string($out_hash) );
1769 }
1771 ################################
1772 #
1773 # @brief Assign a software license to a host
1774 # @param hostid Something like client_1.intranet.mydomain.de
1775 # @param licensePoolId The name of the pool.
1776 #
1777 sub opsi_assignSoftwareLicenseToHost {
1778 my ($msg, $msg_hash, $session_id) = @_;
1779 my $header = @{$msg_hash->{'header'}}[0];
1780 my $source = @{$msg_hash->{'source'}}[0];
1781 my $target = @{$msg_hash->{'target'}}[0];
1782 my $hostId;
1783 my $licensePoolId;
1785 # Check input sanity
1786 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1787 $hostId = @{$msg_hash->{'hostId'}}[0];
1788 } else {
1789 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1790 }
1791 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1792 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1793 } else {
1794 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1795 }
1797 # Assign a software license to a host
1798 my $callobj = {
1799 method => 'getAndAssignSoftwareLicenseKey',
1800 params => [ $hostId, $licensePoolId ],
1801 id => 1,
1802 };
1803 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1805 # Check Opsi error
1806 my ($res_error, $res_error_str) = &check_opsi_res($res);
1807 if ($res_error){
1808 # Create error message
1809 &main::daemon_log("$session_id ERROR: cannot assign a software license to a host at Opsi server: ".$res_error_str, 1);
1810 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1811 return ( &create_xml_string($out_hash) );
1812 }
1814 # Create function result message
1815 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1817 return ( &create_xml_string($out_hash) );
1818 }
1820 ################################
1821 #
1822 # @brief Unassign a software license from a host.
1823 # @param hostid Something like client_1.intranet.mydomain.de
1824 # @param licensePoolId The name of the pool.
1825 #
1826 sub opsi_unassignSoftwareLicenseFromHost {
1827 my ($msg, $msg_hash, $session_id) = @_;
1828 my $header = @{$msg_hash->{'header'}}[0];
1829 my $source = @{$msg_hash->{'source'}}[0];
1830 my $target = @{$msg_hash->{'target'}}[0];
1831 my $hostId;
1832 my $licensePoolId;
1834 # Check input sanity
1835 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1836 $hostId = @{$msg_hash->{'hostId'}}[0];
1837 } else {
1838 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1839 }
1840 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1841 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1842 } else {
1843 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1844 }
1846 # Unassign a software license from a host
1847 my $callobj = {
1848 method => 'deleteSoftwareLicenseUsage',
1849 params => [ $hostId, '', $licensePoolId ],
1850 id => 1,
1851 };
1852 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1854 # Check Opsi error
1855 my ($res_error, $res_error_str) = &check_opsi_res($res);
1856 if ($res_error){
1857 # Create error message
1858 &main::daemon_log("$session_id ERROR: cannot unassign a software license from a host at Opsi server: ".$res_error_str, 1);
1859 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1860 return ( &create_xml_string($out_hash) );
1861 }
1863 # Create function result message
1864 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1866 return ( &create_xml_string($out_hash) );
1867 }
1869 ################################
1870 #
1871 # @brief Unassign all software licenses from a host
1872 # @param hostid Something like client_1.intranet.mydomain.de
1873 #
1874 sub opsi_unassignAllSoftwareLicensesFromHost {
1875 my ($msg, $msg_hash, $session_id) = @_;
1876 my $header = @{$msg_hash->{'header'}}[0];
1877 my $source = @{$msg_hash->{'source'}}[0];
1878 my $target = @{$msg_hash->{'target'}}[0];
1879 my $hostId;
1881 # Check input sanity
1882 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1883 $hostId = @{$msg_hash->{'hostId'}}[0];
1884 } else {
1885 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1886 }
1888 # Unassign all software licenses from a host
1889 my $callobj = {
1890 method => 'deleteAllSoftwareLicenseUsages',
1891 params => [ $hostId ],
1892 id => 1,
1893 };
1894 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1896 # Check Opsi error
1897 my ($res_error, $res_error_str) = &check_opsi_res($res);
1898 if ($res_error){
1899 # Create error message
1900 &main::daemon_log("$session_id ERROR: cannot unassign a software license from a host at Opsi server: ".$res_error_str, 1);
1901 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1902 return ( &create_xml_string($out_hash) );
1903 }
1905 # Create function result message
1906 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1908 return ( &create_xml_string($out_hash) );
1909 }
1912 ################################
1913 #
1914 # @brief Returns the assigned licensePoolId and licenses, how often the product is installed and at which host
1915 # and the number of max and remaining installations for a given OPSI product.
1916 # @param productId Identificator of an OPSI product.
1917 #
1918 sub opsi_getLicenseInformationForProduct {
1919 my ($msg, $msg_hash, $session_id) = @_;
1920 my $header = @{$msg_hash->{'header'}}[0];
1921 my $source = @{$msg_hash->{'source'}}[0];
1922 my $productId;
1923 my $out_hash;
1925 # Check input sanity
1926 if (&_check_xml_tag_is_ok ($msg_hash, 'productId')) {
1927 $productId = @{$msg_hash->{'productId'}}[0];
1928 } else {
1929 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1930 }
1932 # Fetch infos from Opsi server
1933 my $callobj = {
1934 method => 'getLicensePoolId',
1935 params => [ $productId ],
1936 id => 1,
1937 };
1938 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1940 # Check Opsi error
1941 my ($res_error, $res_error_str) = &check_opsi_res($res);
1942 if ($res_error){
1943 # Create error message
1944 &main::daemon_log("$session_id ERROR: cannot get license pool for product '$productId' : ".$res_error_str, 1);
1945 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1946 return ( &create_xml_string($out_hash) );
1947 }
1949 my $licensePoolId = $res->result;
1951 # Fetch statistic information for given pool ID
1952 my $callobj = {
1953 method => 'getLicenseStatistics_hash',
1954 params => [ ],
1955 id => 1,
1956 };
1957 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1959 # Check Opsi error
1960 my ($res_error, $res_error_str) = &check_opsi_res($res);
1961 if ($res_error){
1962 # Create error message
1963 &main::daemon_log("$session_id ERROR: cannot get statistic informations for license pools : ".$res_error_str, 1);
1964 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1965 return ( &create_xml_string($out_hash) );
1966 }
1968 # Create function result message
1969 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1970 &add_content2xml_hash($out_hash, "licensePoolId", $licensePoolId);
1971 &add_content2xml_hash($out_hash, "licenses", $res->result->{$licensePoolId}->{'licenses'});
1972 &add_content2xml_hash($out_hash, "usageCount", $res->result->{$licensePoolId}->{'usageCount'});
1973 &add_content2xml_hash($out_hash, "maxInstallations", $res->result->{$licensePoolId}->{'maxInstallations'});
1974 &add_content2xml_hash($out_hash, "remainingInstallations", $res->result->{$licensePoolId}->{'remainingInstallations'});
1975 map(&add_content2xml_hash($out_hash, "usedBy", "$_"), @{ $res->result->{$licensePoolId}->{'usedBy'}});
1977 return ( &create_xml_string($out_hash) );
1978 }
1980 sub opsi_test {
1981 my ($msg, $msg_hash, $session_id) = @_;
1982 my $header = @{$msg_hash->{'header'}}[0];
1983 my $source = @{$msg_hash->{'source'}}[0];
1984 my $pram1 = @{$msg_hash->{'productId'}}[0];
1986 print STDERR Dumper $pram1;
1988 # Fetch infos from Opsi server
1989 my $callobj = {
1990 method => 'getLicensePoolId',
1991 params => [ $pram1 ],
1992 id => 1,
1993 };
1994 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1996 print STDERR Dumper $res;
1997 return ();
1998 }
1999 1;