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_getLicensePoolIds_list",
26 "opsi_getLicensePool_hash",
27 "opsi_deleteLicensePool",
28 "opsi_createLicense",
29 );
30 @EXPORT = @events;
32 use strict;
33 use warnings;
34 use GOSA::GosaSupportDaemon;
35 use Data::Dumper;
36 use XML::Quote qw(:all);
39 BEGIN {}
41 END {}
43 ## @method get_events()
44 # A brief function returning a list of functions which are exported by importing the module.
45 # @return List of all provided functions
46 sub get_events {
47 return \@events;
48 }
50 ## @method opsi_add_product_to_client
51 # Adds an Opsi product to an Opsi client.
52 # @param msg - STRING - xml message with tags hostId and productId
53 # @param msg_hash - HASHREF - message information parsed into a hash
54 # @param session_id - INTEGER - POE session id of the processing of this message
55 # @return out_msg - STRING - feedback to GOsa in success and error case
56 sub opsi_add_product_to_client {
57 my ($msg, $msg_hash, $session_id) = @_;
58 my $header = @{$msg_hash->{'header'}}[0];
59 my $source = @{$msg_hash->{'source'}}[0];
60 my $target = @{$msg_hash->{'target'}}[0];
61 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
62 my ($hostId, $productId);
63 my $error = 0;
65 # Build return message
66 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
67 if (defined $forward_to_gosa) {
68 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
69 }
71 # Sanity check of needed parameter
72 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
73 $error++;
74 &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
75 &add_content2xml_hash($out_hash, "error", "hostId");
76 &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1);
78 }
79 if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
80 $error++;
81 &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
82 &add_content2xml_hash($out_hash, "error", "productId");
83 &main::daemon_log("$session_id ERROR: no productId specified or procutId tag invalid: $msg", 1);
84 }
86 if (not $error) {
87 # Get hostId
88 $hostId = @{$msg_hash->{'hostId'}}[0];
89 &add_content2xml_hash($out_hash, "hostId", $hostId);
91 # Get productID
92 $productId = @{$msg_hash->{'productId'}}[0];
93 &add_content2xml_hash($out_hash, "productId", $productId);
95 # Do an action request for all these -> "setup".
96 my $callobj = {
97 method => 'setProductActionRequest',
98 params => [ $productId, $hostId, "setup" ],
99 id => 1, };
101 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
102 my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
103 if ($sres_err){
104 &main::daemon_log("$session_id ERROR: cannot add product: ".$sres_err_string, 1);
105 &add_content2xml_hash($out_hash, "error", $sres_err_string);
106 }
107 }
109 # return message
110 return ( &create_xml_string($out_hash) );
111 }
113 ## @method opsi_del_product_from_client
114 # Deletes an Opsi-product from an Opsi-client.
115 # @param msg - STRING - xml message with tags hostId and productId
116 # @param msg_hash - HASHREF - message information parsed into a hash
117 # @param session_id - INTEGER - POE session id of the processing of this message
118 # @return out_msg - STRING - feedback to GOsa in success and error case
119 sub opsi_del_product_from_client {
120 my ($msg, $msg_hash, $session_id) = @_;
121 my $header = @{$msg_hash->{'header'}}[0];
122 my $source = @{$msg_hash->{'source'}}[0];
123 my $target = @{$msg_hash->{'target'}}[0];
124 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
125 my ($hostId, $productId);
126 my $error = 0;
127 my ($sres, $sres_err, $sres_err_string);
129 # Build return message
130 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
131 if (defined $forward_to_gosa) {
132 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
133 }
135 # Sanity check of needed parameter
136 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
137 $error++;
138 &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
139 &add_content2xml_hash($out_hash, "error", "hostId");
140 &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1);
142 }
143 if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
144 $error++;
145 &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
146 &add_content2xml_hash($out_hash, "error", "productId");
147 &main::daemon_log("$session_id ERROR: no productId specified or procutId tag invalid: $msg", 1);
148 }
150 # All parameter available
151 if (not $error) {
152 # Get hostId
153 $hostId = @{$msg_hash->{'hostId'}}[0];
154 &add_content2xml_hash($out_hash, "hostId", $hostId);
156 # Get productID
157 $productId = @{$msg_hash->{'productId'}}[0];
158 &add_content2xml_hash($out_hash, "productId", $productId);
161 #TODO : check the results for more than one entry which is currently installed
162 #$callobj = {
163 # method => 'getProductDependencies_listOfHashes',
164 # params => [ $productId ],
165 # id => 1, };
166 #
167 #my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
168 #my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
169 #if ($sres_err){
170 # &main::daemon_log("ERROR: cannot perform dependency check: ".$sres_err_string, 1);
171 # &add_content2xml_hash($out_hash, "error", $sres_err_string);
172 # return ( &create_xml_string($out_hash) );
173 #}
176 # Check to get product action list
177 my $callobj = {
178 method => 'getPossibleProductActions_list',
179 params => [ $productId ],
180 id => 1, };
181 $sres = $main::opsi_client->call($main::opsi_url, $callobj);
182 ($sres_err, $sres_err_string) = &check_opsi_res($sres);
183 if ($sres_err){
184 &main::daemon_log("$session_id ERROR: cannot get product action list: ".$sres_err_string, 1);
185 &add_content2xml_hash($out_hash, "error", $sres_err_string);
186 $error++;
187 }
188 }
190 # Check action uninstall of product
191 if (not $error) {
192 my $uninst_possible= 0;
193 foreach my $r (@{$sres->result}) {
194 if ($r eq 'uninstall') {
195 $uninst_possible= 1;
196 }
197 }
198 if (!$uninst_possible){
199 &main::daemon_log("$session_id ERROR: cannot uninstall product '$productId', product do not has the action 'uninstall'", 1);
200 &add_content2xml_hash($out_hash, "error", "cannot uninstall product '$productId', product do not has the action 'uninstall'");
201 $error++;
202 }
203 }
205 # Set product state to "none"
206 # Do an action request for all these -> "setup".
207 if (not $error) {
208 my $callobj = {
209 method => 'setProductActionRequest',
210 params => [ $productId, $hostId, "none" ],
211 id => 1,
212 };
213 $sres = $main::opsi_client->call($main::opsi_url, $callobj);
214 ($sres_err, $sres_err_string) = &check_opsi_res($sres);
215 if ($sres_err){
216 &main::daemon_log("$session_id ERROR: cannot delete product: ".$sres_err_string, 1);
217 &add_content2xml_hash($out_hash, "error", $sres_err_string);
218 }
219 }
221 # Return message
222 return ( &create_xml_string($out_hash) );
223 }
225 ## @method opsi_add_client
226 # Adds an Opsi client to Opsi.
227 # @param msg - STRING - xml message with tags hostId and macaddress
228 # @param msg_hash - HASHREF - message information parsed into a hash
229 # @param session_id - INTEGER - POE session id of the processing of this message
230 # @return out_msg - STRING - feedback to GOsa in success and error case
231 sub opsi_add_client {
232 my ($msg, $msg_hash, $session_id) = @_;
233 my $header = @{$msg_hash->{'header'}}[0];
234 my $source = @{$msg_hash->{'source'}}[0];
235 my $target = @{$msg_hash->{'target'}}[0];
236 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
237 my ($hostId, $mac);
238 my $error = 0;
239 my ($sres, $sres_err, $sres_err_string);
241 # Build return message with twisted target and source
242 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
243 if (defined $forward_to_gosa) {
244 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
245 }
247 # Sanity check of needed parameter
248 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
249 $error++;
250 &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
251 &add_content2xml_hash($out_hash, "error", "hostId");
252 &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1);
253 }
254 if ((not exists $msg_hash->{'macaddress'}) || (@{$msg_hash->{'macaddress'}} != 1) || (@{$msg_hash->{'macaddress'}}[0] eq ref 'HASH')) {
255 $error++;
256 &add_content2xml_hash($out_hash, "error_string", "no macaddress specified or macaddress tag invalid");
257 &add_content2xml_hash($out_hash, "error", "macaddress");
258 &main::daemon_log("$session_id ERROR: no macaddress specified or macaddress tag invalid: $msg", 1);
259 }
261 if (not $error) {
262 # Get hostId
263 $hostId = @{$msg_hash->{'hostId'}}[0];
264 &add_content2xml_hash($out_hash, "hostId", $hostId);
266 # Get macaddress
267 $mac = @{$msg_hash->{'macaddress'}}[0];
268 &add_content2xml_hash($out_hash, "macaddress", $mac);
270 my $name= $hostId;
271 $name=~ s/^([^.]+).*$/$1/;
272 my $domain= $hostId;
273 $domain=~ s/^[^.]+\.(.*)$/$1/;
274 my ($description, $notes, $ip);
276 if (defined @{$msg_hash->{'description'}}[0]){
277 $description = @{$msg_hash->{'description'}}[0];
278 }
279 if (defined @{$msg_hash->{'notes'}}[0]){
280 $notes = @{$msg_hash->{'notes'}}[0];
281 }
282 if (defined @{$msg_hash->{'ip'}}[0]){
283 $ip = @{$msg_hash->{'ip'}}[0];
284 }
286 my $callobj;
287 $callobj = {
288 method => 'createClient',
289 params => [ $name, $domain, $description, $notes, $ip, $mac ],
290 id => 1,
291 };
293 $sres = $main::opsi_client->call($main::opsi_url, $callobj);
294 ($sres_err, $sres_err_string) = &check_opsi_res($sres);
295 if ($sres_err){
296 &main::daemon_log("$session_id ERROR: cannot create client: ".$sres_err_string, 1);
297 &add_content2xml_hash($out_hash, "error", $sres_err_string);
298 } else {
299 &main::daemon_log("$session_id INFO: add opsi client '$hostId' with mac '$mac'", 5);
300 }
301 }
303 # Return message
304 return ( &create_xml_string($out_hash) );
305 }
307 ## @method opsi_modify_client
308 # Modifies the parameters description, mac or notes for an Opsi client if the corresponding message tags are given.
309 # @param msg - STRING - xml message with tag hostId and optional description, mac or notes
310 # @param msg_hash - HASHREF - message information parsed into a hash
311 # @param session_id - INTEGER - POE session id of the processing of this message
312 # @return out_msg - STRING - feedback to GOsa in success and error case
313 sub opsi_modify_client {
314 my ($msg, $msg_hash, $session_id) = @_;
315 my $header = @{$msg_hash->{'header'}}[0];
316 my $source = @{$msg_hash->{'source'}}[0];
317 my $target = @{$msg_hash->{'target'}}[0];
318 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
319 my $hostId;
320 my $error = 0;
321 my ($sres, $sres_err, $sres_err_string);
323 # Build return message with twisted target and source
324 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
325 if (defined $forward_to_gosa) {
326 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
327 }
329 # Sanity check of needed parameter
330 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
331 $error++;
332 &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
333 &add_content2xml_hash($out_hash, "error", "hostId");
334 &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1);
335 }
337 if (not $error) {
338 # Get hostId
339 $hostId = @{$msg_hash->{'hostId'}}[0];
340 &add_content2xml_hash($out_hash, "hostId", $hostId);
341 my $name= $hostId;
342 $name=~ s/^([^.]+).*$/$1/;
343 my $domain= $hostId;
344 $domain=~ s/^[^.]+(.*)$/$1/;
346 # Modify description, notes or mac if defined
347 my ($description, $notes, $mac);
348 my $callobj;
349 if ((exists $msg_hash->{'description'}) && (@{$msg_hash->{'description'}} == 1) ){
350 $description = @{$msg_hash->{'description'}}[0];
351 $callobj = {
352 method => 'setHostDescription',
353 params => [ $hostId, $description ],
354 id => 1,
355 };
356 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
357 my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
358 if ($sres_err){
359 &main::daemon_log("ERROR: cannot set description: ".$sres_err_string, 1);
360 &add_content2xml_hash($out_hash, "error", $sres_err_string);
361 }
362 }
363 if ((exists $msg_hash->{'notes'}) && (@{$msg_hash->{'notes'}} == 1)) {
364 $notes = @{$msg_hash->{'notes'}}[0];
365 $callobj = {
366 method => 'setHostNotes',
367 params => [ $hostId, $notes ],
368 id => 1,
369 };
370 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
371 my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
372 if ($sres_err){
373 &main::daemon_log("ERROR: cannot set notes: ".$sres_err_string, 1);
374 &add_content2xml_hash($out_hash, "error", $sres_err_string);
375 }
376 }
377 if ((exists $msg_hash->{'mac'}) && (@{$msg_hash->{'mac'}} == 1)){
378 $mac = @{$msg_hash->{'mac'}}[0];
379 $callobj = {
380 method => 'setMacAddress',
381 params => [ $hostId, $mac ],
382 id => 1,
383 };
384 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
385 my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
386 if ($sres_err){
387 &main::daemon_log("ERROR: cannot set mac address: ".$sres_err_string, 1);
388 &add_content2xml_hash($out_hash, "error", $sres_err_string);
389 }
390 }
391 }
393 # Return message
394 return ( &create_xml_string($out_hash) );
395 }
398 ## @method opsi_get_netboot_products
399 # Get netboot products for specific host.
400 # @param msg - STRING - xml message with tag hostId
401 # @param msg_hash - HASHREF - message information parsed into a hash
402 # @param session_id - INTEGER - POE session id of the processing of this message
403 # @return out_msg - STRING - feedback to GOsa in success and error case
404 sub opsi_get_netboot_products {
405 my ($msg, $msg_hash, $session_id) = @_;
406 my $header = @{$msg_hash->{'header'}}[0];
407 my $source = @{$msg_hash->{'source'}}[0];
408 my $target = @{$msg_hash->{'target'}}[0];
409 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
410 my $hostId;
411 my $xml_msg;
413 # Build return message with twisted target and source
414 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
415 if (defined $forward_to_gosa) {
416 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
417 }
419 # Get hostId if defined
420 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1)) {
421 $hostId = @{$msg_hash->{'hostId'}}[0];
422 &add_content2xml_hash($out_hash, "hostId", $hostId);
423 }
425 &add_content2xml_hash($out_hash, "xxx", "");
426 $xml_msg = &create_xml_string($out_hash);
427 # For hosts, only return the products that are or get installed
428 my $callobj;
429 $callobj = {
430 method => 'getNetBootProductIds_list',
431 params => [ ],
432 id => 1,
433 };
434 &main::daemon_log("$session_id DEBUG: send callobj to opsi_client: ".&opsi_callobj2string($callobj), 7);
435 &main::daemon_log("$session_id DEBUG: opsi_url $main::opsi_url", 7);
436 &main::daemon_log("$session_id DEBUG: waiting for answer from opsi_client!", 7);
437 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
438 &main::daemon_log("$session_id DEBUG: get answer from opsi_client", 7);
439 my %r = ();
440 for (@{$res->result}) { $r{$_} = 1 }
442 if (not &check_opsi_res($res)){
444 if (defined $hostId){
446 $callobj = {
447 method => 'getProductStates_hash',
448 params => [ $hostId ],
449 id => 1,
450 };
452 my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
453 if (not &check_opsi_res($hres)){
454 my $htmp= $hres->result->{$hostId};
456 # check state != not_installed or action == setup -> load and add
457 foreach my $product (@{$htmp}){
459 if (!defined ($r{$product->{'productId'}})){
460 next;
461 }
463 # Now we've a couple of hashes...
464 if ($product->{'installationStatus'} ne "not_installed" or
465 $product->{'actionRequest'} eq "setup"){
466 my $state= "<state>".$product->{'installationStatus'}."</state><action>".$product->{'actionRequest'}."</action>";
468 $callobj = {
469 method => 'getProduct_hash',
470 params => [ $product->{'productId'} ],
471 id => 1,
472 };
474 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
475 if (not &check_opsi_res($sres)){
476 my $tres= $sres->result;
478 my $name= xml_quote($tres->{'name'});
479 my $r= $product->{'productId'};
480 my $description= xml_quote($tres->{'description'});
481 $name=~ s/\//\\\//;
482 $description=~ s/\//\\\//;
483 $xml_msg=~ s/<xxx><\/xxx>/\n<item><productId>$r<\/productId><name>$name<\/name><description>$description<\/description><\/item>$state<xxx><\/xxx>/;
484 }
485 }
486 }
488 }
490 } else {
491 foreach my $r (@{$res->result}) {
492 $callobj = {
493 method => 'getProduct_hash',
494 params => [ $r ],
495 id => 1,
496 };
498 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
499 if (not &check_opsi_res($sres)){
500 my $tres= $sres->result;
502 my $name= xml_quote($tres->{'name'});
503 my $description= xml_quote($tres->{'description'});
504 $name=~ s/\//\\\//;
505 $description=~ s/\//\\\//;
506 $xml_msg=~ s/<xxx><\/xxx>/\n<item><productId>$r<\/productId><name>$name<\/name><description>$description<\/description><\/item><xxx><\/xxx>/;
507 }
508 }
510 }
511 }
512 $xml_msg=~ s/<xxx><\/xxx>//;
514 # Return message
515 return ( $xml_msg );
516 }
519 ## @method opsi_get_product_properties
520 # Get product properties for a product and a specific host or gobally for a product.
521 # @param msg - STRING - xml message with tags productId and optional hostId
522 # @param msg_hash - HASHREF - message information parsed into a hash
523 # @param session_id - INTEGER - POE session id of the processing of this message
524 # @return out_msg - STRING - feedback to GOsa in success and error case
525 sub opsi_get_product_properties {
526 my ($msg, $msg_hash, $session_id) = @_;
527 my $header = @{$msg_hash->{'header'}}[0];
528 my $source = @{$msg_hash->{'source'}}[0];
529 my $target = @{$msg_hash->{'target'}}[0];
530 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
531 my ($hostId, $productId);
532 my $xml_msg;
534 # Build return message with twisted target and source
535 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
536 if (defined $forward_to_gosa) {
537 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
538 }
540 # Sanity check of needed parameter
541 if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
542 &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
543 &add_content2xml_hash($out_hash, "error", "productId");
544 &main::daemon_log("$session_id ERROR: no productId specified or productId tag invalid: $msg", 1);
546 # Return message
547 return ( &create_xml_string($out_hash) );
548 }
550 # Get productid
551 $productId = @{$msg_hash->{'productId'}}[0];
552 &add_content2xml_hash($out_hash, "producId", "$productId");
554 # Get hostId if defined
555 if (defined @{$msg_hash->{'hostId'}}[0]){
556 $hostId = @{$msg_hash->{'hostId'}}[0];
557 &add_content2xml_hash($out_hash, "hostId", $hostId);
558 }
560 # Load actions
561 my $callobj = {
562 method => 'getPossibleProductActions_list',
563 params => [ $productId ],
564 id => 1,
565 };
566 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
567 if (not &check_opsi_res($res)){
568 foreach my $action (@{$res->result}){
569 &add_content2xml_hash($out_hash, "action", $action);
570 }
571 }
573 # Add place holder
574 &add_content2xml_hash($out_hash, "xxx", "");
576 # Move to XML string
577 $xml_msg= &create_xml_string($out_hash);
579 # JSON Query
580 if (defined $hostId){
581 $callobj = {
582 method => 'getProductProperties_hash',
583 params => [ $productId, $hostId ],
584 id => 1,
585 };
586 } else {
587 $callobj = {
588 method => 'getProductProperties_hash',
589 params => [ $productId ],
590 id => 1,
591 };
592 }
593 $res = $main::opsi_client->call($main::opsi_url, $callobj);
595 # JSON Query 2
596 $callobj = {
597 method => 'getProductPropertyDefinitions_listOfHashes',
598 params => [ $productId ],
599 id => 1,
600 };
602 # Assemble options
603 my $res2 = $main::opsi_client->call($main::opsi_url, $callobj);
604 my $values = {};
605 my $descriptions = {};
606 if (not &check_opsi_res($res2)){
607 my $r= $res2->result;
609 foreach my $entr (@$r){
610 # Unroll values
611 my $cnv;
612 if (UNIVERSAL::isa( $entr->{'values'}, "ARRAY" )){
613 foreach my $v (@{$entr->{'values'}}){
614 $cnv.= "<value>$v</value>";
615 }
616 } else {
617 $cnv= $entr->{'values'};
618 }
619 $values->{$entr->{'name'}}= $cnv;
620 $descriptions->{$entr->{'name'}}= "<description>".$entr->{'description'}."</description>";
621 }
622 }
624 if (not &check_opsi_res($res)){
625 my $r= $res->result;
626 foreach my $key (keys %{$r}) {
627 my $item= "\n<item>";
628 my $value= $r->{$key};
629 my $dsc= "";
630 my $vals= "";
631 if (defined $descriptions->{$key}){
632 $dsc= $descriptions->{$key};
633 }
634 if (defined $values->{$key}){
635 $vals= $values->{$key};
636 }
637 $item.= "<$key>$dsc<default>".xml_quote($value)."</default>$vals</$key>";
638 $item.= "</item>";
639 $xml_msg=~ s/<xxx><\/xxx>/$item<xxx><\/xxx>/;
640 }
641 }
643 $xml_msg=~ s/<xxx><\/xxx>//;
645 # Return message
646 return ( $xml_msg );
647 }
650 ## @method opsi_set_product_properties
651 # 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.
652 # @param msg - STRING - xml message with tags productId, action, state and optional hostId, action and state
653 # @param msg_hash - HASHREF - message information parsed into a hash
654 # @param session_id - INTEGER - POE session id of the processing of this message
655 # @return out_msg - STRING - feedback to GOsa in success and error case
656 sub opsi_set_product_properties {
657 my ($msg, $msg_hash, $session_id) = @_;
658 my $header = @{$msg_hash->{'header'}}[0];
659 my $source = @{$msg_hash->{'source'}}[0];
660 my $target = @{$msg_hash->{'target'}}[0];
661 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
662 my ($productId, $hostId);
664 # Build return message with twisted target and source
665 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
666 if (defined $forward_to_gosa) {
667 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
668 }
670 # Sanity check of needed parameter
671 if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
672 &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
673 &add_content2xml_hash($out_hash, "error", "productId");
674 &main::daemon_log("$session_id ERROR: no productId specified or productId tag invalid: $msg", 1);
675 return ( &create_xml_string($out_hash) );
676 }
677 if (not exists $msg_hash->{'item'}) {
678 &add_content2xml_hash($out_hash, "error_string", "message needs one xml-tag 'item' and within the xml-tags 'name' and 'value'");
679 &add_content2xml_hash($out_hash, "error", "item");
680 &main::daemon_log("$session_id ERROR: message needs one xml-tag 'item' and within the xml-tags 'name' and 'value': $msg", 1);
681 return ( &create_xml_string($out_hash) );
682 } else {
683 if ((not exists @{$msg_hash->{'item'}}[0]->{'name'}) || (@{@{$msg_hash->{'item'}}[0]->{'name'}} != 1 )) {
684 &add_content2xml_hash($out_hash, "error_string", "message needs within the xml-tag 'item' one xml-tags 'name'");
685 &add_content2xml_hash($out_hash, "error", "name");
686 &main::daemon_log("$session_id ERROR: message needs within the xml-tag 'item' one xml-tags 'name': $msg", 1);
687 return ( &create_xml_string($out_hash) );
688 }
689 if ((not exists @{$msg_hash->{'item'}}[0]->{'value'}) || (@{@{$msg_hash->{'item'}}[0]->{'value'}} != 1 )) {
690 &add_content2xml_hash($out_hash, "error_string", "message needs within the xml-tag 'item' one xml-tags 'value'");
691 &add_content2xml_hash($out_hash, "error", "value");
692 &main::daemon_log("$session_id ERROR: message needs within the xml-tag 'item' one xml-tags 'value': $msg", 1);
693 return ( &create_xml_string($out_hash) );
694 }
695 }
696 # if no hostId is given, set_product_properties will act on globally
697 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} > 1)) {
698 &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
699 &add_content2xml_hash($out_hash, "error", "hostId");
700 &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1);
701 return ( &create_xml_string($out_hash) );
702 }
705 # Get productId
706 $productId = @{$msg_hash->{'productId'}}[0];
707 &add_content2xml_hash($out_hash, "productId", $productId);
709 # Get hostId if defined
710 if (exists $msg_hash->{'hostId'}){
711 $hostId = @{$msg_hash->{'hostId'}}[0];
712 &add_content2xml_hash($out_hash, "hostId", $hostId);
713 }
715 # Set product states if requested
716 if (defined @{$msg_hash->{'action'}}[0]){
717 &_set_action($productId, @{$msg_hash->{'action'}}[0], $hostId);
718 }
719 if (defined @{$msg_hash->{'state'}}[0]){
720 &_set_state($productId, @{$msg_hash->{'state'}}[0], $hostId);
721 }
723 # Find properties
724 foreach my $item (@{$msg_hash->{'item'}}){
725 # JSON Query
726 my $callobj;
728 if (defined $hostId){
729 $callobj = {
730 method => 'setProductProperty',
731 params => [ $productId, $item->{'name'}[0], $item->{'value'}[0], $hostId ],
732 id => 1,
733 };
734 } else {
735 $callobj = {
736 method => 'setProductProperty',
737 params => [ $productId, $item->{'name'}[0], $item->{'value'}[0] ],
738 id => 1,
739 };
740 }
742 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
743 my ($res_err, $res_err_string) = &check_opsi_res($res);
745 if ($res_err){
746 &main::daemon_log("$session_id ERROR: communication failed while setting '".$item->{'name'}[0]."': ".$res_err_string, 1);
747 &add_content2xml_hash($out_hash, "error", $res_err_string);
748 }
749 }
752 # Return message
753 return ( &create_xml_string($out_hash) );
754 }
757 ## @method opsi_get_client_hardware
758 # Reports client hardware inventory.
759 # @param msg - STRING - xml message with tag hostId
760 # @param msg_hash - HASHREF - message information parsed into a hash
761 # @param session_id - INTEGER - POE session id of the processing of this message
762 # @return out_msg - STRING - feedback to GOsa in success and error case
763 sub opsi_get_client_hardware {
764 my ($msg, $msg_hash, $session_id) = @_;
765 my $header = @{$msg_hash->{'header'}}[0];
766 my $source = @{$msg_hash->{'source'}}[0];
767 my $target = @{$msg_hash->{'target'}}[0];
768 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
769 my $hostId;
770 my $error = 0;
771 my $xml_msg;
773 # Build return message with twisted target and source
774 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
775 if (defined $forward_to_gosa) {
776 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
777 }
779 # Sanity check of needed parameter
780 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
781 $error++;
782 &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
783 &add_content2xml_hash($out_hash, "error", "hostId");
784 &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1);
785 }
787 if (not $error) {
789 # Get hostId
790 $hostId = @{$msg_hash->{'hostId'}}[0];
791 &add_content2xml_hash($out_hash, "hostId", "$hostId");
792 &add_content2xml_hash($out_hash, "xxx", "");
793 }
795 # Move to XML string
796 $xml_msg= &create_xml_string($out_hash);
798 if (not $error) {
800 # JSON Query
801 my $callobj = {
802 method => 'getHardwareInformation_hash',
803 params => [ $hostId ],
804 id => 1,
805 };
807 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
808 if (not &check_opsi_res($res)){
809 my $result= $res->result;
810 if (ref $result eq "HASH") {
811 foreach my $r (keys %{$result}){
812 my $item= "\n<item><id>".xml_quote($r)."</id>";
813 my $value= $result->{$r};
814 foreach my $sres (@{$value}){
816 foreach my $dres (keys %{$sres}){
817 if (defined $sres->{$dres}){
818 $item.= "<$dres>".xml_quote($sres->{$dres})."</$dres>";
819 }
820 }
822 }
823 $item.= "</item>";
824 $xml_msg=~ s%<xxx></xxx>%$item<xxx></xxx>%;
826 }
827 }
828 }
830 $xml_msg=~ s/<xxx><\/xxx>//;
832 }
834 # Return message
835 return ( $xml_msg );
836 }
839 ## @method opsi_list_clients
840 # Reports all Opsi clients.
841 # @param msg - STRING - xml message
842 # @param msg_hash - HASHREF - message information parsed into a hash
843 # @param session_id - INTEGER - POE session id of the processing of this message
844 # @return out_msg - STRING - feedback to GOsa in success and error case
845 sub opsi_list_clients {
846 my ($msg, $msg_hash, $session_id) = @_;
847 my $header = @{$msg_hash->{'header'}}[0];
848 my $source = @{$msg_hash->{'source'}}[0];
849 my $target = @{$msg_hash->{'target'}}[0];
850 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
852 # Build return message with twisted target and source
853 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
854 if (defined $forward_to_gosa) {
855 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
856 }
857 &add_content2xml_hash($out_hash, "xxx", "");
859 # Move to XML string
860 my $xml_msg= &create_xml_string($out_hash);
862 # JSON Query
863 my $callobj = {
864 method => 'getClients_listOfHashes',
865 params => [ ],
866 id => 1,
867 };
868 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
869 if (not &check_opsi_res($res)){
870 foreach my $host (@{$res->result}){
871 my $item= "\n<item><name>".$host->{'hostId'}."</name>";
872 if (defined($host->{'description'})){
873 $item.= "<description>".xml_quote($host->{'description'})."</description>";
874 }
875 if (defined($host->{'notes'})){
876 $item.= "<notes>".xml_quote($host->{'notes'})."</notes>";
877 }
878 if (defined($host->{'lastSeen'})){
879 $item.= "<lastSeen>".xml_quote($host->{'lastSeen'})."</lastSeen>";
880 }
882 $callobj = {
883 method => 'getIpAddress',
884 params => [ $host->{'hostId'} ],
885 id => 1,
886 };
887 my $sres= $main::opsi_client->call($main::opsi_url, $callobj);
888 if ( not &check_opsi_res($sres)){
889 $item.= "<ip>".xml_quote($sres->result)."</ip>";
890 }
892 $callobj = {
893 method => 'getMacAddress',
894 params => [ $host->{'hostId'} ],
895 id => 1,
896 };
897 $sres= $main::opsi_client->call($main::opsi_url, $callobj);
898 if ( not &check_opsi_res($sres)){
899 $item.= "<mac>".xml_quote($sres->result)."</mac>";
900 }
901 $item.= "</item>";
902 $xml_msg=~ s%<xxx></xxx>%$item<xxx></xxx>%;
903 }
904 }
906 $xml_msg=~ s/<xxx><\/xxx>//;
907 return ( $xml_msg );
908 }
912 ## @method opsi_get_client_software
913 # Reports client software inventory.
914 # @param msg - STRING - xml message with tag hostId
915 # @param msg_hash - HASHREF - message information parsed into a hash
916 # @param session_id - INTEGER - POE session id of the processing of this message
917 # @return out_msg - STRING - feedback to GOsa in success and error case
918 sub opsi_get_client_software {
919 my ($msg, $msg_hash, $session_id) = @_;
920 my $header = @{$msg_hash->{'header'}}[0];
921 my $source = @{$msg_hash->{'source'}}[0];
922 my $target = @{$msg_hash->{'target'}}[0];
923 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
924 my $error = 0;
925 my $hostId;
926 my $xml_msg;
928 # Build return message with twisted target and source
929 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
930 if (defined $forward_to_gosa) {
931 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
932 }
934 # Sanity check of needed parameter
935 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
936 $error++;
937 &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
938 &add_content2xml_hash($out_hash, "error", "hostId");
939 &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1);
940 }
942 if (not $error) {
944 # Get hostId
945 $hostId = @{$msg_hash->{'hostId'}}[0];
946 &add_content2xml_hash($out_hash, "hostId", "$hostId");
947 &add_content2xml_hash($out_hash, "xxx", "");
948 }
950 $xml_msg= &create_xml_string($out_hash);
952 if (not $error) {
954 # JSON Query
955 my $callobj = {
956 method => 'getSoftwareInformation_hash',
957 params => [ $hostId ],
958 id => 1,
959 };
961 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
962 if (not &check_opsi_res($res)){
963 my $result= $res->result;
964 # TODO : Ist das hier schon fertig???
965 }
967 $xml_msg=~ s/<xxx><\/xxx>//;
969 }
971 # Return message
972 return ( $xml_msg );
973 }
976 ## @method opsi_get_local_products
977 # Reports product for given hostId or globally.
978 # @param msg - STRING - xml message with optional tag hostId
979 # @param msg_hash - HASHREF - message information parsed into a hash
980 # @param session_id - INTEGER - POE session id of the processing of this message
981 # @return out_msg - STRING - feedback to GOsa in success and error case
982 sub opsi_get_local_products {
983 my ($msg, $msg_hash, $session_id) = @_;
984 my $header = @{$msg_hash->{'header'}}[0];
985 my $source = @{$msg_hash->{'source'}}[0];
986 my $target = @{$msg_hash->{'target'}}[0];
987 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
988 my $hostId;
990 # Build return message with twisted target and source
991 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
992 if (defined $forward_to_gosa) {
993 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
994 }
995 &add_content2xml_hash($out_hash, "xxx", "");
997 # Get hostId if defined
998 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1)) {
999 $hostId = @{$msg_hash->{'hostId'}}[0];
1000 &add_content2xml_hash($out_hash, "hostId", $hostId);
1001 }
1003 # Move to XML string
1004 my $xml_msg= &create_xml_string($out_hash);
1006 # For hosts, only return the products that are or get installed
1007 my $callobj;
1008 $callobj = {
1009 method => 'getLocalBootProductIds_list',
1010 params => [ ],
1011 id => 1,
1012 };
1014 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1015 my %r = ();
1016 for (@{$res->result}) { $r{$_} = 1 }
1018 if (not &check_opsi_res($res)){
1020 if (defined $hostId){
1021 $callobj = {
1022 method => 'getProductStates_hash',
1023 params => [ $hostId ],
1024 id => 1,
1025 };
1027 my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
1028 if (not &check_opsi_res($hres)){
1029 my $htmp= $hres->result->{$hostId};
1031 # Check state != not_installed or action == setup -> load and add
1032 foreach my $product (@{$htmp}){
1034 if (!defined ($r{$product->{'productId'}})){
1035 next;
1036 }
1038 # Now we've a couple of hashes...
1039 if ($product->{'installationStatus'} ne "not_installed" or
1040 $product->{'actionRequest'} eq "setup"){
1041 my $state= "<state>".$product->{'installationStatus'}."</state><action>".$product->{'actionRequest'}."</action>";
1043 $callobj = {
1044 method => 'getProduct_hash',
1045 params => [ $product->{'productId'} ],
1046 id => 1,
1047 };
1049 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
1050 if (not &check_opsi_res($sres)){
1051 my $tres= $sres->result;
1053 my $name= xml_quote($tres->{'name'});
1054 my $r= $product->{'productId'};
1055 my $description= xml_quote($tres->{'description'});
1056 $name=~ s/\//\\\//;
1057 $description=~ s/\//\\\//;
1058 $xml_msg=~ s/<xxx><\/xxx>/\n<item><productId>$r<\/productId><name>$name<\/name><description>$description<\/description><\/item>$state<xxx><\/xxx>/;
1059 }
1061 }
1062 }
1064 }
1066 } else {
1067 foreach my $r (@{$res->result}) {
1068 $callobj = {
1069 method => 'getProduct_hash',
1070 params => [ $r ],
1071 id => 1,
1072 };
1074 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
1075 if (not &check_opsi_res($sres)){
1076 my $tres= $sres->result;
1078 my $name= xml_quote($tres->{'name'});
1079 my $description= xml_quote($tres->{'description'});
1080 $name=~ s/\//\\\//;
1081 $description=~ s/\//\\\//;
1082 $xml_msg=~ s/<xxx><\/xxx>/\n<item><productId>$r<\/productId><name>$name<\/name><description>$description<\/description><\/item><xxx><\/xxx>/;
1083 }
1085 }
1087 }
1088 }
1090 $xml_msg=~ s/<xxx><\/xxx>//;
1092 # Retrun Message
1093 return ( $xml_msg );
1094 }
1097 ## @method opsi_del_client
1098 # Deletes a client from Opsi.
1099 # @param msg - STRING - xml message with tag hostId
1100 # @param msg_hash - HASHREF - message information parsed into a hash
1101 # @param session_id - INTEGER - POE session id of the processing of this message
1102 # @return out_msg - STRING - feedback to GOsa in success and error case
1103 sub opsi_del_client {
1104 my ($msg, $msg_hash, $session_id) = @_;
1105 my $header = @{$msg_hash->{'header'}}[0];
1106 my $source = @{$msg_hash->{'source'}}[0];
1107 my $target = @{$msg_hash->{'target'}}[0];
1108 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1109 my $hostId;
1110 my $error = 0;
1112 # Build return message with twisted target and source
1113 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1114 if (defined $forward_to_gosa) {
1115 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1116 }
1118 # Sanity check of needed parameter
1119 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
1120 $error++;
1121 &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
1122 &add_content2xml_hash($out_hash, "error", "hostId");
1123 &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1);
1124 }
1126 if (not $error) {
1128 # Get hostId
1129 $hostId = @{$msg_hash->{'hostId'}}[0];
1130 &add_content2xml_hash($out_hash, "hostId", "$hostId");
1132 # JSON Query
1133 my $callobj = {
1134 method => 'deleteClient',
1135 params => [ $hostId ],
1136 id => 1,
1137 };
1138 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1139 }
1141 # Move to XML string
1142 my $xml_msg= &create_xml_string($out_hash);
1144 # Return message
1145 return ( $xml_msg );
1146 }
1149 ## @method opsi_install_client
1150 # Set a client in Opsi to install and trigger a wake on lan message (WOL).
1151 # @param msg - STRING - xml message with tags hostId, macaddress
1152 # @param msg_hash - HASHREF - message information parsed into a hash
1153 # @param session_id - INTEGER - POE session id of the processing of this message
1154 # @return out_msg - STRING - feedback to GOsa in success and error case
1155 sub opsi_install_client {
1156 my ($msg, $msg_hash, $session_id) = @_;
1157 my $header = @{$msg_hash->{'header'}}[0];
1158 my $source = @{$msg_hash->{'source'}}[0];
1159 my $target = @{$msg_hash->{'target'}}[0];
1160 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1163 my ($hostId, $macaddress);
1165 my $error = 0;
1166 my @out_msg_l;
1168 # Build return message with twisted target and source
1169 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1170 if (defined $forward_to_gosa) {
1171 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1172 }
1174 # Sanity check of needed parameter
1175 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
1176 $error++;
1177 &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
1178 &add_content2xml_hash($out_hash, "error", "hostId");
1179 &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1);
1180 }
1181 if ((not exists $msg_hash->{'macaddress'}) || (@{$msg_hash->{'macaddress'}} != 1) || (@{$msg_hash->{'macaddress'}}[0] eq ref 'HASH') ) {
1182 $error++;
1183 &add_content2xml_hash($out_hash, "error_string", "no macaddress specified or macaddress tag invalid");
1184 &add_content2xml_hash($out_hash, "error", "macaddress");
1185 &main::daemon_log("$session_id ERROR: no macaddress specified or macaddress tag invalid: $msg", 1);
1186 } else {
1187 if ((exists $msg_hash->{'macaddress'}) &&
1188 ($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)) {
1189 $macaddress = $1;
1190 } else {
1191 $error ++;
1192 &add_content2xml_hash($out_hash, "error_string", "given mac address is not correct");
1193 &add_content2xml_hash($out_hash, "error", "macaddress");
1194 &main::daemon_log("$session_id ERROR: given mac address is not correct: $msg", 1);
1195 }
1196 }
1198 if (not $error) {
1200 # Get hostId
1201 $hostId = @{$msg_hash->{'hostId'}}[0];
1202 &add_content2xml_hash($out_hash, "hostId", "$hostId");
1204 # Load all products for this host with status != "not_installed" or actionRequest != "none"
1205 my $callobj = {
1206 method => 'getProductStates_hash',
1207 params => [ $hostId ],
1208 id => 1,
1209 };
1211 my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
1212 if (not &check_opsi_res($hres)){
1213 my $htmp= $hres->result->{$hostId};
1215 # check state != not_installed or action == setup -> load and add
1216 foreach my $product (@{$htmp}){
1217 # Now we've a couple of hashes...
1218 if ($product->{'installationStatus'} ne "not_installed" or
1219 $product->{'actionRequest'} ne "none"){
1221 # Do an action request for all these -> "setup".
1222 $callobj = {
1223 method => 'setProductActionRequest',
1224 params => [ $product->{'productId'}, $hostId, "setup" ],
1225 id => 1,
1226 };
1227 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1228 my ($res_err, $res_err_string) = &check_opsi_res($res);
1229 if ($res_err){
1230 &main::daemon_log("$session_id ERROR: cannot set product action request for '$hostId': ".$product->{'productId'}, 1);
1231 } else {
1232 &main::daemon_log("$session_id INFO: requesting 'setup' for '".$product->{'productId'}."' on $hostId", 1);
1233 }
1234 }
1235 }
1236 }
1237 push(@out_msg_l, &create_xml_string($out_hash));
1240 # Build wakeup message for client
1241 if (not $error) {
1242 my $wakeup_hash = &create_xml_hash("trigger_wake", "GOSA", "KNOWN_SERVER");
1243 &add_content2xml_hash($wakeup_hash, 'macaddress', $macaddress);
1244 my $wakeup_msg = &create_xml_string($wakeup_hash);
1245 push(@out_msg_l, $wakeup_msg);
1247 # invoke trigger wake for this gosa-si-server
1248 &main::server_server_com::trigger_wake($wakeup_msg, $wakeup_hash, $session_id);
1249 }
1250 }
1252 # Return messages
1253 return @out_msg_l;
1254 }
1257 ## @method _set_action
1258 # Set action for an Opsi client
1259 # @param product - STRING - Opsi product
1260 # @param action - STRING - action
1261 # @param hostId - STRING - Opsi hostId
1262 sub _set_action {
1263 my $product= shift;
1264 my $action = shift;
1265 my $hostId = shift;
1266 my $callobj;
1268 $callobj = {
1269 method => 'setProductActionRequest',
1270 params => [ $product, $hostId, $action],
1271 id => 1,
1272 };
1274 $main::opsi_client->call($main::opsi_url, $callobj);
1275 }
1277 ## @method _set_state
1278 # Set state for an Opsi client
1279 # @param product - STRING - Opsi product
1280 # @param action - STRING - state
1281 # @param hostId - STRING - Opsi hostId
1282 sub _set_state {
1283 my $product = shift;
1284 my $state = shift;
1285 my $hostId = shift;
1286 my $callobj;
1288 $callobj = {
1289 method => 'setProductState',
1290 params => [ $product, $hostId, $state ],
1291 id => 1,
1292 };
1294 $main::opsi_client->call($main::opsi_url, $callobj);
1295 }
1297 ################################
1298 #
1299 # @brief Create a license pool at Opsi server.
1300 #
1301 sub opsi_createLicensePool {
1302 my ($msg, $msg_hash, $session_id) = @_;
1303 my $header = @{$msg_hash->{'header'}}[0];
1304 my $source = @{$msg_hash->{'source'}}[0];
1305 my $target = @{$msg_hash->{'target'}}[0];
1306 my $out_hash;
1307 my $licensePoolId = defined $msg_hash->{'licensePoolId'} ? @{$msg_hash->{'licensePoolId'}}[0] : undef;
1308 my $description = defined $msg_hash->{'description'} ? @{$msg_hash->{'description'}}[0] : undef;
1309 my @productIds = defined $msg_hash->{'productIds'} ? $msg_hash->{'productIds'} : undef;
1310 my @windowsSoftwareIds = defined $msg_hash->{'windowsSoftwareIds'} ? $msg_hash->{'windowsSoftwareIds'} : undef;
1312 # Submit data to Opsi server
1313 my $callobj = {
1314 method => 'createLicensePool',
1315 params => [ $licensePoolId, $description, @productIds, @windowsSoftwareIds],
1316 id => 1,
1317 };
1318 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1320 # Check Opsi error
1321 my ($res_error, $res_error_str) = &check_opsi_res($res);
1322 if ($res_error){
1323 # Create error message
1324 &main::daemon_log("$session_id ERROR: cannot create license pool at Opsi server: ".$res_error_str, 1);
1325 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1327 } else {
1328 # Create function result message
1329 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source, $res->result);
1330 }
1332 return ( &create_xml_string($out_hash) );
1333 }
1335 ################################
1336 #
1337 # @brief Fetch license pool IDs from Opsi server and provide it as a list.
1338 #
1339 sub opsi_getLicensePoolIds_list {
1340 my ($msg, $msg_hash, $session_id) = @_;
1341 my $header = @{$msg_hash->{'header'}}[0];
1342 my $source = @{$msg_hash->{'source'}}[0];
1343 my $out_hash;
1345 # Fetch infos from Opsi server
1346 my $callobj = {
1347 method => 'getLicensePoolIds_list',
1348 params => [ ],
1349 id => 1,
1350 };
1351 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1353 # Check Opsi error
1354 my ($res_error, $res_error_str) = &check_opsi_res($res);
1355 if ($res_error){
1356 # Create error message
1357 &main::daemon_log("$session_id ERROR: cannot get license pool ID list from Opsi server: ".$res_error_str, 1);
1358 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1360 } else {
1361 # Create function result message
1362 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1363 map(&add_content2xml_hash($out_hash, "licensePoolIds", "$_"), @{$res->result});
1364 }
1366 return ( &create_xml_string($out_hash) );
1367 }
1370 ################################
1371 #
1372 # @brief Fetch license pool details(productIds, windowsSoftwareIds, description) from Opsi server and
1373 #
1374 sub opsi_getLicensePool_hash {
1375 my ($msg, $msg_hash, $session_id) = @_;
1376 my $header = @{$msg_hash->{'header'}}[0];
1377 my $source = @{$msg_hash->{'source'}}[0];
1378 my $target = @{$msg_hash->{'target'}}[0];
1379 my $licensePoolId;
1380 my $out_hash;
1382 # Check input sanity
1383 if (not defined $msg_hash->{'licensePoolId'}) {
1384 &main::daemon_log("$session_id ERROR: message contains no tag 'licensePoolId': ".$msg, 1);
1385 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, "message contains no tag 'licensePoolId'");
1386 return ( &create_xml_string($out_hash) );
1387 }
1388 if (ref @{$msg_hash->{'licensePoolId'}}[0] eq 'HASH') {
1389 &main::daemon_log("$session_id ERROR: message contains no license pool ID: ".$msg, 1);
1390 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, "message contains no license pool ID");
1391 return ( &create_xml_string($out_hash) );
1392 }
1393 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1395 # Fetch infos from Opsi server
1396 my $callobj = {
1397 method => 'getLicensePool_hash',
1398 params => [ $licensePoolId ],
1399 id => 1,
1400 };
1401 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1403 # Check Opsi error
1404 my ($res_error, $res_error_str) = &check_opsi_res($res);
1405 if ($res_error){
1406 # Create error message
1407 &main::daemon_log("$session_id ERROR: cannot get license pool from Opsi server: ".$res_error_str, 1);
1408 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source);
1409 &add_content2xml_hash($out_hash, "error", $res_error_str);
1411 } else {
1412 # Create function result message
1413 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1414 &add_content2xml_hash($out_hash, "licensePoolId", $res->result->{'licensePoolId'});
1415 &add_content2xml_hash($out_hash, "description", $res->result->{'description'});
1416 map(&add_content2xml_hash($out_hash, "productIds", "$_"), @{ $res->result->{'productIds'} });
1417 map(&add_content2xml_hash($out_hash, "windowsSoftwareIds", "$_"), @{ $res->result->{'windowsSoftwareIds'} });
1418 }
1420 return ( &create_xml_string($out_hash) );
1421 }
1423 ################################
1424 #
1425 # @brief Delete licnese pool by license pool ID. A pool can only be deleted if there are no software licenses bound to the pool.
1426 # by specifing the parameter deleteLicenses=True all software licenses bound to the pool are being deleted.
1427 #
1428 # TODO: funktion loescht alles bis auf die lizenz vertraege, weg finden wie auch noch die verträge gelöscht werden könne (getSoftwareLicenses_listOfHashes)
1429 sub opsi_deleteLicensePool {
1430 my ($msg, $msg_hash, $session_id) = @_;
1431 my $header = @{$msg_hash->{'header'}}[0];
1432 my $source = @{$msg_hash->{'source'}}[0];
1433 my $target = @{$msg_hash->{'target'}}[0];
1434 my $licensePoolId;
1435 my $out_hash;
1437 # Check input sanity
1438 if (not defined $msg_hash->{'licensePoolId'}) {
1439 &main::daemon_log("$session_id ERROR: message contains no tag 'licensePoolId': ".$msg, 1);
1440 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, "message contains no tag 'licensePoolId'");
1441 return ( &create_xml_string($out_hash) );
1442 }
1443 if (ref @{$msg_hash->{'licensePoolId'}}[0] eq 'HASH') {
1444 &main::daemon_log("$session_id ERROR: message contains no license pool ID: ".$msg, 1);
1445 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, "message contains no license pool ID");
1446 return ( &create_xml_string($out_hash) );
1447 }
1448 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1450 # Fetch infos from Opsi server
1451 my $callobj = {
1452 method => 'deleteLicensePool',
1453 params => [ $licensePoolId, 'deleteLicenses=True' ],
1454 id => 1,
1455 };
1456 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1458 # Check Opsi error
1459 my ($res_error, $res_error_str) = &check_opsi_res($res);
1460 if ($res_error){
1461 # Create error message
1462 &main::daemon_log("$session_id ERROR: cannot delete license pool at Opsi server: ".$res_error_str, 1);
1463 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1465 } else {
1466 # Create function result message
1467 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1468 }
1470 return ( &create_xml_string($out_hash) );
1472 }
1474 ################################
1475 #
1476 # @brief
1477 #
1478 sub opsi_createLicense {
1479 my ($msg, $msg_hash, $session_id) = @_;
1480 my $header = @{$msg_hash->{'header'}}[0];
1481 my $source = @{$msg_hash->{'source'}}[0];
1482 my $target = @{$msg_hash->{'target'}}[0];
1483 my $partner = defined $msg_hash->{'partner'} ? @{$msg_hash->{'partner'}}[0] : undef;
1484 my $conclusionDate = defined $msg_hash->{'conclusionDate'} ? @{$msg_hash->{'conclusionDate'}}[0] : undef;
1485 my $notificationDate = defined $msg_hash->{'notificationDate'} ? @{$msg_hash->{'notificationDate'}}[0] : undef;
1486 my $notes = defined $msg_hash->{'notes'} ? @{$msg_hash->{'notes'}}[0] : undef;
1487 my $licenseContractId;
1488 my $softwareLicenseId = defined $msg_hash->{'licenseId'} ? @{$msg_hash->{'licenseId'}}[0] : undef;
1489 my $licenseType = defined $msg_hash->{'licenseType'} ? @{$msg_hash->{'licenseType'}}[0] : undef;
1490 my $maxInstallations = defined $msg_hash->{'maxInstallations'} ? @{$msg_hash->{'maxInstallations'}}[0] : undef;
1491 my $boundToHost = defined $msg_hash->{'boundToHost'} ? @{$msg_hash->{'boundToHost'}}[0] : undef;
1492 my $expirationDate = defined $msg_hash->{'expirationDate'} ? @{$msg_hash->{'expirationDate'}}[0] : undef;
1493 my $out_hash;
1495 # Check input sanity
1496 if (not defined $msg_hash->{'licensePoolId'}) {
1497 &main::daemon_log("$session_id ERROR: message contains no tag 'licensePoolId': ".$msg, 1);
1498 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, "message contains no tag 'licensePoolId'");
1499 return ( &create_xml_string($out_hash) );
1500 }
1501 if (ref @{$msg_hash->{'licensePoolId'}}[0] eq 'HASH') {
1502 &main::daemon_log("$session_id ERROR: message contains no license pool ID: ".$msg, 1);
1503 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, "message contains no license pool ID");
1504 return ( &create_xml_string($out_hash) );
1505 }
1506 my $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1507 if (not defined $msg_hash->{'licenseKey'}) {
1508 &main::daemon_log("$session_id ERROR: message contains no tag 'licenseKey': ".$msg, 1);
1509 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, "message contains no tag 'licenseKey'");
1510 return ( &create_xml_string($out_hash) );
1511 }
1512 if (ref @{$msg_hash->{'licenseKey'}}[0] eq 'HASH') {
1513 &main::daemon_log("$session_id ERROR: message contains no license key: ".$msg, 1);
1514 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, "message contains no license key");
1515 return ( &create_xml_string($out_hash) );
1516 }
1517 my $licenseKey = @{$msg_hash->{'licenseKey'}}[0];
1519 # Create license contract at Opsi server
1520 my $callobj = {
1521 method => 'createLicenseContract',
1522 params => [ undef, $partner, $conclusionDate, $notificationDate, undef, $notes ],
1523 id => 1,
1524 };
1525 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1527 # Check Opsi error
1528 my ($res_error, $res_error_str) = &check_opsi_res($res);
1529 if ($res_error){
1530 print STDERR Dumper $res;
1531 # Create error message
1532 &main::daemon_log("$session_id ERROR: cannot create license contract at Opsi server: ".$res_error_str, 1);
1533 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1534 return ( &create_xml_string($out_hash) );
1535 }
1537 $licenseContractId = $res->result;
1538 print STDERR Dumper $licenseContractId;
1540 # Create software license at Opsi server
1541 $callobj = {
1542 method => 'createSoftwareLicense',
1543 params => [ $softwareLicenseId, $licenseContractId, $licenseType, $maxInstallations, $boundToHost, $expirationDate ],
1544 id => 1,
1545 };
1546 $res = $main::opsi_client->call($main::opsi_url, $callobj);
1548 # Check Opsi error
1549 ($res_error, $res_error_str) = &check_opsi_res($res);
1550 if ($res_error){
1551 print STDERR Dumper $res;
1552 # Create error message
1553 &main::daemon_log("$session_id ERROR: cannot create software license at Opsi server: ".$res_error_str, 1);
1554 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1555 return ( &create_xml_string($out_hash) );
1556 }
1557 $softwareLicenseId = $res->result;
1558 print STDERR Dumper $softwareLicenseId;
1560 # Add software license to license pool
1561 $callobj = {
1562 method => 'addSoftwareLicenseToLicensePool',
1563 params => [ $softwareLicenseId, $licensePoolId, $licenseKey ],
1564 id => 1,
1565 };
1566 $res = $main::opsi_client->call($main::opsi_url, $callobj);
1568 # Check Opsi error
1569 ($res_error, $res_error_str) = &check_opsi_res($res);
1570 if ($res_error){
1571 print STDERR Dumper $res;
1572 # Create error message
1573 &main::daemon_log("$session_id ERROR: cannot add software license to license pool at Opsi server: ".$res_error_str, 1);
1574 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1575 return ( &create_xml_string($out_hash) );
1576 }
1577 print STDERR Dumper $res;
1581 ## Create license contract
1582 #licenseContractId
1583 #partner
1584 #conclusionDate
1585 #notificationDate
1586 #expirationDate
1587 #notes
1588 #
1589 ## Create software license
1590 #softwareLicenseId,
1591 #licenseContractId,
1592 #licenseType,
1593 #maxInstallations,
1594 #boundToHost,
1595 #expirationDate
1596 return;
1597 }
1599 1;