Code

update: opsi functions
[gosa.git] / gosa-si / server / events / opsi_com.pm
1 ## @file
2 # @details A GOsa-SI-server event module containing all functions for message handling.
3 # @brief Implementation of an event module for GOsa-SI-server. 
6 package opsi_com;
7 use Exporter;
8 @ISA = qw(Exporter);
9 my @events = (
10     "get_events",
11     "opsi_install_client",
12     "opsi_get_netboot_products",  
13     "opsi_get_local_products",
14     "opsi_get_client_hardware",
15     "opsi_get_client_software",
16     "opsi_get_product_properties",
17     "opsi_set_product_properties",
18     "opsi_list_clients",
19     "opsi_del_client",
20     "opsi_add_client",
21     "opsi_modify_client",
22     "opsi_add_product_to_client",
23     "opsi_del_product_from_client",
24    );
25 @EXPORT = @events;
27 use strict;
28 use warnings;
29 use GOSA::GosaSupportDaemon;
30 use Data::Dumper;
31 use XML::Quote qw(:all);
34 BEGIN {}
36 END {}
38 ## @method get_events()
39 # A brief function returning a list of functions which are exported by importing the module.
40 # @return List of all provided functions
41 sub get_events {
42     return \@events;
43 }
45 ## @method opsi_add_product_to_client
46 # Adds an Opsi product to an Opsi client.
47 # @param msg - STRING - xml message with tags hostId and productId
48 # @param msg_hash - HASHREF - message information parsed into a hash
49 # @param session_id - INTEGER - POE session id of the processing of this message
50 # @return out_msg - STRING - feedback to GOsa in success and error case
51 sub opsi_add_product_to_client {
52     my ($msg, $msg_hash, $session_id) = @_;
53     my $header = @{$msg_hash->{'header'}}[0];
54     my $source = @{$msg_hash->{'source'}}[0];
55     my $target = @{$msg_hash->{'target'}}[0];
56     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
57     my ($hostId, $productId);
58     my $error = 0;
60     # Build return message
61     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
62     if (defined $forward_to_gosa) {
63         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
64     }
66     # Sanity check of needed parameter
67     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1))  {
68         $error++;
69         &add_content2xml_hash($out_hash, "hostId_error", "no hostId specified or hostId tag invalid");
70         &add_content2xml_hash($out_hash, "error", "hostId");
71         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
73     }
74     if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1)) {
75         $error++;
76         &add_content2xml_hash($out_hash, "productId_error", "no productId specified or productId tag invalid");
77         &add_content2xml_hash($out_hash, "error", "productId");
78         &main::daemon_log("$session_id ERROR: no productId specified or procutId tag invalid: $msg", 1); 
79     }
81     if (not $error) {
82         # Get hostID
83         $hostId = @{$msg_hash->{'hostId'}}[0];
84         &add_content2xml_hash($out_hash, "hostId", $hostId);
86         # Get productID
87         $productId = @{$msg_hash->{'productId'}}[0];
88         &add_content2xml_hash($out_hash, "productId", $productId);
90         # Do an action request for all these -> "setup".
91         my $callobj = {
92             method  => 'setProductActionRequest',
93             params  => [ $productId, $hostId, "setup" ],
94             id  => 1, }; 
96         my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
97         my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
98         if ($sres_err){
99             &main::daemon_log("$session_id ERROR: cannot add product: ".$sres_err_string, 1);
100             &add_content2xml_hash($out_hash, "error", $sres_err_string);
101         }
102     } 
104     # return message
105     return ( &create_xml_string($out_hash) );
108 ## @method opsi_del_product_from_client
109 # Deletes an Opsi-product from an Opsi-client. 
110 # @param msg - STRING - xml message with tags hostId and productId
111 # @param msg_hash - HASHREF - message information parsed into a hash
112 # @param session_id - INTEGER - POE session id of the processing of this message
113 # @return out_msg - STRING - feedback to GOsa in success and error case
114 sub opsi_del_product_from_client {
115     my ($msg, $msg_hash, $session_id) = @_;
116     my $header = @{$msg_hash->{'header'}}[0];
117     my $source = @{$msg_hash->{'source'}}[0];
118     my $target = @{$msg_hash->{'target'}}[0];
119     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
120     my ($hostId, $productId);
121     my $error = 0;
122     my ($sres, $sres_err, $sres_err_string);
124     # Build return message
125     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
126     if (defined $forward_to_gosa) {
127         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
128     }
130     # Sanity check of needed parameter
131     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1))  {
132         $error++;
133         &add_content2xml_hash($out_hash, "hostId_error", "no hostId specified or hostId tag invalid");
134         &add_content2xml_hash($out_hash, "error", "hostId");
135         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
137     }
138     if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1)) {
139         $error++;
140         &add_content2xml_hash($out_hash, "productId_error", "no productId specified or productId tag invalid");
141         &add_content2xml_hash($out_hash, "error", "productId");
142         &main::daemon_log("$session_id ERROR: no productId specified or procutId tag invalid: $msg", 1); 
143     }
145     # All parameter available
146     if (not $error) {
147         # Get hostID
148         $hostId = @{$msg_hash->{'hostId'}}[0];
149         &add_content2xml_hash($out_hash, "hostId", $hostId);
151         # Get productID
152         $productId = @{$msg_hash->{'productId'}}[0];
153         &add_content2xml_hash($out_hash, "productId", $productId);
156         #TODO: check the results for more than one entry which is currently installed
157         #$callobj = {
158         #    method  => 'getProductDependencies_listOfHashes',
159         #    params  => [ $productId ],
160         #    id  => 1, };
161         #
162         #my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
163         #my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
164         #if ($sres_err){
165         #  &main::daemon_log("ERROR: cannot perform dependency check: ".$sres_err_string, 1);
166         #  &add_content2xml_hash($out_hash, "error", $sres_err_string);
167         #  return ( &create_xml_string($out_hash) );
168         #}
171     # Check to get product action list 
172         my $callobj = {
173             method  => 'getPossibleProductActions_list',
174             params  => [ $productId ],
175             id  => 1, };
176         $sres = $main::opsi_client->call($main::opsi_url, $callobj);
177         ($sres_err, $sres_err_string) = &check_opsi_res($sres);
178         if ($sres_err){
179             &main::daemon_log("$session_id ERROR: cannot get product action list: ".$sres_err_string, 1);
180             &add_content2xml_hash($out_hash, "error", $sres_err_string);
181             $error++;
182         }
183     }
185     # Check action uninstall of product
186     if (not $error) {
187         my $uninst_possible= 0;
188         foreach my $r (@{$sres->result}) {
189             if ($r eq 'uninstall') {
190                 $uninst_possible= 1;
191             }
192         }
193         if (!$uninst_possible){
194             &main::daemon_log("$session_id ERROR: cannot uninstall product '$productId', product do not has the action 'uninstall'", 1);
195             &add_content2xml_hash($out_hash, "error", "cannot uninstall product '$productId', product do not has the action 'uninstall'");
196             $error++;
197         }
198     }
200     # Set product state to "none"
201     # Do an action request for all these -> "setup".
202     if (not $error) {
203         my $callobj = {
204             method  => 'setProductActionRequest',
205             params  => [ $productId, $hostId, "none" ],
206             id  => 1, 
207         }; 
208         $sres = $main::opsi_client->call($main::opsi_url, $callobj);
209         ($sres_err, $sres_err_string) = &check_opsi_res($sres);
210         if ($sres_err){
211             &main::daemon_log("$session_id ERROR: cannot delete product: ".$sres_err_string, 1);
212             &add_content2xml_hash($out_hash, "error", $sres_err_string);
213         }
214     }
216     # Return message
217     return ( &create_xml_string($out_hash) );
220 ## @method opsi_add_client
221 # Adds an Opsi client to Opsi.
222 # @param msg - STRING - xml message with tags hostId and macaddress
223 # @param msg_hash - HASHREF - message information parsed into a hash
224 # @param session_id - INTEGER - POE session id of the processing of this message
225 # @return out_msg - STRING - feedback to GOsa in success and error case
226 sub opsi_add_client {
227     my ($msg, $msg_hash, $session_id) = @_;
228     my $header = @{$msg_hash->{'header'}}[0];
229     my $source = @{$msg_hash->{'source'}}[0];
230     my $target = @{$msg_hash->{'target'}}[0];
231     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
232     my ($hostId, $mac);
233     my $error = 0;
234     my ($sres, $sres_err, $sres_err_string);
236     # build return message with twisted target and source
237     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
238     if (defined $forward_to_gosa) {
239         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
240     }
242     # Sanity check of needed parameter
243     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1))  {
244         $error++;
245         &add_content2xml_hash($out_hash, "hostId_error", "no hostId specified or hostId tag invalid");
246         &add_content2xml_hash($out_hash, "error", "hostId");
247         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
248     }
249     if ((not exists $msg_hash->{'macaddress'}) || (@{$msg_hash->{'macaddress'}} != 1))  {
250         $error++;
251         &add_content2xml_hash($out_hash, "macaddress_error", "no macaddress specified or macaddress tag invalid");
252         &add_content2xml_hash($out_hash, "error", "macaddress");
253         &main::daemon_log("$session_id ERROR: no macaddress specified or macaddress tag invalid: $msg", 1); 
254     }
256     if (not $error) {
257         # Get hostID
258         $hostId = @{$msg_hash->{'hostId'}}[0];
259         &add_content2xml_hash($out_hash, "hostId", $hostId);
261         # Get macaddress
262         $mac = @{$msg_hash->{'macaddress'}}[0];
263         &add_content2xml_hash($out_hash, "macaddress", $mac);
265         my $name= $hostId;
266         $name=~ s/^([^.]+).*$/$1/;
267         my $domain= $hostId;
268         $domain=~ s/^[^.]+\.(.*)$/$1/;
269         my ($description, $notes, $ip);
271         if (defined @{$msg_hash->{'description'}}[0]){
272             $description = @{$msg_hash->{'description'}}[0];
273         }
274         if (defined @{$msg_hash->{'notes'}}[0]){
275             $notes = @{$msg_hash->{'notes'}}[0];
276         }
277         if (defined @{$msg_hash->{'ip'}}[0]){
278             $ip = @{$msg_hash->{'ip'}}[0];
279         }
281         my $callobj;
282         $callobj = {
283             method  => 'createClient',
284             params  => [ $name, $domain, $description, $notes, $ip, $mac ],
285             id  => 1,
286         };
288         $sres = $main::opsi_client->call($main::opsi_url, $callobj);
289         ($sres_err, $sres_err_string) = &check_opsi_res($sres);
290         if ($sres_err){
291             &main::daemon_log("$session_id ERROR: cannot create client: ".$sres_err_string, 1);
292             &add_content2xml_hash($out_hash, "error", $sres_err_string);
293         } else {
294             &main::daemon_log("$session_id INFO: add opsi client '$hostId' with mac '$mac'", 5); 
295         }
296     }
298     # Return message
299     return ( &create_xml_string($out_hash) );
302 ## @method opsi_modify_client
303 # Modifies the parameters description, mac or notes for an Opsi client if the corresponding message tags are given.
304 # @param msg - STRING - xml message with tag hostId and optional description, mac or notes
305 # @param msg_hash - HASHREF - message information parsed into a hash
306 # @param session_id - INTEGER - POE session id of the processing of this message    
307 # @return out_msg - STRING - feedback to GOsa in success and error case
308 sub opsi_modify_client {
309     my ($msg, $msg_hash, $session_id) = @_;
310     my $header = @{$msg_hash->{'header'}}[0];
311     my $source = @{$msg_hash->{'source'}}[0];
312     my $target = @{$msg_hash->{'target'}}[0];
313     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
314     my $hostId;
315     my $error = 0;
316     my ($sres, $sres_err, $sres_err_string);
318     # Build return message with twisted target and source
319     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
320     if (defined $forward_to_gosa) {
321         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
322     }
324     # Sanity check of needed parameter
325     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1))  {
326         $error++;
327         &add_content2xml_hash($out_hash, "hostId_error", "no hostId specified or hostId tag invalid");
328         &add_content2xml_hash($out_hash, "error", "hostId");
329         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
330     }
332     if (not $error) {
333         # Get hostID
334         $hostId = @{$msg_hash->{'hostId'}}[0];
335         &add_content2xml_hash($out_hash, "hostId", $hostId);
336         my $name= $hostId;
337         $name=~ s/^([^.]+).*$/$1/;
338         my $domain= $hostId;
339         $domain=~ s/^[^.]+(.*)$/$1/;
341         # Modify description, notes or mac if defined
342         my ($description, $notes, $mac);
343         my $callobj;
344         if ((exists $msg_hash->{'description'}) && (@{$msg_hash->{'description'}} == 1) ){
345             $description = @{$msg_hash->{'description'}}[0];
346             $callobj = {
347                 method  => 'setHostDescription',
348                 params  => [ $hostId, $description ],
349                 id  => 1,
350             };
351             my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
352             my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
353             if ($sres_err){
354                 &main::daemon_log("ERROR: cannot set description: ".$sres_err_string, 1);
355                 &add_content2xml_hash($out_hash, "error", $sres_err_string);
356             }
357         }
358         if ((exists $msg_hash->{'notes'}) && (@{$msg_hash->{'notes'}} == 1)) {
359             $notes = @{$msg_hash->{'notes'}}[0];
360             $callobj = {
361                 method  => 'setHostNotes',
362                 params  => [ $hostId, $notes ],
363                 id  => 1,
364             };
365             my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
366             my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
367             if ($sres_err){
368                 &main::daemon_log("ERROR: cannot set notes: ".$sres_err_string, 1);
369                 &add_content2xml_hash($out_hash, "error", $sres_err_string);
370             }
371         }
372         if ((exists $msg_hash->{'mac'}) && (@{$msg_hash->{'mac'}} == 1)){
373             $mac = @{$msg_hash->{'mac'}}[0];
374             $callobj = {
375                 method  => 'setMacAddress',
376                 params  => [ $hostId, $mac ],
377                 id  => 1,
378             };
379             my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
380             my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
381             if ($sres_err){
382                 &main::daemon_log("ERROR: cannot set mac address: ".$sres_err_string, 1);
383                 &add_content2xml_hash($out_hash, "error", $sres_err_string);
384             }
385         }
386     }
388     # Return message
389     return ( &create_xml_string($out_hash) );
392     
393 ## @method opsi_get_netboot_products
394 # Get netboot products for specific host.
395 # @param msg - STRING - xml message with tag hostId
396 # @param msg_hash - HASHREF - message information parsed into a hash
397 # @param session_id - INTEGER - POE session id of the processing of this message
398 # @return out_msg - STRING - feedback to GOsa in success and error case
399 sub opsi_get_netboot_products {
400     my ($msg, $msg_hash, $session_id) = @_;
401     my $header = @{$msg_hash->{'header'}}[0];
402     my $source = @{$msg_hash->{'source'}}[0];
403     my $target = @{$msg_hash->{'target'}}[0];
404     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
405     my $hostId;
406     my $error = 0;
407     my $xml_msg;
409     # Build return message with twisted target and source
410     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
411     if (defined $forward_to_gosa) {
412         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
413     }
415     # Sanity check of needed parameter
416     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1))  {
417         $error++;
418         &add_content2xml_hash($out_hash, "hostId_error", "no hostId specified or hostId tag invalid");
419         &add_content2xml_hash($out_hash, "error", "hostId");
420         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
421     }
423     if (not $error) {
425         # Get hostID if defined
426         $hostId = @{$msg_hash->{'hostId'}}[0];
427         &add_content2xml_hash($out_hash, "hostId", $hostId);
429         &add_content2xml_hash($out_hash, "xxx", "");
430         $xml_msg= &create_xml_string($out_hash);
432         # For hosts, only return the products that are or get installed
433         my $callobj;
434         $callobj = {
435             method  => 'getNetBootProductIds_list',
436             params  => [ ],
437             id  => 1,
438         };
440         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
441         my %r = ();
442         for (@{$res->result}) { $r{$_} = 1 }
444         if (not &check_opsi_res($res)){
446             if (defined $hostId){
447                 $callobj = {
448                     method  => 'getProductStates_hash',
449                     params  => [ $hostId ],
450                     id  => 1,
451                 };
453                 my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
454                 if (not &check_opsi_res($hres)){
455                     my $htmp= $hres->result->{$hostId};
457                     # check state != not_installed or action == setup -> load and add
458                     foreach my $product (@{$htmp}){
460                         if (!defined ($r{$product->{'productId'}})){
461                             next;
462                         }
464                         # Now we've a couple of hashes...
465                         if ($product->{'installationStatus'} ne "not_installed" or
466                                 $product->{'actionRequest'} eq "setup"){
467                             my $state= "<state>".$product->{'installationStatus'}."</state><action>".$product->{'actionRequest'}."</action>";
469                             $callobj = {
470                                 method  => 'getProduct_hash',
471                                 params  => [ $product->{'productId'} ],
472                                 id  => 1,
473                             };
475                             my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
476                             if (not &check_opsi_res($sres)){
477                                 my $tres= $sres->result;
479                                 my $name= xml_quote($tres->{'name'});
480                                 my $r= $product->{'productId'};
481                                 my $description= xml_quote($tres->{'description'});
482                                 $name=~ s/\//\\\//;
483                                 $description=~ s/\//\\\//;
484                                 $xml_msg=~ s/<xxx><\/xxx>/<item><productId>$r<\/productId><name><\/name><description>$description<\/description><\/item>$state<xxx><\/xxx>/;
485                             }
486                         }
487                     }
489                 }
491             } else {
492                 foreach my $r (@{$res->result}) {
493                     $callobj = {
494                         method  => 'getProduct_hash',
495                         params  => [ $r ],
496                         id  => 1,
497                     };
499                     my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
500                     if (not &check_opsi_res($sres)){
501                         my $tres= $sres->result;
503                         my $name= xml_quote($tres->{'name'});
504                         my $description= xml_quote($tres->{'description'});
505                         $name=~ s/\//\\\//;
506                         $description=~ s/\//\\\//;
507                         $xml_msg=~ s/<xxx><\/xxx>/<item><productId>$r<\/productId><name><\/name><description>$description<\/description><\/item><xxx><\/xxx>/;
508                     }
509                 }
511             }
512         }
513         $xml_msg=~ s/<xxx><\/xxx>//;
514     }
516     # Return message
517     return ( $xml_msg );
521 ## @method opsi_get_product_properties
522 # Get product properties for a product and a specific host or gobally for a product.
523 # @param msg - STRING - xml message with tags productId and optional hostId
524 # @param msg_hash - HASHREF - message information parsed into a hash
525 # @param session_id - INTEGER - POE session id of the processing of this message
526 # @return out_msg - STRING - feedback to GOsa in success and error case
527 sub opsi_get_product_properties {
528     my ($msg, $msg_hash, $session_id) = @_;
529     my $header = @{$msg_hash->{'header'}}[0];
530     my $source = @{$msg_hash->{'source'}}[0];
531     my $target = @{$msg_hash->{'target'}}[0];
532     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
533     my ($hostId, $productId);
534     my $error = 0;
535     my $xml_msg;
537     # build return message with twisted target and source
538     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
539     if (defined $forward_to_gosa) {
540         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
541     }
543     # Sanity check of needed parameter
544     if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1))  {
545         $error++;
546         &add_content2xml_hash($out_hash, "productId_error", "no productId specified or productId tag invalid");
547         &add_content2xml_hash($out_hash, "error", "productId");
548         &main::daemon_log("$session_id ERROR: no productId specified or productId tag invalid: $msg", 1); 
549     }
551     if (not $error) {
553         # Get productid
554         $productId = @{$msg_hash->{'productId'}}[0];
555         &add_content2xml_hash($out_hash, "producId", "$productId");
558         $hostId = @{$msg_hash->{'hostId'}}[0];
559         &add_content2xml_hash($out_hash, "hostId", $hostId);
561         # Load actions
562         my $callobj = {
563             method  => 'getPossibleProductActions_list',
564             params  => [ $productId ],
565             id  => 1,
566         };
567         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
568         if (not &check_opsi_res($res)){
569             foreach my $action (@{$res->result}){
570                 &add_content2xml_hash($out_hash, "action", $action);
571             }
572         }
574         # Add place holder
575         &add_content2xml_hash($out_hash, "xxx", "");
577     }
579     # Move to XML string
580     $xml_msg= &create_xml_string($out_hash);
582     if (not $error) {
584         # JSON Query
585         my $callobj = {
586             method  => 'getProductProperties_hash',
587             params  => [ $productId ],
588             id  => 1,
589         };
590         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
591         if (not &check_opsi_res($res)){
592             my $r= $res->result;
593             foreach my $key (keys %{$r}) {
594                 my $item= "<item>";
595                 my $value= $r->{$key};
596                 if (UNIVERSAL::isa( $value, "ARRAY" )){
597                     foreach my $subval (@{$value}){
598                         $item.= "<$key>".xml_quote($subval)."</$key>";
599                     }
600                 } else {
601                     $item.= "<$key>".xml_quote($value)."</$key>";
602                 }
603                 $item.= "</item>";
604                 $xml_msg=~ s/<xxx><\/xxx>/$item<xxx><\/xxx>/;
605             }
606         }
608         $xml_msg=~ s/<xxx><\/xxx>//;
609     }
611     # Return message
612     return ( $xml_msg );
616 ## @method opsi_set_product_properties
617 # 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.
618 # @param msg - STRING - xml message with tags productId, action, state and optional hostId, action and state
619 # @param msg_hash - HASHREF - message information parsed into a hash
620 # @param session_id - INTEGER - POE session id of the processing of this message
621 # @return out_msg - STRING - feedback to GOsa in success and error case
622 sub opsi_set_product_properties {
623     my ($msg, $msg_hash, $session_id) = @_;
624     my $header = @{$msg_hash->{'header'}}[0];
625     my $source = @{$msg_hash->{'source'}}[0];
626     my $target = @{$msg_hash->{'target'}}[0];
627     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
628     my ($productId, $hostId);
629     my $error = 0;
630 print STDERR Dumper($msg_hash);
631     # Build return message with twisted target and source
632     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
633     if (defined $forward_to_gosa) {
634         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
635     }
637     # Sanity check of needed parameter
638     if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1))  {
639         $error++;
640         &add_content2xml_hash($out_hash, "productId_error", "no productId specified or productId tag invalid");
641         &add_content2xml_hash($out_hash, "error", "productId");
642         &main::daemon_log("$session_id ERROR: no productId specified or productId tag invalid: $msg", 1); 
643     }
644     if (not exists $msg_hash->{'item'}) {
645         $error++;
646         &add_content2xml_hash($out_hash, "item_error", "message needs one xml-tag 'item' and within the xml-tags 'name' and 'value'");
647         &add_content2xml_hash($out_hash, "error", "item");
648         &main::daemon_log("$session_id ERROR: message needs one xml-tag 'item' and within the xml-tags 'name' and 'value': $msg", 1); 
649     } else {
650         if ((not exists @{$msg_hash->{'item'}}[0]->{'name'}) || (@{@{$msg_hash->{'item'}}[0]->{'name'}} != 1 )) {
651             $error++;
652             &add_content2xml_hash($out_hash, "name_error", "message needs within the xml-tag 'item' one xml-tags 'name'");
653             &add_content2xml_hash($out_hash, "error", "name");
654             &main::daemon_log("$session_id ERROR: message needs within the xml-tag 'item' one xml-tags 'name': $msg", 1); 
655         }
656         if ((not exists @{$msg_hash->{'item'}}[0]->{'value'}) || (@{@{$msg_hash->{'item'}}[0]->{'value'}} != 1 )) {
657             $error++;
658             &add_content2xml_hash($out_hash, "value_error", "message needs within the xml-tag 'item' one xml-tags 'value'");
659             &add_content2xml_hash($out_hash, "error", "value");
660             &main::daemon_log("$session_id ERROR: message needs within the xml-tag 'item' one xml-tags 'value': $msg", 1); 
661         }
662     }
663     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1))  {
664         $error++;
665         &add_content2xml_hash($out_hash, "hostId_error", "hostId contains no or more than one values");
666         &add_content2xml_hash($out_hash, "error", "hostId");
667         &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1); 
668     }
670     if (not $error) {
671         
672     # Get productId
673         $productId =  @{$msg_hash->{'productId'}}[0];
674         &add_content2xml_hash($out_hash, "productId", $productId);
676     # Get hostID if defined
677         if (exists $msg_hash->{'hostId'}){
678             $hostId = @{$msg_hash->{'hostId'}}[0];
679             &add_content2xml_hash($out_hash, "hostId", $hostId);
680         }
682     # Set product states if requested
683         if (defined @{$msg_hash->{'action'}}[0]){
684             &_set_action($productId, @{$msg_hash->{'action'}}[0], $hostId);
685         }
686         if (defined @{$msg_hash->{'state'}}[0]){
687             &_set_state($productId, @{$msg_hash->{'state'}}[0], $hostId);
688         }
690     # Find properties
691         foreach my $item (@{$msg_hash->{'item'}}){
692             # JSON Query
693             my $callobj;
695             if (defined $hostId){
696                 $callobj = {
697                     method  => 'setProductProperty',
698                     params  => [ $productId, $item->{'name'}[0], $item->{'value'}[0], $hostId ],
699                     id  => 1,
700                 };
701             } else {
702                 $callobj = {
703                     method  => 'setProductProperty',
704                     params  => [ $productId, $item->{'name'}[0], $item->{'value'}[0] ],
705                     id  => 1,
706                 };
707             }
709             my $res = $main::opsi_client->call($main::opsi_url, $callobj);
710             my ($res_err, $res_err_string) = &check_opsi_res($res);
711 # TODO : Diese Errormessage klingt komisch! 
712             if (!$res_err){
713                 &main::daemon_log("$session_id ERROR: no communication failed while setting '".$item->{'name'}[0]."'", 1);
714                 &add_content2xml_hash($out_hash, "error", $res_err_string);
715             }
716         }
718     }
720     # Return message
721     return ( &create_xml_string($out_hash) );
725 ## @method opsi_get_client_hardware
726 # Reports client hardware inventory.
727 # @param msg - STRING - xml message with tag hostId
728 # @param msg_hash - HASHREF - message information parsed into a hash
729 # @param session_id - INTEGER - POE session id of the processing of this message
730 # @return out_msg - STRING - feedback to GOsa in success and error case
731 sub opsi_get_client_hardware {
732     my ($msg, $msg_hash, $session_id) = @_;
733     my $header = @{$msg_hash->{'header'}}[0];
734     my $source = @{$msg_hash->{'source'}}[0];
735     my $target = @{$msg_hash->{'target'}}[0];
736     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
737     my $hostId;
738     my $error = 0;
739     my $xml_msg;
741     # build return message with twisted target and source
742     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
743     if (defined $forward_to_gosa) {
744       &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
745     }
747     # Sanity check of needed parameter
748     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1))  {
749         $error++;
750         &add_content2xml_hash($out_hash, "hostId_error", "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     }
755     if (not $error) {
757     # Get hostID
758         $hostId = @{$msg_hash->{'hostId'}}[0];
759         &add_content2xml_hash($out_hash, "hostId", "$hostId");
760         &add_content2xml_hash($out_hash, "xxx", "");
761     }    
763     # Move to XML string
764     $xml_msg= &create_xml_string($out_hash);
765     
766     if (not $error) {
768     # JSON Query
769         my $callobj = {
770             method  => 'getHardwareInformation_hash',
771             params  => [ $hostId ],
772             id  => 1,
773         };
775         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
776         if (not &check_opsi_res($res)){
777             my $result= $res->result;
778             foreach my $r (keys %{$result}){
779                 my $item= "<item><id>".xml_quote($r)."</id>";
780                 my $value= $result->{$r};
781                 foreach my $sres (@{$value}){
783                     foreach my $dres (keys %{$sres}){
784                         if (defined $sres->{$dres}){
785                             $item.= "<$dres>".xml_quote($sres->{$dres})."</$dres>";
786                         }
787                     }
789                 }
790                 $item.= "</item>";
791                 $xml_msg=~ s%<xxx></xxx>%$item<xxx></xxx>%;
793             }
794         }
796         $xml_msg=~ s/<xxx><\/xxx>//;
798     }
800     # Return message
801     return ( $xml_msg );
805 ## @method opsi_list_clients
806 # Reports all Opsi clients. 
807 # @param msg - STRING - xml message 
808 # @param msg_hash - HASHREF - message information parsed into a hash
809 # @param session_id - INTEGER - POE session id of the processing of this message
810 # @return out_msg - STRING - feedback to GOsa in success and error case
811 sub opsi_list_clients {
812     my ($msg, $msg_hash, $session_id) = @_;
813     my $header = @{$msg_hash->{'header'}}[0];
814     my $source = @{$msg_hash->{'source'}}[0];
815     my $target = @{$msg_hash->{'target'}}[0];
816     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
817     my $error = 0;
819     # build return message with twisted target and source
820     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
821     if (defined $forward_to_gosa) {
822       &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
823     }
824     &add_content2xml_hash($out_hash, "xxx", "");
826     # Move to XML string
827     my $xml_msg= &create_xml_string($out_hash);
829     if (not $error) {
831     # JSON Query
832         my $callobj = {
833             method  => 'getClients_listOfHashes',
834             params  => [ ],
835             id  => 1,
836         };
837         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
838         if (not &check_opsi_res($res)){
839             foreach my $host (@{$res->result}){
841 print STDERR Dumper($host);            
842                 my $item= "<item><name>".$host->{'hostId'}."</name>";
843                 if (defined($host->{'description'})){
844                     $item.= "<description>".xml_quote($host->{'description'})."</description>";
845                 }
846                 if (defined($host->{'ip'})){
847                     $item.= "<ip>".xml_quote($host->{'ip'})."</ip>";
848                 }
849                 if (defined($host->{'mac'})){
850                     $item.= "<mac>".xml_quote($host->{'mac'})."</mac>";
851                 }
852                 if (defined($host->{'notes'})){
853                     $item.= "<notes>".xml_quote($host->{'notes'})."</notes>";
854                 }
855                 $item.= "</item>";
856                 $xml_msg=~ s%<xxx></xxx>%$item<xxx></xxx>%;
857             }
858         }
859     }
861     $xml_msg=~ s/<xxx><\/xxx>//;
862     return ( $xml_msg );
866 ## @method opsi_get_client_software
867 # Reports client software inventory.
868 # @param msg - STRING - xml message with tag hostId
869 # @param msg_hash - HASHREF - message information parsed into a hash
870 # @param session_id - INTEGER - POE session id of the processing of this message
871 # @return out_msg - STRING - feedback to GOsa in success and error case
872 sub opsi_get_client_software {
873     my ($msg, $msg_hash, $session_id) = @_;
874     my $header = @{$msg_hash->{'header'}}[0];
875     my $source = @{$msg_hash->{'source'}}[0];
876     my $target = @{$msg_hash->{'target'}}[0];
877     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
878     my $error = 0;
879     my $hostId;
880     my $xml_msg;
882     # build return message with twisted target and source
883     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
884     if (defined $forward_to_gosa) {
885       &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
886     }
888     # Sanity check of needed parameter
889     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1))  {
890         $error++;
891         &add_content2xml_hash($out_hash, "hostId_error", "hostId contains no or more than one values");
892         &add_content2xml_hash($out_hash, "error", "hostId");
893         &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1); 
894     }
896     if (not $error) {
898     # Get hostID
899         $hostId = @{$msg_hash->{'hostId'}}[0];
900         &add_content2xml_hash($out_hash, "hostId", "$hostId");
901         &add_content2xml_hash($out_hash, "xxx", "");
902     }
904     $xml_msg= &create_xml_string($out_hash);
906     if (not $error) {
908     # JSON Query
909         my $callobj = {
910             method  => 'getSoftwareInformation_hash',
911             params  => [ $hostId ],
912             id  => 1,
913         };
915         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
916         if (not &check_opsi_res($res)){
917             my $result= $res->result;
918 # TODO : Ist das hier schon fertig???   
919         }
921         $xml_msg=~ s/<xxx><\/xxx>//;
923     }
925     # Return message
926     return ( $xml_msg );
930 ## @method opsi_get_local_products
931 # Reports product for given hostId or globally.
932 # @param msg - STRING - xml message with optional tag hostId
933 # @param msg_hash - HASHREF - message information parsed into a hash
934 # @param session_id - INTEGER - POE session id of the processing of this message
935 # @return out_msg - STRING - feedback to GOsa in success and error case
936 sub opsi_get_local_products {
937     my ($msg, $msg_hash, $session_id) = @_;
938     my $header = @{$msg_hash->{'header'}}[0];
939     my $source = @{$msg_hash->{'source'}}[0];
940     my $target = @{$msg_hash->{'target'}}[0];
941     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
942     my $hostId;
943     my $error = 0;
945     # Build return message with twisted target and source
946     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
947     if (defined $forward_to_gosa) {
948         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
949     }
950     &add_content2xml_hash($out_hash, "xxx", "");
952     # Get hostID if defined
953     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1))  {
954         $hostId = @{$msg_hash->{'hostId'}}[0];
955         &add_content2xml_hash($out_hash, "hostId", $hostId);
956     }
958     # Move to XML string
959     my $xml_msg= &create_xml_string($out_hash);
961     # For hosts, only return the products that are or get installed
962     my $callobj;
963     $callobj = {
964         method  => 'getLocalBootProductIds_list',
965         params  => [ ],
966         id  => 1,
967     };
969     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
970     my %r = ();
971     for (@{$res->result}) { $r{$_} = 1 }
973     if (not &check_opsi_res($res)){
975         if (defined $hostId){
976             $callobj = {
977                 method  => 'getProductStates_hash',
978                 params  => [ $hostId ],
979                 id  => 1,
980             };
982             my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
983             if (not &check_opsi_res($hres)){
984                 my $htmp= $hres->result->{$hostId};
986                 # Check state != not_installed or action == setup -> load and add
987                 foreach my $product (@{$htmp}){
989                     if (!defined ($r{$product->{'productId'}})){
990                         next;
991                     }
993                     # Now we've a couple of hashes...
994                     if ($product->{'installationStatus'} ne "not_installed" or
995                             $product->{'actionRequest'} eq "setup"){
996                         my $state= "<state>".$product->{'installationStatus'}."</state><action>".$product->{'actionRequest'}."</action>";
998                         $callobj = {
999                             method  => 'getProduct_hash',
1000                             params  => [ $product->{'productId'} ],
1001                             id  => 1,
1002                         };
1004                         my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
1005                         if (not &check_opsi_res($sres)){
1006                             my $tres= $sres->result;
1008                             my $name= xml_quote($tres->{'name'});
1009                             my $r= $product->{'productId'};
1010                             my $description= xml_quote($tres->{'description'});
1011                             $name=~ s/\//\\\//;
1012                             $description=~ s/\//\\\//;
1013                             $xml_msg=~ s/<xxx><\/xxx>/<item><productId>$r<\/productId><name><\/name><description>$description<\/description><\/item>$state<xxx><\/xxx>/;
1014                         }
1016                     }
1017                 }
1019             }
1021         } else {
1022             foreach my $r (@{$res->result}) {
1023                 $callobj = {
1024                     method  => 'getProduct_hash',
1025                     params  => [ $r ],
1026                     id  => 1,
1027                 };
1029                 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
1030                 if (not &check_opsi_res($sres)){
1031                     my $tres= $sres->result;
1033                     my $name= xml_quote($tres->{'name'});
1034                     my $description= xml_quote($tres->{'description'});
1035                     $name=~ s/\//\\\//;
1036                     $description=~ s/\//\\\//;
1037                     $xml_msg=~ s/<xxx><\/xxx>/<item><productId>$r<\/productId><name><\/name><description>$description<\/description><\/item><xxx><\/xxx>/;
1038                 }
1040             }
1042         }
1043     }
1045     $xml_msg=~ s/<xxx><\/xxx>//;
1047     # Retrun Message
1048     return ( $xml_msg );
1052 ## @method opsi_del_client
1053 # Deletes a client from Opsi.
1054 # @param msg - STRING - xml message with tag hostId
1055 # @param msg_hash - HASHREF - message information parsed into a hash
1056 # @param session_id - INTEGER - POE session id of the processing of this message
1057 # @return out_msg - STRING - feedback to GOsa in success and error case
1058 sub opsi_del_client {
1059     my ($msg, $msg_hash, $session_id) = @_;
1060     my $header = @{$msg_hash->{'header'}}[0];
1061     my $source = @{$msg_hash->{'source'}}[0];
1062     my $target = @{$msg_hash->{'target'}}[0];
1063     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1064     my $hostId;
1065     my $error = 0;
1067     # Build return message with twisted target and source
1068     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1069     if (defined $forward_to_gosa) {
1070       &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1071     }
1073     # Sanity check of needed parameter
1074     if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1))  {
1075         $error++;
1076         &add_content2xml_hash($out_hash, "hostId_error", "hostId contains no or more than one values");
1077         &add_content2xml_hash($out_hash, "error", "hostId");
1078         &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1); 
1079     }
1081     if (not $error) {
1083     # Get hostID
1084         $hostId = @{$msg_hash->{'hostId'}}[0];
1085         &add_content2xml_hash($out_hash, "hostId", "$hostId");
1087     # JSON Query
1088         my $callobj = {
1089             method  => 'deleteClient',
1090             params  => [ $hostId ],
1091             id  => 1,
1092         };
1093         my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1094     }
1096     # Move to XML string
1097     my $xml_msg= &create_xml_string($out_hash);
1099     # Return message
1100     return ( $xml_msg );
1104 ## @method opsi_install_client
1105 # Set a client in Opsi to install and trigger a wake on lan message (WOL).  
1106 # @param msg - STRING - xml message with tags hostId, macaddress
1107 # @param msg_hash - HASHREF - message information parsed into a hash
1108 # @param session_id - INTEGER - POE session id of the processing of this message
1109 # @return out_msg - STRING - feedback to GOsa in success and error case
1110 sub opsi_install_client {
1111     my ($msg, $msg_hash, $session_id) = @_;
1112     my $header = @{$msg_hash->{'header'}}[0];
1113     my $source = @{$msg_hash->{'source'}}[0];
1114     my $target = @{$msg_hash->{'target'}}[0];
1115     my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1118     my ($hostId, $macaddress);
1120     my $error = 0;
1121     my @out_msg_l;
1123     # Build return message with twisted target and source
1124     my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1125     if (defined $forward_to_gosa) {
1126         &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1127     }
1129     # Sanity check of needed parameter
1130     if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1))  {
1131         $error++;
1132         &add_content2xml_hash($out_hash, "hostId_error", "no hostId specified or hostId tag invalid");
1133         &add_content2xml_hash($out_hash, "error", "hostId");
1134         &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1); 
1135     }
1136     if ((not exists $msg_hash->{'macaddress'}) || (@{$msg_hash->{'macaddress'}} != 1))  {
1137         $error++;
1138         &add_content2xml_hash($out_hash, "macaddress_error", "no macaddress specified or macaddress tag invalid");
1139         &add_content2xml_hash($out_hash, "error", "macaddress");
1140         &main::daemon_log("$session_id ERROR: no macaddress specified or macaddress tag invalid: $msg", 1); 
1141     } else {
1142         if ((exists $msg_hash->{'macaddress'}) && 
1143                 ($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)) {  
1144             $macaddress = $1; 
1145         } else { 
1146             $error ++; 
1147             &add_content2xml_hash($out_hash, "macaddress_error", "given mac address is not correct");
1148             &add_content2xml_hash($out_hash, "error", "macaddress");
1149             &main::daemon_log("$session_id ERROR: given mac address is not correct: $msg", 1); 
1150         }
1151     }
1153     if (not $error) {
1155     # Get hostId
1156         $hostId = @{$msg_hash->{'hostId'}}[0];
1157         &add_content2xml_hash($out_hash, "hostId", "$hostId");
1159         # Load all products for this host with status != "not_installed" or actionRequest != "none"
1160         my $callobj = {
1161             method  => 'getProductStates_hash',
1162             params  => [ $hostId ],
1163             id  => 1,
1164         };
1166         my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
1167         if (not &check_opsi_res($hres)){
1168             my $htmp= $hres->result->{$hostId};
1170             # check state != not_installed or action == setup -> load and add
1171             foreach my $product (@{$htmp}){
1172                 # Now we've a couple of hashes...
1173                 if ($product->{'installationStatus'} ne "not_installed" or
1174                         $product->{'actionRequest'} ne "none"){
1176                     # Do an action request for all these -> "setup".
1177                     $callobj = {
1178                         method  => 'setProductActionRequest',
1179                         params  => [ $product->{'productId'}, $hostId, "setup" ],
1180                         id  => 1,
1181                     };
1182                     my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1183                     my ($res_err, $res_err_string) = &check_opsi_res($res);
1184                     if ($res_err){
1185                         &main::daemon_log("$session_id ERROR: cannot set product action request for '$hostId': ".$product->{'productId'}, 1);
1186                     } else {
1187                         &main::daemon_log("$session_id INFO: requesting 'setup' for '".$product->{'productId'}."' on $hostId", 1);
1188                     }
1189                 }
1190             }
1191         }
1192         push(@out_msg_l, &create_xml_string($out_hash));
1193     
1195     # Build wakeup message for client
1196         if (not $error) {
1197             my $wakeup_hash = &create_xml_hash("trigger_wake", "GOSA", "KNOWN_SERVER");
1198             &add_content2xml_hash($wakeup_hash, 'macAddress', $macaddress);
1199             my $wakeup_msg = &create_xml_string($wakeup_hash);
1200             push(@out_msg_l, $wakeup_msg);
1202             # invoke trigger wake for this gosa-si-server
1203             &main::server_server_com::trigger_wake($wakeup_msg, $wakeup_hash, $session_id);
1204         }
1205     }
1206     
1207     # Return messages
1208     return @out_msg_l;
1212 ## @method _set_action
1213 # Set action for an Opsi client
1214 # @param product - STRING - Opsi product
1215 # @param action - STRING - action
1216 # @param hostId - STRING - Opsi hostId
1217 sub _set_action {
1218   my $product= shift;
1219   my $action = shift;
1220   my $hostId = shift;
1221   my $callobj;
1223   $callobj = {
1224     method  => 'setProductActionRequest',
1225     params  => [ $product, $hostId, $action],
1226     id  => 1,
1227   };
1229   $main::opsi_client->call($main::opsi_url, $callobj);
1232 ## @method _set_state
1233 # Set state for an Opsi client
1234 # @param product - STRING - Opsi product
1235 # @param action - STRING - state
1236 # @param hostId - STRING - Opsi hostId
1237 sub _set_state {
1238   my $product = shift;
1239   my $state = shift;
1240   my $hostId = shift;
1241   my $callobj;
1243   $callobj = {
1244     method  => 'setProductState',
1245     params  => [ $product, $hostId, $state ],
1246     id  => 1,
1247   };
1249   $main::opsi_client->call($main::opsi_url, $callobj);
1252 1;