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_getLicenses_list",
31 "opsi_getLicense_hash",
32 "opsi_getSoftwareLicense_hash",
33 "opsi_getLicensePool_hash",
34 "opsi_getSoftwareLicenseUsages_listOfHashes",
35 "opsi_getLicensePools_listOfHashes",
36 "opsi_getLicenseInformationForProduct",
37 "opsi_test",
38 );
39 @EXPORT = @events;
41 use strict;
42 use warnings;
43 use GOSA::GosaSupportDaemon;
44 use Data::Dumper;
45 use XML::Quote qw(:all);
47 BEGIN {}
49 END {}
51 # ----------------------------------------------------------------------------
52 # D E C L A R A T I O N S
53 # ----------------------------------------------------------------------------
55 my $licenseTyp_hash = { 'OEM'=>'', 'VOLUME'=>'', 'RETAIL'=>''};
59 # ----------------------------------------------------------------------------
60 # S U B R O U T I N E S
61 # ----------------------------------------------------------------------------
64 ################################
65 #
66 # @brief A function returning a list of functions which are exported by importing the module.
67 # @return List of all provided functions
68 #
69 sub get_events {
70 return \@events;
71 }
73 ################################
74 #
75 # @brief Checks if there is a specified tag and if the the tag has a content.
76 # @return 0|1
77 #
78 sub _check_xml_tag_is_ok {
79 my ($msg_hash,$tag) = @_;
80 if (not defined $msg_hash->{$tag}) {
81 $_ = "message contains no tag '$tag'";
82 return 0;
83 }
84 if (ref @{$msg_hash->{$tag}}[0] eq 'HASH') {
85 $_ = "message tag '$tag' has no content";
86 return 0;
87 }
88 return 1;
89 }
91 ################################
92 #
93 # @brief Writes the log line and returns the error message for GOsa.
94 #
95 sub _give_feedback {
96 my ($msg, $msg_hash, $session_id, $error) = @_;
97 &main::daemon_log("$session_id ERROR: $error: ".$msg, 1);
98 my $out_hash = &main::create_xml_hash("error_".@{$msg_hash->{'header'}}[0], $main::server_address, @{$msg_hash->{'source'}}[0], $error);
99 return &create_xml_string($out_hash);
100 }
102 ## @method opsi_add_product_to_client
103 # Adds an Opsi product to an Opsi client.
104 # @param msg - STRING - xml message with tags hostId and productId
105 # @param msg_hash - HASHREF - message information parsed into a hash
106 # @param session_id - INTEGER - POE session id of the processing of this message
107 # @return out_msg - STRING - feedback to GOsa in success and error case
108 sub opsi_add_product_to_client {
109 my ($msg, $msg_hash, $session_id) = @_;
110 my $header = @{$msg_hash->{'header'}}[0];
111 my $source = @{$msg_hash->{'source'}}[0];
112 my $target = @{$msg_hash->{'target'}}[0];
113 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
114 my ($hostId, $productId);
115 my $error = 0;
117 # Build return message
118 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
119 if (defined $forward_to_gosa) {
120 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
121 }
123 # Sanity check of needed parameter
124 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
125 $error++;
126 &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
127 &add_content2xml_hash($out_hash, "error", "hostId");
128 &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1);
130 }
131 if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
132 $error++;
133 &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
134 &add_content2xml_hash($out_hash, "error", "productId");
135 &main::daemon_log("$session_id ERROR: no productId specified or procutId tag invalid: $msg", 1);
136 }
138 if (not $error) {
139 # Get hostId
140 $hostId = @{$msg_hash->{'hostId'}}[0];
141 &add_content2xml_hash($out_hash, "hostId", $hostId);
143 # Get productID
144 $productId = @{$msg_hash->{'productId'}}[0];
145 &add_content2xml_hash($out_hash, "productId", $productId);
147 # Do an action request for all these -> "setup".
148 my $callobj = {
149 method => 'setProductActionRequest',
150 params => [ $productId, $hostId, "setup" ],
151 id => 1, };
153 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
154 my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
155 if ($sres_err){
156 &main::daemon_log("$session_id ERROR: cannot add product: ".$sres_err_string, 1);
157 &add_content2xml_hash($out_hash, "error", $sres_err_string);
158 }
159 }
161 # return message
162 return ( &create_xml_string($out_hash) );
163 }
165 ## @method opsi_del_product_from_client
166 # Deletes an Opsi-product from an Opsi-client.
167 # @param msg - STRING - xml message with tags hostId and productId
168 # @param msg_hash - HASHREF - message information parsed into a hash
169 # @param session_id - INTEGER - POE session id of the processing of this message
170 # @return out_msg - STRING - feedback to GOsa in success and error case
171 sub opsi_del_product_from_client {
172 my ($msg, $msg_hash, $session_id) = @_;
173 my $header = @{$msg_hash->{'header'}}[0];
174 my $source = @{$msg_hash->{'source'}}[0];
175 my $target = @{$msg_hash->{'target'}}[0];
176 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
177 my ($hostId, $productId);
178 my $error = 0;
179 my ($sres, $sres_err, $sres_err_string);
181 # Build return message
182 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
183 if (defined $forward_to_gosa) {
184 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
185 }
187 # Sanity check of needed parameter
188 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
189 $error++;
190 &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
191 &add_content2xml_hash($out_hash, "error", "hostId");
192 &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1);
194 }
195 if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
196 $error++;
197 &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
198 &add_content2xml_hash($out_hash, "error", "productId");
199 &main::daemon_log("$session_id ERROR: no productId specified or procutId tag invalid: $msg", 1);
200 }
202 # All parameter available
203 if (not $error) {
204 # Get hostId
205 $hostId = @{$msg_hash->{'hostId'}}[0];
206 &add_content2xml_hash($out_hash, "hostId", $hostId);
208 # Get productID
209 $productId = @{$msg_hash->{'productId'}}[0];
210 &add_content2xml_hash($out_hash, "productId", $productId);
213 #TODO : check the results for more than one entry which is currently installed
214 #$callobj = {
215 # method => 'getProductDependencies_listOfHashes',
216 # params => [ $productId ],
217 # id => 1, };
218 #
219 #my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
220 #my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
221 #if ($sres_err){
222 # &main::daemon_log("ERROR: cannot perform dependency check: ".$sres_err_string, 1);
223 # &add_content2xml_hash($out_hash, "error", $sres_err_string);
224 # return ( &create_xml_string($out_hash) );
225 #}
228 # Check to get product action list
229 my $callobj = {
230 method => 'getPossibleProductActions_list',
231 params => [ $productId ],
232 id => 1, };
233 $sres = $main::opsi_client->call($main::opsi_url, $callobj);
234 ($sres_err, $sres_err_string) = &check_opsi_res($sres);
235 if ($sres_err){
236 &main::daemon_log("$session_id ERROR: cannot get product action list: ".$sres_err_string, 1);
237 &add_content2xml_hash($out_hash, "error", $sres_err_string);
238 $error++;
239 }
240 }
242 # Check action uninstall of product
243 if (not $error) {
244 my $uninst_possible= 0;
245 foreach my $r (@{$sres->result}) {
246 if ($r eq 'uninstall') {
247 $uninst_possible= 1;
248 }
249 }
250 if (!$uninst_possible){
251 &main::daemon_log("$session_id ERROR: cannot uninstall product '$productId', product do not has the action 'uninstall'", 1);
252 &add_content2xml_hash($out_hash, "error", "cannot uninstall product '$productId', product do not has the action 'uninstall'");
253 $error++;
254 }
255 }
257 # Set product state to "none"
258 # Do an action request for all these -> "setup".
259 if (not $error) {
260 my $callobj = {
261 method => 'setProductActionRequest',
262 params => [ $productId, $hostId, "none" ],
263 id => 1,
264 };
265 $sres = $main::opsi_client->call($main::opsi_url, $callobj);
266 ($sres_err, $sres_err_string) = &check_opsi_res($sres);
267 if ($sres_err){
268 &main::daemon_log("$session_id ERROR: cannot delete product: ".$sres_err_string, 1);
269 &add_content2xml_hash($out_hash, "error", $sres_err_string);
270 }
271 }
273 # Return message
274 return ( &create_xml_string($out_hash) );
275 }
277 ## @method opsi_add_client
278 # Adds an Opsi client to Opsi.
279 # @param msg - STRING - xml message with tags hostId and macaddress
280 # @param msg_hash - HASHREF - message information parsed into a hash
281 # @param session_id - INTEGER - POE session id of the processing of this message
282 # @return out_msg - STRING - feedback to GOsa in success and error case
283 sub opsi_add_client {
284 my ($msg, $msg_hash, $session_id) = @_;
285 my $header = @{$msg_hash->{'header'}}[0];
286 my $source = @{$msg_hash->{'source'}}[0];
287 my $target = @{$msg_hash->{'target'}}[0];
288 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
289 my ($hostId, $mac);
290 my $error = 0;
291 my ($sres, $sres_err, $sres_err_string);
293 # Build return message with twisted target and source
294 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
295 if (defined $forward_to_gosa) {
296 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
297 }
299 # Sanity check of needed parameter
300 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
301 $error++;
302 &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
303 &add_content2xml_hash($out_hash, "error", "hostId");
304 &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1);
305 }
306 if ((not exists $msg_hash->{'macaddress'}) || (@{$msg_hash->{'macaddress'}} != 1) || (@{$msg_hash->{'macaddress'}}[0] eq ref 'HASH')) {
307 $error++;
308 &add_content2xml_hash($out_hash, "error_string", "no macaddress specified or macaddress tag invalid");
309 &add_content2xml_hash($out_hash, "error", "macaddress");
310 &main::daemon_log("$session_id ERROR: no macaddress specified or macaddress tag invalid: $msg", 1);
311 }
313 if (not $error) {
314 # Get hostId
315 $hostId = @{$msg_hash->{'hostId'}}[0];
316 &add_content2xml_hash($out_hash, "hostId", $hostId);
318 # Get macaddress
319 $mac = @{$msg_hash->{'macaddress'}}[0];
320 &add_content2xml_hash($out_hash, "macaddress", $mac);
322 my $name= $hostId;
323 $name=~ s/^([^.]+).*$/$1/;
324 my $domain= $hostId;
325 $domain=~ s/^[^.]+\.(.*)$/$1/;
326 my ($description, $notes, $ip);
328 if (defined @{$msg_hash->{'description'}}[0]){
329 $description = @{$msg_hash->{'description'}}[0];
330 }
331 if (defined @{$msg_hash->{'notes'}}[0]){
332 $notes = @{$msg_hash->{'notes'}}[0];
333 }
334 if (defined @{$msg_hash->{'ip'}}[0]){
335 $ip = @{$msg_hash->{'ip'}}[0];
336 }
338 my $callobj;
339 $callobj = {
340 method => 'createClient',
341 params => [ $name, $domain, $description, $notes, $ip, $mac ],
342 id => 1,
343 };
345 $sres = $main::opsi_client->call($main::opsi_url, $callobj);
346 ($sres_err, $sres_err_string) = &check_opsi_res($sres);
347 if ($sres_err){
348 &main::daemon_log("$session_id ERROR: cannot create client: ".$sres_err_string, 1);
349 &add_content2xml_hash($out_hash, "error", $sres_err_string);
350 } else {
351 &main::daemon_log("$session_id INFO: add opsi client '$hostId' with mac '$mac'", 5);
352 }
353 }
355 # Return message
356 return ( &create_xml_string($out_hash) );
357 }
359 ## @method opsi_modify_client
360 # Modifies the parameters description, mac or notes for an Opsi client if the corresponding message tags are given.
361 # @param msg - STRING - xml message with tag hostId and optional description, mac or notes
362 # @param msg_hash - HASHREF - message information parsed into a hash
363 # @param session_id - INTEGER - POE session id of the processing of this message
364 # @return out_msg - STRING - feedback to GOsa in success and error case
365 sub opsi_modify_client {
366 my ($msg, $msg_hash, $session_id) = @_;
367 my $header = @{$msg_hash->{'header'}}[0];
368 my $source = @{$msg_hash->{'source'}}[0];
369 my $target = @{$msg_hash->{'target'}}[0];
370 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
371 my $hostId;
372 my $error = 0;
373 my ($sres, $sres_err, $sres_err_string);
375 # Build return message with twisted target and source
376 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
377 if (defined $forward_to_gosa) {
378 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
379 }
381 # Sanity check of needed parameter
382 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
383 $error++;
384 &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
385 &add_content2xml_hash($out_hash, "error", "hostId");
386 &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1);
387 }
389 if (not $error) {
390 # Get hostId
391 $hostId = @{$msg_hash->{'hostId'}}[0];
392 &add_content2xml_hash($out_hash, "hostId", $hostId);
393 my $name= $hostId;
394 $name=~ s/^([^.]+).*$/$1/;
395 my $domain= $hostId;
396 $domain=~ s/^[^.]+(.*)$/$1/;
398 # Modify description, notes or mac if defined
399 my ($description, $notes, $mac);
400 my $callobj;
401 if ((exists $msg_hash->{'description'}) && (@{$msg_hash->{'description'}} == 1) ){
402 $description = @{$msg_hash->{'description'}}[0];
403 $callobj = {
404 method => 'setHostDescription',
405 params => [ $hostId, $description ],
406 id => 1,
407 };
408 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
409 my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
410 if ($sres_err){
411 &main::daemon_log("ERROR: cannot set description: ".$sres_err_string, 1);
412 &add_content2xml_hash($out_hash, "error", $sres_err_string);
413 }
414 }
415 if ((exists $msg_hash->{'notes'}) && (@{$msg_hash->{'notes'}} == 1)) {
416 $notes = @{$msg_hash->{'notes'}}[0];
417 $callobj = {
418 method => 'setHostNotes',
419 params => [ $hostId, $notes ],
420 id => 1,
421 };
422 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
423 my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
424 if ($sres_err){
425 &main::daemon_log("ERROR: cannot set notes: ".$sres_err_string, 1);
426 &add_content2xml_hash($out_hash, "error", $sres_err_string);
427 }
428 }
429 if ((exists $msg_hash->{'mac'}) && (@{$msg_hash->{'mac'}} == 1)){
430 $mac = @{$msg_hash->{'mac'}}[0];
431 $callobj = {
432 method => 'setMacAddress',
433 params => [ $hostId, $mac ],
434 id => 1,
435 };
436 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
437 my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
438 if ($sres_err){
439 &main::daemon_log("ERROR: cannot set mac address: ".$sres_err_string, 1);
440 &add_content2xml_hash($out_hash, "error", $sres_err_string);
441 }
442 }
443 }
445 # Return message
446 return ( &create_xml_string($out_hash) );
447 }
450 ## @method opsi_get_netboot_products
451 # Get netboot products for specific host.
452 # @param msg - STRING - xml message with tag hostId
453 # @param msg_hash - HASHREF - message information parsed into a hash
454 # @param session_id - INTEGER - POE session id of the processing of this message
455 # @return out_msg - STRING - feedback to GOsa in success and error case
456 sub opsi_get_netboot_products {
457 my ($msg, $msg_hash, $session_id) = @_;
458 my $header = @{$msg_hash->{'header'}}[0];
459 my $source = @{$msg_hash->{'source'}}[0];
460 my $target = @{$msg_hash->{'target'}}[0];
461 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
462 my $hostId;
463 my $xml_msg;
465 # Build return message with twisted target and source
466 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
467 if (defined $forward_to_gosa) {
468 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
469 }
471 # Get hostId if defined
472 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1)) {
473 $hostId = @{$msg_hash->{'hostId'}}[0];
474 &add_content2xml_hash($out_hash, "hostId", $hostId);
475 }
477 &add_content2xml_hash($out_hash, "xxx", "");
478 $xml_msg = &create_xml_string($out_hash);
479 # For hosts, only return the products that are or get installed
480 my $callobj;
481 $callobj = {
482 method => 'getNetBootProductIds_list',
483 params => [ ],
484 id => 1,
485 };
486 &main::daemon_log("$session_id DEBUG: send callobj to opsi_client: ".&opsi_callobj2string($callobj), 7);
487 &main::daemon_log("$session_id DEBUG: opsi_url $main::opsi_url", 7);
488 &main::daemon_log("$session_id DEBUG: waiting for answer from opsi_client!", 7);
489 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
490 &main::daemon_log("$session_id DEBUG: get answer from opsi_client", 7);
491 my %r = ();
492 for (@{$res->result}) { $r{$_} = 1 }
494 if (not &check_opsi_res($res)){
496 if (defined $hostId){
498 $callobj = {
499 method => 'getProductStates_hash',
500 params => [ $hostId ],
501 id => 1,
502 };
504 my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
505 if (not &check_opsi_res($hres)){
506 my $htmp= $hres->result->{$hostId};
508 # check state != not_installed or action == setup -> load and add
509 foreach my $product (@{$htmp}){
511 if (!defined ($r{$product->{'productId'}})){
512 next;
513 }
515 # Now we've a couple of hashes...
516 if ($product->{'installationStatus'} ne "not_installed" or
517 $product->{'actionRequest'} eq "setup"){
518 my $state= "<state>".$product->{'installationStatus'}."</state><action>".$product->{'actionRequest'}."</action>";
520 $callobj = {
521 method => 'getProduct_hash',
522 params => [ $product->{'productId'} ],
523 id => 1,
524 };
526 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
527 if (not &check_opsi_res($sres)){
528 my $tres= $sres->result;
530 my $name= xml_quote($tres->{'name'});
531 my $r= $product->{'productId'};
532 my $description= xml_quote($tres->{'description'});
533 $name=~ s/\//\\\//;
534 $description=~ s/\//\\\//;
535 $xml_msg=~ s/<xxx><\/xxx>/\n<item><productId>$r<\/productId><name>$name<\/name><description>$description<\/description><\/item>$state<xxx><\/xxx>/;
536 }
537 }
538 }
540 }
542 } else {
543 foreach my $r (@{$res->result}) {
544 $callobj = {
545 method => 'getProduct_hash',
546 params => [ $r ],
547 id => 1,
548 };
550 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
551 if (not &check_opsi_res($sres)){
552 my $tres= $sres->result;
554 my $name= xml_quote($tres->{'name'});
555 my $description= xml_quote($tres->{'description'});
556 $name=~ s/\//\\\//;
557 $description=~ s/\//\\\//;
558 $xml_msg=~ s/<xxx><\/xxx>/\n<item><productId>$r<\/productId><name>$name<\/name><description>$description<\/description><\/item><xxx><\/xxx>/;
559 }
560 }
562 }
563 }
564 $xml_msg=~ s/<xxx><\/xxx>//;
566 # Return message
567 return ( $xml_msg );
568 }
571 ## @method opsi_get_product_properties
572 # Get product properties for a product and a specific host or gobally for a product.
573 # @param msg - STRING - xml message with tags productId and optional hostId
574 # @param msg_hash - HASHREF - message information parsed into a hash
575 # @param session_id - INTEGER - POE session id of the processing of this message
576 # @return out_msg - STRING - feedback to GOsa in success and error case
577 sub opsi_get_product_properties {
578 my ($msg, $msg_hash, $session_id) = @_;
579 my $header = @{$msg_hash->{'header'}}[0];
580 my $source = @{$msg_hash->{'source'}}[0];
581 my $target = @{$msg_hash->{'target'}}[0];
582 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
583 my ($hostId, $productId);
584 my $xml_msg;
586 # Build return message with twisted target and source
587 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
588 if (defined $forward_to_gosa) {
589 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
590 }
592 # Sanity check of needed parameter
593 if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
594 &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
595 &add_content2xml_hash($out_hash, "error", "productId");
596 &main::daemon_log("$session_id ERROR: no productId specified or productId tag invalid: $msg", 1);
598 # Return message
599 return ( &create_xml_string($out_hash) );
600 }
602 # Get productid
603 $productId = @{$msg_hash->{'productId'}}[0];
604 &add_content2xml_hash($out_hash, "producId", "$productId");
606 # Get hostId if defined
607 if (defined @{$msg_hash->{'hostId'}}[0]){
608 $hostId = @{$msg_hash->{'hostId'}}[0];
609 &add_content2xml_hash($out_hash, "hostId", $hostId);
610 }
612 # Load actions
613 my $callobj = {
614 method => 'getPossibleProductActions_list',
615 params => [ $productId ],
616 id => 1,
617 };
618 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
619 if (not &check_opsi_res($res)){
620 foreach my $action (@{$res->result}){
621 &add_content2xml_hash($out_hash, "action", $action);
622 }
623 }
625 # Add place holder
626 &add_content2xml_hash($out_hash, "xxx", "");
628 # Move to XML string
629 $xml_msg= &create_xml_string($out_hash);
631 # JSON Query
632 if (defined $hostId){
633 $callobj = {
634 method => 'getProductProperties_hash',
635 params => [ $productId, $hostId ],
636 id => 1,
637 };
638 } else {
639 $callobj = {
640 method => 'getProductProperties_hash',
641 params => [ $productId ],
642 id => 1,
643 };
644 }
645 $res = $main::opsi_client->call($main::opsi_url, $callobj);
647 # JSON Query 2
648 $callobj = {
649 method => 'getProductPropertyDefinitions_listOfHashes',
650 params => [ $productId ],
651 id => 1,
652 };
654 # Assemble options
655 my $res2 = $main::opsi_client->call($main::opsi_url, $callobj);
656 my $values = {};
657 my $descriptions = {};
658 if (not &check_opsi_res($res2)){
659 my $r= $res2->result;
661 foreach my $entr (@$r){
662 # Unroll values
663 my $cnv;
664 if (UNIVERSAL::isa( $entr->{'values'}, "ARRAY" )){
665 foreach my $v (@{$entr->{'values'}}){
666 $cnv.= "<value>$v</value>";
667 }
668 } else {
669 $cnv= $entr->{'values'};
670 }
671 $values->{$entr->{'name'}}= $cnv;
672 $descriptions->{$entr->{'name'}}= "<description>".$entr->{'description'}."</description>";
673 }
674 }
676 if (not &check_opsi_res($res)){
677 my $r= $res->result;
678 foreach my $key (keys %{$r}) {
679 my $item= "\n<item>";
680 my $value= $r->{$key};
681 my $dsc= "";
682 my $vals= "";
683 if (defined $descriptions->{$key}){
684 $dsc= $descriptions->{$key};
685 }
686 if (defined $values->{$key}){
687 $vals= $values->{$key};
688 }
689 $item.= "<$key>$dsc<default>".xml_quote($value)."</default>$vals</$key>";
690 $item.= "</item>";
691 $xml_msg=~ s/<xxx><\/xxx>/$item<xxx><\/xxx>/;
692 }
693 }
695 $xml_msg=~ s/<xxx><\/xxx>//;
697 # Return message
698 return ( $xml_msg );
699 }
702 ## @method opsi_set_product_properties
703 # 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.
704 # @param msg - STRING - xml message with tags productId, action, state and optional hostId, action and state
705 # @param msg_hash - HASHREF - message information parsed into a hash
706 # @param session_id - INTEGER - POE session id of the processing of this message
707 # @return out_msg - STRING - feedback to GOsa in success and error case
708 sub opsi_set_product_properties {
709 my ($msg, $msg_hash, $session_id) = @_;
710 my $header = @{$msg_hash->{'header'}}[0];
711 my $source = @{$msg_hash->{'source'}}[0];
712 my $target = @{$msg_hash->{'target'}}[0];
713 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
714 my ($productId, $hostId);
716 # Build return message with twisted target and source
717 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
718 if (defined $forward_to_gosa) {
719 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
720 }
722 # Sanity check of needed parameter
723 if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
724 &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
725 &add_content2xml_hash($out_hash, "error", "productId");
726 &main::daemon_log("$session_id ERROR: no productId specified or productId tag invalid: $msg", 1);
727 return ( &create_xml_string($out_hash) );
728 }
729 if (not exists $msg_hash->{'item'}) {
730 &add_content2xml_hash($out_hash, "error_string", "message needs one xml-tag 'item' and within the xml-tags 'name' and 'value'");
731 &add_content2xml_hash($out_hash, "error", "item");
732 &main::daemon_log("$session_id ERROR: message needs one xml-tag 'item' and within the xml-tags 'name' and 'value': $msg", 1);
733 return ( &create_xml_string($out_hash) );
734 } else {
735 if ((not exists @{$msg_hash->{'item'}}[0]->{'name'}) || (@{@{$msg_hash->{'item'}}[0]->{'name'}} != 1 )) {
736 &add_content2xml_hash($out_hash, "error_string", "message needs within the xml-tag 'item' one xml-tags 'name'");
737 &add_content2xml_hash($out_hash, "error", "name");
738 &main::daemon_log("$session_id ERROR: message needs within the xml-tag 'item' one xml-tags 'name': $msg", 1);
739 return ( &create_xml_string($out_hash) );
740 }
741 if ((not exists @{$msg_hash->{'item'}}[0]->{'value'}) || (@{@{$msg_hash->{'item'}}[0]->{'value'}} != 1 )) {
742 &add_content2xml_hash($out_hash, "error_string", "message needs within the xml-tag 'item' one xml-tags 'value'");
743 &add_content2xml_hash($out_hash, "error", "value");
744 &main::daemon_log("$session_id ERROR: message needs within the xml-tag 'item' one xml-tags 'value': $msg", 1);
745 return ( &create_xml_string($out_hash) );
746 }
747 }
748 # if no hostId is given, set_product_properties will act on globally
749 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} > 1)) {
750 &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
751 &add_content2xml_hash($out_hash, "error", "hostId");
752 &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1);
753 return ( &create_xml_string($out_hash) );
754 }
757 # Get productId
758 $productId = @{$msg_hash->{'productId'}}[0];
759 &add_content2xml_hash($out_hash, "productId", $productId);
761 # Get hostId if defined
762 if (exists $msg_hash->{'hostId'}){
763 $hostId = @{$msg_hash->{'hostId'}}[0];
764 &add_content2xml_hash($out_hash, "hostId", $hostId);
765 }
767 # Set product states if requested
768 if (defined @{$msg_hash->{'action'}}[0]){
769 &_set_action($productId, @{$msg_hash->{'action'}}[0], $hostId);
770 }
771 if (defined @{$msg_hash->{'state'}}[0]){
772 &_set_state($productId, @{$msg_hash->{'state'}}[0], $hostId);
773 }
775 # Find properties
776 foreach my $item (@{$msg_hash->{'item'}}){
777 # JSON Query
778 my $callobj;
780 if (defined $hostId){
781 $callobj = {
782 method => 'setProductProperty',
783 params => [ $productId, $item->{'name'}[0], $item->{'value'}[0], $hostId ],
784 id => 1,
785 };
786 } else {
787 $callobj = {
788 method => 'setProductProperty',
789 params => [ $productId, $item->{'name'}[0], $item->{'value'}[0] ],
790 id => 1,
791 };
792 }
794 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
795 my ($res_err, $res_err_string) = &check_opsi_res($res);
797 if ($res_err){
798 &main::daemon_log("$session_id ERROR: communication failed while setting '".$item->{'name'}[0]."': ".$res_err_string, 1);
799 &add_content2xml_hash($out_hash, "error", $res_err_string);
800 }
801 }
804 # Return message
805 return ( &create_xml_string($out_hash) );
806 }
809 ## @method opsi_get_client_hardware
810 # Reports client hardware inventory.
811 # @param msg - STRING - xml message with tag hostId
812 # @param msg_hash - HASHREF - message information parsed into a hash
813 # @param session_id - INTEGER - POE session id of the processing of this message
814 # @return out_msg - STRING - feedback to GOsa in success and error case
815 sub opsi_get_client_hardware {
816 my ($msg, $msg_hash, $session_id) = @_;
817 my $header = @{$msg_hash->{'header'}}[0];
818 my $source = @{$msg_hash->{'source'}}[0];
819 my $target = @{$msg_hash->{'target'}}[0];
820 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
821 my $hostId;
822 my $error = 0;
823 my $xml_msg;
825 # Build return message with twisted target and source
826 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
827 if (defined $forward_to_gosa) {
828 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
829 }
831 # Sanity check of needed parameter
832 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
833 $error++;
834 &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
835 &add_content2xml_hash($out_hash, "error", "hostId");
836 &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1);
837 }
839 if (not $error) {
841 # Get hostId
842 $hostId = @{$msg_hash->{'hostId'}}[0];
843 &add_content2xml_hash($out_hash, "hostId", "$hostId");
844 &add_content2xml_hash($out_hash, "xxx", "");
845 }
847 # Move to XML string
848 $xml_msg= &create_xml_string($out_hash);
850 if (not $error) {
852 # JSON Query
853 my $callobj = {
854 method => 'getHardwareInformation_hash',
855 params => [ $hostId ],
856 id => 1,
857 };
859 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
860 if (not &check_opsi_res($res)){
861 my $result= $res->result;
862 if (ref $result eq "HASH") {
863 foreach my $r (keys %{$result}){
864 my $item= "\n<item><id>".xml_quote($r)."</id>";
865 my $value= $result->{$r};
866 foreach my $sres (@{$value}){
868 foreach my $dres (keys %{$sres}){
869 if (defined $sres->{$dres}){
870 $item.= "<$dres>".xml_quote($sres->{$dres})."</$dres>";
871 }
872 }
874 }
875 $item.= "</item>";
876 $xml_msg=~ s%<xxx></xxx>%$item<xxx></xxx>%;
878 }
879 }
880 }
882 $xml_msg=~ s/<xxx><\/xxx>//;
884 }
886 # Return message
887 return ( $xml_msg );
888 }
891 ## @method opsi_list_clients
892 # Reports all Opsi clients.
893 # @param msg - STRING - xml message
894 # @param msg_hash - HASHREF - message information parsed into a hash
895 # @param session_id - INTEGER - POE session id of the processing of this message
896 # @return out_msg - STRING - feedback to GOsa in success and error case
897 sub opsi_list_clients {
898 my ($msg, $msg_hash, $session_id) = @_;
899 my $header = @{$msg_hash->{'header'}}[0];
900 my $source = @{$msg_hash->{'source'}}[0];
901 my $target = @{$msg_hash->{'target'}}[0];
902 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
904 # Build return message with twisted target and source
905 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
906 if (defined $forward_to_gosa) {
907 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
908 }
909 &add_content2xml_hash($out_hash, "xxx", "");
911 # Move to XML string
912 my $xml_msg= &create_xml_string($out_hash);
914 # JSON Query
915 my $callobj = {
916 method => 'getClients_listOfHashes',
917 params => [ ],
918 id => 1,
919 };
920 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
921 if (not &check_opsi_res($res)){
922 foreach my $host (@{$res->result}){
923 my $item= "\n<item><name>".$host->{'hostId'}."</name>";
924 if (defined($host->{'description'})){
925 $item.= "<description>".xml_quote($host->{'description'})."</description>";
926 }
927 if (defined($host->{'notes'})){
928 $item.= "<notes>".xml_quote($host->{'notes'})."</notes>";
929 }
930 if (defined($host->{'lastSeen'})){
931 $item.= "<lastSeen>".xml_quote($host->{'lastSeen'})."</lastSeen>";
932 }
934 $callobj = {
935 method => 'getIpAddress',
936 params => [ $host->{'hostId'} ],
937 id => 1,
938 };
939 my $sres= $main::opsi_client->call($main::opsi_url, $callobj);
940 if ( not &check_opsi_res($sres)){
941 $item.= "<ip>".xml_quote($sres->result)."</ip>";
942 }
944 $callobj = {
945 method => 'getMacAddress',
946 params => [ $host->{'hostId'} ],
947 id => 1,
948 };
949 $sres= $main::opsi_client->call($main::opsi_url, $callobj);
950 if ( not &check_opsi_res($sres)){
951 $item.= "<mac>".xml_quote($sres->result)."</mac>";
952 }
953 $item.= "</item>";
954 $xml_msg=~ s%<xxx></xxx>%$item<xxx></xxx>%;
955 }
956 }
958 $xml_msg=~ s/<xxx><\/xxx>//;
959 return ( $xml_msg );
960 }
964 ## @method opsi_get_client_software
965 # Reports client software inventory.
966 # @param msg - STRING - xml message with tag hostId
967 # @param msg_hash - HASHREF - message information parsed into a hash
968 # @param session_id - INTEGER - POE session id of the processing of this message
969 # @return out_msg - STRING - feedback to GOsa in success and error case
970 sub opsi_get_client_software {
971 my ($msg, $msg_hash, $session_id) = @_;
972 my $header = @{$msg_hash->{'header'}}[0];
973 my $source = @{$msg_hash->{'source'}}[0];
974 my $target = @{$msg_hash->{'target'}}[0];
975 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
976 my $error = 0;
977 my $hostId;
978 my $xml_msg;
980 # Build return message with twisted target and source
981 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
982 if (defined $forward_to_gosa) {
983 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
984 }
986 # Sanity check of needed parameter
987 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
988 $error++;
989 &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
990 &add_content2xml_hash($out_hash, "error", "hostId");
991 &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1);
992 }
994 if (not $error) {
996 # Get hostId
997 $hostId = @{$msg_hash->{'hostId'}}[0];
998 &add_content2xml_hash($out_hash, "hostId", "$hostId");
999 &add_content2xml_hash($out_hash, "xxx", "");
1000 }
1002 $xml_msg= &create_xml_string($out_hash);
1004 if (not $error) {
1006 # JSON Query
1007 my $callobj = {
1008 method => 'getSoftwareInformation_hash',
1009 params => [ $hostId ],
1010 id => 1,
1011 };
1013 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1014 if (not &check_opsi_res($res)){
1015 my $result= $res->result;
1016 }
1018 $xml_msg=~ s/<xxx><\/xxx>//;
1020 }
1022 # Return message
1023 return ( $xml_msg );
1024 }
1027 ## @method opsi_get_local_products
1028 # Reports product for given hostId or globally.
1029 # @param msg - STRING - xml message with optional tag hostId
1030 # @param msg_hash - HASHREF - message information parsed into a hash
1031 # @param session_id - INTEGER - POE session id of the processing of this message
1032 # @return out_msg - STRING - feedback to GOsa in success and error case
1033 sub opsi_get_local_products {
1034 my ($msg, $msg_hash, $session_id) = @_;
1035 my $header = @{$msg_hash->{'header'}}[0];
1036 my $source = @{$msg_hash->{'source'}}[0];
1037 my $target = @{$msg_hash->{'target'}}[0];
1038 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1039 my $hostId;
1041 # Build return message with twisted target and source
1042 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1043 if (defined $forward_to_gosa) {
1044 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1045 }
1046 &add_content2xml_hash($out_hash, "xxx", "");
1048 # Get hostId if defined
1049 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1)) {
1050 $hostId = @{$msg_hash->{'hostId'}}[0];
1051 &add_content2xml_hash($out_hash, "hostId", $hostId);
1052 }
1054 # Move to XML string
1055 my $xml_msg= &create_xml_string($out_hash);
1057 # For hosts, only return the products that are or get installed
1058 my $callobj;
1059 $callobj = {
1060 method => 'getLocalBootProductIds_list',
1061 params => [ ],
1062 id => 1,
1063 };
1065 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1066 my %r = ();
1067 for (@{$res->result}) { $r{$_} = 1 }
1069 if (not &check_opsi_res($res)){
1071 if (defined $hostId){
1072 $callobj = {
1073 method => 'getProductStates_hash',
1074 params => [ $hostId ],
1075 id => 1,
1076 };
1078 my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
1079 if (not &check_opsi_res($hres)){
1080 my $htmp= $hres->result->{$hostId};
1082 # Check state != not_installed or action == setup -> load and add
1083 foreach my $product (@{$htmp}){
1085 if (!defined ($r{$product->{'productId'}})){
1086 next;
1087 }
1089 # Now we've a couple of hashes...
1090 if ($product->{'installationStatus'} ne "not_installed" or
1091 $product->{'actionRequest'} eq "setup"){
1092 my $state= "<state>".$product->{'installationStatus'}."</state><action>".$product->{'actionRequest'}."</action>";
1094 $callobj = {
1095 method => 'getProduct_hash',
1096 params => [ $product->{'productId'} ],
1097 id => 1,
1098 };
1100 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
1101 if (not &check_opsi_res($sres)){
1102 my $tres= $sres->result;
1104 my $name= xml_quote($tres->{'name'});
1105 my $r= $product->{'productId'};
1106 my $description= xml_quote($tres->{'description'});
1107 $name=~ s/\//\\\//;
1108 $description=~ s/\//\\\//;
1109 $xml_msg=~ s/<xxx><\/xxx>/\n<item><productId>$r<\/productId><name>$name<\/name><description>$description<\/description><\/item>$state<xxx><\/xxx>/;
1110 }
1112 }
1113 }
1115 }
1117 } else {
1118 foreach my $r (@{$res->result}) {
1119 $callobj = {
1120 method => 'getProduct_hash',
1121 params => [ $r ],
1122 id => 1,
1123 };
1125 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
1126 if (not &check_opsi_res($sres)){
1127 my $tres= $sres->result;
1129 my $name= xml_quote($tres->{'name'});
1130 my $description= xml_quote($tres->{'description'});
1131 $name=~ s/\//\\\//;
1132 $description=~ s/\//\\\//;
1133 $xml_msg=~ s/<xxx><\/xxx>/\n<item><productId>$r<\/productId><name>$name<\/name><description>$description<\/description><\/item><xxx><\/xxx>/;
1134 }
1136 }
1138 }
1139 }
1141 $xml_msg=~ s/<xxx><\/xxx>//;
1143 # Retrun Message
1144 return ( $xml_msg );
1145 }
1148 ## @method opsi_del_client
1149 # Deletes a client from Opsi.
1150 # @param msg - STRING - xml message with tag hostId
1151 # @param msg_hash - HASHREF - message information parsed into a hash
1152 # @param session_id - INTEGER - POE session id of the processing of this message
1153 # @return out_msg - STRING - feedback to GOsa in success and error case
1154 sub opsi_del_client {
1155 my ($msg, $msg_hash, $session_id) = @_;
1156 my $header = @{$msg_hash->{'header'}}[0];
1157 my $source = @{$msg_hash->{'source'}}[0];
1158 my $target = @{$msg_hash->{'target'}}[0];
1159 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1160 my $hostId;
1161 my $error = 0;
1163 # Build return message with twisted target and source
1164 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1165 if (defined $forward_to_gosa) {
1166 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1167 }
1169 # Sanity check of needed parameter
1170 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
1171 $error++;
1172 &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
1173 &add_content2xml_hash($out_hash, "error", "hostId");
1174 &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1);
1175 }
1177 if (not $error) {
1179 # Get hostId
1180 $hostId = @{$msg_hash->{'hostId'}}[0];
1181 &add_content2xml_hash($out_hash, "hostId", "$hostId");
1183 # JSON Query
1184 my $callobj = {
1185 method => 'deleteClient',
1186 params => [ $hostId ],
1187 id => 1,
1188 };
1189 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1190 }
1192 # Move to XML string
1193 my $xml_msg= &create_xml_string($out_hash);
1195 # Return message
1196 return ( $xml_msg );
1197 }
1200 ## @method opsi_install_client
1201 # Set a client in Opsi to install and trigger a wake on lan message (WOL).
1202 # @param msg - STRING - xml message with tags hostId, macaddress
1203 # @param msg_hash - HASHREF - message information parsed into a hash
1204 # @param session_id - INTEGER - POE session id of the processing of this message
1205 # @return out_msg - STRING - feedback to GOsa in success and error case
1206 sub opsi_install_client {
1207 my ($msg, $msg_hash, $session_id) = @_;
1208 my $header = @{$msg_hash->{'header'}}[0];
1209 my $source = @{$msg_hash->{'source'}}[0];
1210 my $target = @{$msg_hash->{'target'}}[0];
1211 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1214 my ($hostId, $macaddress);
1216 my $error = 0;
1217 my @out_msg_l;
1219 # Build return message with twisted target and source
1220 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1221 if (defined $forward_to_gosa) {
1222 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1223 }
1225 # Sanity check of needed parameter
1226 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
1227 $error++;
1228 &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
1229 &add_content2xml_hash($out_hash, "error", "hostId");
1230 &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1);
1231 }
1232 if ((not exists $msg_hash->{'macaddress'}) || (@{$msg_hash->{'macaddress'}} != 1) || (@{$msg_hash->{'macaddress'}}[0] eq ref 'HASH') ) {
1233 $error++;
1234 &add_content2xml_hash($out_hash, "error_string", "no macaddress specified or macaddress tag invalid");
1235 &add_content2xml_hash($out_hash, "error", "macaddress");
1236 &main::daemon_log("$session_id ERROR: no macaddress specified or macaddress tag invalid: $msg", 1);
1237 } else {
1238 if ((exists $msg_hash->{'macaddress'}) &&
1239 ($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)) {
1240 $macaddress = $1;
1241 } else {
1242 $error ++;
1243 &add_content2xml_hash($out_hash, "error_string", "given mac address is not correct");
1244 &add_content2xml_hash($out_hash, "error", "macaddress");
1245 &main::daemon_log("$session_id ERROR: given mac address is not correct: $msg", 1);
1246 }
1247 }
1249 if (not $error) {
1251 # Get hostId
1252 $hostId = @{$msg_hash->{'hostId'}}[0];
1253 &add_content2xml_hash($out_hash, "hostId", "$hostId");
1255 # Load all products for this host with status != "not_installed" or actionRequest != "none"
1256 my $callobj = {
1257 method => 'getProductStates_hash',
1258 params => [ $hostId ],
1259 id => 1,
1260 };
1262 my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
1263 if (not &check_opsi_res($hres)){
1264 my $htmp= $hres->result->{$hostId};
1266 # check state != not_installed or action == setup -> load and add
1267 foreach my $product (@{$htmp}){
1268 # Now we've a couple of hashes...
1269 if ($product->{'installationStatus'} ne "not_installed" or
1270 $product->{'actionRequest'} ne "none"){
1272 # Do an action request for all these -> "setup".
1273 $callobj = {
1274 method => 'setProductActionRequest',
1275 params => [ $product->{'productId'}, $hostId, "setup" ],
1276 id => 1,
1277 };
1278 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1279 my ($res_err, $res_err_string) = &check_opsi_res($res);
1280 if ($res_err){
1281 &main::daemon_log("$session_id ERROR: cannot set product action request for '$hostId': ".$product->{'productId'}, 1);
1282 } else {
1283 &main::daemon_log("$session_id INFO: requesting 'setup' for '".$product->{'productId'}."' on $hostId", 1);
1284 }
1285 }
1286 }
1287 }
1288 push(@out_msg_l, &create_xml_string($out_hash));
1291 # Build wakeup message for client
1292 if (not $error) {
1293 my $wakeup_hash = &create_xml_hash("trigger_wake", "GOSA", "KNOWN_SERVER");
1294 &add_content2xml_hash($wakeup_hash, 'macaddress', $macaddress);
1295 my $wakeup_msg = &create_xml_string($wakeup_hash);
1296 push(@out_msg_l, $wakeup_msg);
1298 # invoke trigger wake for this gosa-si-server
1299 &main::server_server_com::trigger_wake($wakeup_msg, $wakeup_hash, $session_id);
1300 }
1301 }
1303 # Return messages
1304 return @out_msg_l;
1305 }
1308 ## @method _set_action
1309 # Set action for an Opsi client
1310 # @param product - STRING - Opsi product
1311 # @param action - STRING - action
1312 # @param hostId - STRING - Opsi hostId
1313 sub _set_action {
1314 my $product= shift;
1315 my $action = shift;
1316 my $hostId = shift;
1317 my $callobj;
1319 $callobj = {
1320 method => 'setProductActionRequest',
1321 params => [ $product, $hostId, $action],
1322 id => 1,
1323 };
1325 $main::opsi_client->call($main::opsi_url, $callobj);
1326 }
1328 ## @method _set_state
1329 # Set state for an Opsi client
1330 # @param product - STRING - Opsi product
1331 # @param action - STRING - state
1332 # @param hostId - STRING - Opsi hostId
1333 sub _set_state {
1334 my $product = shift;
1335 my $state = shift;
1336 my $hostId = shift;
1337 my $callobj;
1339 $callobj = {
1340 method => 'setProductState',
1341 params => [ $product, $hostId, $state ],
1342 id => 1,
1343 };
1345 $main::opsi_client->call($main::opsi_url, $callobj);
1346 }
1348 # TODO
1349 ################################
1350 #
1351 # @brief Create a license pool at Opsi server.
1352 # @param licensePoolId The name of the pool (optional).
1353 # @param description The description of the pool (optional).
1354 # @param productIds A list of assigned porducts of the pool (optional).
1355 # @param windowsSoftwareIds A list of windows software IDs associated to the pool (optional).
1356 #
1357 sub opsi_createLicensePool {
1358 my ($msg, $msg_hash, $session_id) = @_;
1359 my $header = @{$msg_hash->{'header'}}[0];
1360 my $source = @{$msg_hash->{'source'}}[0];
1361 my $target = @{$msg_hash->{'target'}}[0];
1362 my $out_hash;
1363 my $licensePoolId = defined $msg_hash->{'licensePoolId'} ? @{$msg_hash->{'licensePoolId'}}[0] : undef;
1364 my $description = defined $msg_hash->{'description'} ? @{$msg_hash->{'description'}}[0] : undef;
1365 my @productIds = defined $msg_hash->{'productIds'} ? $msg_hash->{'productIds'} : undef;
1366 my @windowsSoftwareIds = defined $msg_hash->{'windowsSoftwareIds'} ? $msg_hash->{'windowsSoftwareIds'} : undef;
1368 # Create license Pool
1369 my $callobj = {
1370 method => 'createLicensePool',
1371 params => [ $licensePoolId, $description, @productIds, @windowsSoftwareIds],
1372 id => 1,
1373 };
1374 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1376 # Check Opsi error
1377 my ($res_error, $res_error_str) = &check_opsi_res($res);
1378 if ($res_error){
1379 # Create error message
1380 &main::daemon_log("$session_id ERROR: cannot create license pool at Opsi server: ".$res_error_str, 1);
1381 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1382 return ( &create_xml_string($out_hash) );
1383 }
1385 # Create function result message
1386 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source, $res->result);
1388 return ( &create_xml_string($out_hash) );
1389 }
1391 ################################
1392 #
1393 # @brief Return licensePoolId, description, productIds and windowsSoftwareIds for all found license pools.
1394 #
1395 sub opsi_getLicensePools_listOfHashes {
1396 my ($msg, $msg_hash, $session_id) = @_;
1397 my $header = @{$msg_hash->{'header'}}[0];
1398 my $source = @{$msg_hash->{'source'}}[0];
1399 my $out_hash;
1401 # Fetch infos from Opsi server
1402 my $callobj = {
1403 method => 'getLicensePools_listOfHashes',
1404 params => [ ],
1405 id => 1,
1406 };
1407 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1409 # Check Opsi error
1410 my ($res_error, $res_error_str) = &check_opsi_res($res);
1411 if ($res_error){
1412 # Create error message
1413 &main::daemon_log("$session_id ERROR: cannot get license pool ID list from Opsi server: ".$res_error_str, 1);
1414 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1415 return ( &create_xml_string($out_hash) );
1416 }
1418 # Create function result message
1419 my $res_hash = { 'hit'=> [] };
1420 foreach my $licensePool ( @{$res->result}) {
1421 my $licensePool_hash = { 'licensePoolId' => [$licensePool->{'licensePoolId'}],
1422 'description' => [$licensePool->{'description'}],
1423 'productIds' => $licensePool->{'productIds'},
1424 'windowsSoftwareIds' => $licensePool->{'windowsSoftwareIds'},
1425 };
1426 push( @{$res_hash->{hit}}, $licensePool_hash );
1427 }
1429 # Create function result message
1430 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1431 $out_hash->{result} = [$res_hash];
1433 return ( &create_xml_string($out_hash) );
1434 }
1436 ################################
1437 #
1438 # @brief Return productIds, windowsSoftwareIds and description for a given licensePoolId
1439 # @param licensePoolId The name of the pool.
1440 #
1441 sub opsi_getLicensePool_hash {
1442 my ($msg, $msg_hash, $session_id) = @_;
1443 my $header = @{$msg_hash->{'header'}}[0];
1444 my $source = @{$msg_hash->{'source'}}[0];
1445 my $target = @{$msg_hash->{'target'}}[0];
1446 my $licensePoolId;
1447 my $out_hash;
1449 # Check input sanity
1450 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1451 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1452 } else {
1453 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1454 }
1456 # Fetch infos from Opsi server
1457 my $callobj = {
1458 method => 'getLicensePool_hash',
1459 params => [ $licensePoolId ],
1460 id => 1,
1461 };
1462 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1464 # Check Opsi error
1465 my ($res_error, $res_error_str) = &check_opsi_res($res);
1466 if ($res_error){
1467 # Create error message
1468 &main::daemon_log("$session_id ERROR: cannot get license pool from Opsi server: ".$res_error_str, 1);
1469 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source);
1470 &add_content2xml_hash($out_hash, "error", $res_error_str);
1471 return ( &create_xml_string($out_hash) );
1472 }
1474 # Create function result message
1475 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1476 &add_content2xml_hash($out_hash, "licensePoolId", $res->result->{'licensePoolId'});
1477 &add_content2xml_hash($out_hash, "description", $res->result->{'description'});
1478 map(&add_content2xml_hash($out_hash, "productIds", "$_"), @{ $res->result->{'productIds'} });
1479 map(&add_content2xml_hash($out_hash, "windowsSoftwareIds", "$_"), @{ $res->result->{'windowsSoftwareIds'} });
1481 return ( &create_xml_string($out_hash) );
1482 }
1484 ################################
1485 #
1486 # @brief Returns softwareLicenseId, notes, licenseKey, hostId and licensePoolId for optional given licensePoolId and hostId
1487 # @param hostid Something like client_1.intranet.mydomain.de (optional).
1488 # @param licensePoolId The name of the pool (optional).
1489 #
1490 sub opsi_getSoftwareLicenseUsages_listOfHashes {
1491 my ($msg, $msg_hash, $session_id) = @_;
1492 my $header = @{$msg_hash->{'header'}}[0];
1493 my $source = @{$msg_hash->{'source'}}[0];
1494 my $target = @{$msg_hash->{'target'}}[0];
1495 my $licensePoolId = defined $msg_hash->{'licensePoolId'} ? @{$msg_hash->{'licensePoolId'}}[0] : undef;
1496 my $hostId = defined $msg_hash->{'hostId'} ? @{$msg_hash->{'hostId'}}[0] : undef;
1497 my $out_hash;
1499 # Fetch information from Opsi server
1500 my $callobj = {
1501 method => 'getSoftwareLicenseUsages_listOfHashes',
1502 params => [ $hostId, $licensePoolId ],
1503 id => 1,
1504 };
1505 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1507 # Check Opsi error
1508 my ($res_error, $res_error_str) = &check_opsi_res($res);
1509 if ($res_error){
1510 # Create error message
1511 &main::daemon_log("$session_id ERROR: cannot fetch software licenses from license pool '$licensePoolId': ".$res_error_str, 1);
1512 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1513 return ( &create_xml_string($out_hash) );
1514 }
1516 # Parse Opsi result
1517 my $res_hash = { 'hit'=> [] };
1518 foreach my $license ( @{$res->result}) {
1519 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
1520 'notes' => [$license->{'notes'}],
1521 'licenseKey' => [$license->{'licenseKey'}],
1522 'hostId' => [$license->{'hostId'}],
1523 'licensePoolId' => [$license->{'licensePoolId'}],
1524 };
1525 push( @{$res_hash->{hit}}, $license_hash );
1526 }
1528 # Create function result message
1529 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1530 $out_hash->{result} = [$res_hash];
1532 return ( &create_xml_string($out_hash) );
1533 }
1535 ################################
1536 #
1537 # @brief Returns expirationDate, boundToHost, maxInstallation, licenseTyp, licensePoolIds and licenseKeys for a given softwareLicense ID.
1538 # @param softwareLicenseId Identificator of a license.
1539 #
1540 sub opsi_getSoftwareLicense_hash {
1541 my ($msg, $msg_hash, $session_id) = @_;
1542 my $header = @{$msg_hash->{'header'}}[0];
1543 my $source = @{$msg_hash->{'source'}}[0];
1544 my $target = @{$msg_hash->{'target'}}[0];
1545 my $softwareLicenseId;
1546 my $out_hash;
1548 # Check input sanity
1549 if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
1550 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
1551 } else {
1552 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1553 }
1555 my $callobj = {
1556 method => 'getSoftwareLicense_hash',
1557 params => [ $softwareLicenseId ],
1558 id => 1,
1559 };
1560 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1562 # Check Opsi error
1563 my ($res_error, $res_error_str) = &check_opsi_res($res);
1564 if ($res_error){
1565 # Create error message
1566 &main::daemon_log("$session_id ERROR: cannot fetch information for license '$softwareLicenseId': ".$res_error_str, 1);
1567 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1568 return ( &create_xml_string($out_hash) );
1569 }
1571 # Create function result message
1572 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1573 &add_content2xml_hash($out_hash, "expirationDate", $res->result->{'expirationDate'});
1574 &add_content2xml_hash($out_hash, "boundToHost", $res->result->{'boundToHost'});
1575 &add_content2xml_hash($out_hash, "maxInstallations", $res->result->{'maxInstallations'});
1576 &add_content2xml_hash($out_hash, "licenseTyp", $res->result->{'licenseTyp'});
1577 foreach my $licensePoolId ( @{$res->result->{'licensePoolIds'}}) {
1578 &add_content2xml_hash($out_hash, "licensePoolId", $licensePoolId);
1579 &add_content2xml_hash($out_hash, $licensePoolId, $res->result->{'licenseKeys'}->{$licensePoolId});
1580 }
1582 return ( &create_xml_string($out_hash) );
1583 }
1585 ################################
1586 #
1587 # @brief Delete licnese pool by license pool ID. A pool can only be deleted if there are no software licenses bound to the pool.
1588 # The fixed parameter deleteLicenses=True specifies that all software licenses bound to the pool are being deleted.
1589 # @param licensePoolId The name of the pool.
1590 #
1591 sub opsi_deleteLicensePool {
1592 my ($msg, $msg_hash, $session_id) = @_;
1593 my $header = @{$msg_hash->{'header'}}[0];
1594 my $source = @{$msg_hash->{'source'}}[0];
1595 my $target = @{$msg_hash->{'target'}}[0];
1596 my $licensePoolId;
1597 my $out_hash;
1599 # Check input sanity
1600 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1601 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1602 } else {
1603 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1604 }
1606 # Fetch softwareLicenseIds used in license pool
1607 # This has to be done because function deleteLicensePool deletes the pool and the corresponding software licenses
1608 # but not the license contracts of the software licenses. In our case each software license has exactly one license contract.
1609 my $callobj = {
1610 method => 'getSoftwareLicenses_listOfHashes',
1611 params => [ ],
1612 id => 1,
1613 };
1614 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1616 # Keep list of licenseContractIds in mind to delete it after the deletion of the software licenses
1617 my @lCI_toBeDeleted;
1618 foreach my $softwareLicenseHash ( @{$res->result} ) {
1619 if ((@{$softwareLicenseHash->{'licensePoolIds'}} == 0) || (@{$softwareLicenseHash->{'licensePoolIds'}}[0] ne $licensePoolId)) {
1620 next;
1621 }
1622 push (@lCI_toBeDeleted, $softwareLicenseHash->{'licenseContractId'});
1623 }
1625 # Delete license pool at Opsi server
1626 $callobj = {
1627 method => 'deleteLicensePool',
1628 params => [ $licensePoolId, 'deleteLicenses=True' ],
1629 id => 1,
1630 };
1631 $res = $main::opsi_client->call($main::opsi_url, $callobj);
1632 my ($res_error, $res_error_str) = &check_opsi_res($res);
1633 if ($res_error){
1634 # Create error message
1635 &main::daemon_log("$session_id ERROR: cannot delete license pool at Opsi server: ".$res_error_str, 1);
1636 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1637 return ( &create_xml_string($out_hash) );
1638 }
1640 # Delete each license contract connected with the license pool
1641 foreach my $licenseContractId ( @lCI_toBeDeleted ) {
1642 my $callobj = {
1643 method => 'deleteLicenseContract',
1644 params => [ $licenseContractId ],
1645 id => 1,
1646 };
1647 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1648 my ($res_error, $res_error_str) = &check_opsi_res($res);
1649 if ($res_error){
1650 # Create error message
1651 &main::daemon_log("$session_id ERROR: cannot delete license contract '$licenseContractId' connected with license pool '$licensePoolId' at Opsi server: ".$res_error_str, 1);
1652 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1653 return ( &create_xml_string($out_hash) );
1654 }
1655 }
1657 # Create function result message
1658 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1660 return ( &create_xml_string($out_hash) );
1661 }
1663 ################################
1664 #
1665 # @brief Create a license contract, create a software license and add the software license to the license pool
1666 # @param licensePoolId The name of the pool the license should be assigned.
1667 # @param licenseKey The license key.
1668 # @param partner Name of the license partner (optional).
1669 # @param conclusionDate Date of conclusion of license contract (optional)
1670 # @param notificationDate Date of notification that license is running out soon (optional).
1671 # @param notes This is the place for some notes (optional)
1672 # @param softwareLicenseId Identificator of a license (optional).
1673 # @param licenseTyp Typ of a licnese, either "OEM", "VOLUME" or "RETAIL" (optional).
1674 # @param maxInstallations The number of clients use this license (optional).
1675 # @param boundToHost The name of the client the license is bound to (optional).
1676 # @param expirationDate The date when the license is running down (optional).
1677 #
1678 sub opsi_createLicense {
1679 my ($msg, $msg_hash, $session_id) = @_;
1680 my $header = @{$msg_hash->{'header'}}[0];
1681 my $source = @{$msg_hash->{'source'}}[0];
1682 my $target = @{$msg_hash->{'target'}}[0];
1683 my $partner = defined $msg_hash->{'partner'} ? @{$msg_hash->{'partner'}}[0] : undef;
1684 my $conclusionDate = defined $msg_hash->{'conclusionDate'} ? @{$msg_hash->{'conclusionDate'}}[0] : undef;
1685 my $notificationDate = defined $msg_hash->{'notificationDate'} ? @{$msg_hash->{'notificationDate'}}[0] : undef;
1686 my $notes = defined $msg_hash->{'notes'} ? @{$msg_hash->{'notes'}}[0] : undef;
1687 my $licenseContractId;
1688 my $softwareLicenseId = defined $msg_hash->{'licenseId'} ? @{$msg_hash->{'licenseId'}}[0] : undef;
1689 my $licenseType = defined $msg_hash->{'licenseType'} ? @{$msg_hash->{'licenseType'}}[0] : undef;
1690 my $maxInstallations = defined $msg_hash->{'maxInstallations'} ? @{$msg_hash->{'maxInstallations'}}[0] : undef;
1691 my $boundToHost = defined $msg_hash->{'boundToHost'} ? @{$msg_hash->{'boundToHost'}}[0] : undef;
1692 my $expirationDate = defined $msg_hash->{'expirationDate'} ? @{$msg_hash->{'expirationDate'}}[0] : undef;
1693 my $licensePoolId;
1694 my $licenseKey;
1695 my $out_hash;
1697 # Check input sanity
1698 if (&_check_xml_tag_is_ok ($msg_hash, 'licenseKey')) {
1699 $licenseKey = @{$msg_hash->{'licenseKey'}}[0];
1700 } else {
1701 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1702 }
1703 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1704 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1705 } else {
1706 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1707 }
1708 if ((defined $licenseType) && (not exists $licenseTyp_hash->{$licenseType})) {
1709 return ( &_give_feedback($msg, $msg_hash, $session_id, "The typ of a license can be either 'OEM', 'VOLUME' or 'RETAIL'."));
1710 }
1712 # Create license contract at Opsi server
1713 my $callobj = {
1714 method => 'createLicenseContract',
1715 params => [ undef, $partner, $conclusionDate, $notificationDate, undef, $notes ],
1716 id => 1,
1717 };
1718 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1720 # Check Opsi error
1721 my ($res_error, $res_error_str) = &check_opsi_res($res);
1722 if ($res_error){
1723 # Create error message
1724 &main::daemon_log("$session_id ERROR: cannot create license contract at Opsi server: ".$res_error_str, 1);
1725 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1726 return ( &create_xml_string($out_hash) );
1727 }
1729 $licenseContractId = $res->result;
1731 # Create software license at Opsi server
1732 $callobj = {
1733 method => 'createSoftwareLicense',
1734 params => [ $softwareLicenseId, $licenseContractId, $licenseType, $maxInstallations, $boundToHost, $expirationDate ],
1735 id => 1,
1736 };
1737 $res = $main::opsi_client->call($main::opsi_url, $callobj);
1739 # Check Opsi error
1740 ($res_error, $res_error_str) = &check_opsi_res($res);
1741 if ($res_error){
1742 # Create error message
1743 &main::daemon_log("$session_id ERROR: cannot create software license at Opsi server: ".$res_error_str, 1);
1744 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1745 return ( &create_xml_string($out_hash) );
1746 }
1748 $softwareLicenseId = $res->result;
1750 # Add software license to license pool
1751 $callobj = {
1752 method => 'addSoftwareLicenseToLicensePool',
1753 params => [ $softwareLicenseId, $licensePoolId, $licenseKey ],
1754 id => 1,
1755 };
1756 $res = $main::opsi_client->call($main::opsi_url, $callobj);
1758 # Check Opsi error
1759 ($res_error, $res_error_str) = &check_opsi_res($res);
1760 if ($res_error){
1761 # Create error message
1762 &main::daemon_log("$session_id ERROR: cannot add software license to license pool at Opsi server: ".$res_error_str, 1);
1763 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1764 return ( &create_xml_string($out_hash) );
1765 }
1767 # Create function result message
1768 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1770 return ( &create_xml_string($out_hash) );
1771 }
1773 ################################
1774 #
1775 # @brief Assign a software license to a host
1776 # @param hostid Something like client_1.intranet.mydomain.de
1777 # @param licensePoolId The name of the pool.
1778 #
1779 sub opsi_assignSoftwareLicenseToHost {
1780 my ($msg, $msg_hash, $session_id) = @_;
1781 my $header = @{$msg_hash->{'header'}}[0];
1782 my $source = @{$msg_hash->{'source'}}[0];
1783 my $target = @{$msg_hash->{'target'}}[0];
1784 my $hostId;
1785 my $licensePoolId;
1787 # Check input sanity
1788 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1789 $hostId = @{$msg_hash->{'hostId'}}[0];
1790 } else {
1791 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1792 }
1793 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1794 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1795 } else {
1796 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1797 }
1799 # Assign a software license to a host
1800 my $callobj = {
1801 method => 'getAndAssignSoftwareLicenseKey',
1802 params => [ $hostId, $licensePoolId ],
1803 id => 1,
1804 };
1805 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1807 # Check Opsi error
1808 my ($res_error, $res_error_str) = &check_opsi_res($res);
1809 if ($res_error){
1810 # Create error message
1811 &main::daemon_log("$session_id ERROR: cannot assign a software license to a host at Opsi server: ".$res_error_str, 1);
1812 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1813 return ( &create_xml_string($out_hash) );
1814 }
1816 # Create function result message
1817 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1819 return ( &create_xml_string($out_hash) );
1820 }
1822 ################################
1823 #
1824 # @brief Unassign a software license from a host.
1825 # @param hostid Something like client_1.intranet.mydomain.de
1826 # @param licensePoolId The name of the pool.
1827 #
1828 sub opsi_unassignSoftwareLicenseFromHost {
1829 my ($msg, $msg_hash, $session_id) = @_;
1830 my $header = @{$msg_hash->{'header'}}[0];
1831 my $source = @{$msg_hash->{'source'}}[0];
1832 my $target = @{$msg_hash->{'target'}}[0];
1833 my $hostId;
1834 my $licensePoolId;
1836 # Check input sanity
1837 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1838 $hostId = @{$msg_hash->{'hostId'}}[0];
1839 } else {
1840 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1841 }
1842 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1843 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1844 } else {
1845 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1846 }
1848 # Unassign a software license from a host
1849 my $callobj = {
1850 method => 'deleteSoftwareLicenseUsage',
1851 params => [ $hostId, '', $licensePoolId ],
1852 id => 1,
1853 };
1854 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1856 # Check Opsi error
1857 my ($res_error, $res_error_str) = &check_opsi_res($res);
1858 if ($res_error){
1859 # Create error message
1860 &main::daemon_log("$session_id ERROR: cannot unassign a software license from a host at Opsi server: ".$res_error_str, 1);
1861 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1862 return ( &create_xml_string($out_hash) );
1863 }
1865 # Create function result message
1866 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1868 return ( &create_xml_string($out_hash) );
1869 }
1871 ################################
1872 #
1873 # @brief Unassign all software licenses from a host
1874 # @param hostid Something like client_1.intranet.mydomain.de
1875 #
1876 sub opsi_unassignAllSoftwareLicensesFromHost {
1877 my ($msg, $msg_hash, $session_id) = @_;
1878 my $header = @{$msg_hash->{'header'}}[0];
1879 my $source = @{$msg_hash->{'source'}}[0];
1880 my $target = @{$msg_hash->{'target'}}[0];
1881 my $hostId;
1883 # Check input sanity
1884 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1885 $hostId = @{$msg_hash->{'hostId'}}[0];
1886 } else {
1887 return ( &_give_feedback($msg, $msg_hash, $session_id, $_) );
1888 }
1890 # Unassign all software licenses from a host
1891 my $callobj = {
1892 method => 'deleteAllSoftwareLicenseUsages',
1893 params => [ $hostId ],
1894 id => 1,
1895 };
1896 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1898 # Check Opsi error
1899 my ($res_error, $res_error_str) = &check_opsi_res($res);
1900 if ($res_error){
1901 # Create error message
1902 &main::daemon_log("$session_id ERROR: cannot unassign a software license from a host at Opsi server: ".$res_error_str, 1);
1903 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1904 return ( &create_xml_string($out_hash) );
1905 }
1907 # Create function result message
1908 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1910 return ( &create_xml_string($out_hash) );
1911 }
1914 ################################
1915 #
1916 # @brief
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;