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_get_full_product_host_information",
18 "opsi_set_product_properties",
19 "opsi_list_clients",
20 "opsi_del_client",
21 "opsi_add_client",
22 "opsi_modify_client",
23 "opsi_add_product_to_client",
24 "opsi_del_product_from_client",
25 "opsi_createLicensePool",
26 "opsi_deleteLicensePool",
27 "opsi_createLicense",
28 "opsi_assignSoftwareLicenseToHost",
29 "opsi_unassignSoftwareLicenseFromHost",
30 "opsi_unassignAllSoftwareLicensesFromHost",
31 "opsi_getSoftwareLicense_hash",
32 "opsi_getLicensePool_hash",
33 "opsi_getSoftwareLicenseUsages",
34 "opsi_getSoftwareLicenseUsagesForProductId",
35 "opsi_getLicensePools_listOfHashes",
36 "opsi_getLicenseInformationForProduct",
37 "opsi_getPool",
38 "opsi_getAllSoftwareLicenses",
39 "opsi_removeLicense",
40 "opsi_getReservedLicenses",
41 "opsi_boundHostToLicense",
42 "opsi_unboundHostFromLicense",
43 "opsi_get_full_product_host_information",
44 "opsi_test",
45 );
46 @EXPORT = @events;
48 use strict;
49 use warnings;
50 use GOSA::GosaSupportDaemon;
51 use Data::Dumper;
52 use XML::Quote qw(:all);
54 BEGIN {}
56 END {}
58 # ----------------------------------------------------------------------------
59 # D E C L A R A T I O N S
60 # ----------------------------------------------------------------------------
62 my $licenseTyp_hash = { 'OEM'=>'', 'VOLUME'=>'', 'RETAIL'=>''};
63 my ($opsi_enabled, $opsi_server, $opsi_admin, $opsi_password, $opsi_url, $opsi_client);
64 my %cfg_defaults = (
65 "Opsi" => {
66 "enabled" => [\$opsi_enabled, "false"],
67 "server" => [\$opsi_server, "localhost"],
68 "admin" => [\$opsi_admin, "opsi-admin"],
69 "password" => [\$opsi_password, "secret"],
70 },
71 );
72 &read_configfile($main::cfg_file, %cfg_defaults);
73 if ($opsi_enabled eq "true") {
74 use JSON::RPC::Client;
75 use XML::Quote qw(:all);
76 use Time::HiRes qw( time );
77 $opsi_url= "https://".$opsi_admin.":".$opsi_password."@".$opsi_server.":4447/rpc";
78 $opsi_client = new JSON::RPC::Client;
80 # Check version dependencies
81 eval { &myXmlHashToString(); };
82 if ($@ ) {
83 die "\nThe version of the Opsi plugin you want to use requires a newer version of GosaSupportDaemon. Please update your GOsa-SI or deactivate the Opsi plugin.\n";
84 }
85 }
87 # ----------------------------------------------------------------------------
88 # external methods handling the comunication with GOsa/GOsa-si
89 # ----------------------------------------------------------------------------
91 ################################
92 # @brief A function returning a list of functions which are exported by importing the module.
93 # @return List of all provided functions
94 sub get_events {
95 return \@events;
96 }
98 ################################
99 # @brief Adds an Opsi product to an Opsi client.
100 # @param msg - STRING - xml message with tags hostId and productId
101 # @param msg_hash - HASHREF - message information parsed into a hash
102 # @param session_id - INTEGER - POE session id of the processing of this message
103 # @return out_msg - STRING - feedback to GOsa in success and error case
104 sub opsi_add_product_to_client {
105 my $startTime = Time::HiRes::time;
106 my ($msg, $msg_hash, $session_id) = @_;
107 my $header = @{$msg_hash->{'header'}}[0];
108 my $source = @{$msg_hash->{'source'}}[0];
109 my $target = @{$msg_hash->{'target'}}[0];
110 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
112 # Build return message
113 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
114 if (defined $forward_to_gosa) {
115 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
116 }
118 # Sanity check of needed parameter
119 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
120 return &_giveErrorFeedback($msg_hash, "no hostId specified or hostId tag invalid", $session_id);
121 }
122 if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
123 return &_giveErrorFeedback($msg_hash, "no productId specified or productId tag invalid", $session_id);
124 }
126 # Get hostId
127 my $hostId = @{$msg_hash->{'hostId'}}[0];
128 &add_content2xml_hash($out_hash, "hostId", $hostId);
130 # Get productID
131 my $productId = @{$msg_hash->{'productId'}}[0];
132 &add_content2xml_hash($out_hash, "productId", $productId);
134 # Do an action request for all these -> "setup".
135 my $callobj = {
136 method => 'setProductActionRequest',
137 params => [ $productId, $hostId, "setup" ],
138 id => 1, };
139 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
141 if (&check_opsi_res($res)) { return ( (caller(0))[3]." : ".$_, 1 ); };
143 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
144 return ( &create_xml_string($out_hash) );
145 }
147 ################################
148 # @brief Deletes an Opsi-product from an Opsi-client.
149 # @param msg - STRING - xml message with tags hostId and productId
150 # @param msg_hash - HASHREF - message information parsed into a hash
151 # @param session_id - INTEGER - POE session id of the processing of this message
152 # @return out_msg - STRING - feedback to GOsa in success and error case
153 sub opsi_del_product_from_client {
154 my $startTime = Time::HiRes::time;
155 my ($msg, $msg_hash, $session_id) = @_;
156 my $header = @{$msg_hash->{'header'}}[0];
157 my $source = @{$msg_hash->{'source'}}[0];
158 my $target = @{$msg_hash->{'target'}}[0];
159 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
160 my ($hostId, $productId);
161 my $error = 0;
162 my ($sres, $sres_err, $sres_err_string);
164 # Build return message
165 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
166 if (defined $forward_to_gosa) {
167 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
168 }
170 # Sanity check of needed parameter
171 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
172 $error++;
173 &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
174 &add_content2xml_hash($out_hash, "error", "hostId");
175 &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1);
177 }
178 if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
179 $error++;
180 &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
181 &add_content2xml_hash($out_hash, "error", "productId");
182 &main::daemon_log("$session_id ERROR: no productId specified or procutId tag invalid: $msg", 1);
183 }
185 # All parameter available
186 if (not $error) {
187 # Get hostId
188 $hostId = @{$msg_hash->{'hostId'}}[0];
189 &add_content2xml_hash($out_hash, "hostId", $hostId);
191 # Get productID
192 $productId = @{$msg_hash->{'productId'}}[0];
193 &add_content2xml_hash($out_hash, "productId", $productId);
195 # Check to get product action list
196 my $callobj = {
197 method => 'getPossibleProductActions_list',
198 params => [ $productId ],
199 id => 1, };
200 $sres = $main::opsi_client->call($main::opsi_url, $callobj);
201 ($sres_err, $sres_err_string) = &check_opsi_res($sres);
202 if ($sres_err){
203 &main::daemon_log("$session_id ERROR: cannot get product action list: ".$sres_err_string, 1);
204 &add_content2xml_hash($out_hash, "error", $sres_err_string);
205 $error++;
206 }
207 }
209 # Check action uninstall of product
210 if (not $error) {
211 my $uninst_possible= 0;
212 foreach my $r (@{$sres->result}) {
213 if ($r eq 'uninstall') {
214 $uninst_possible= 1;
215 }
216 }
217 if (!$uninst_possible){
218 &main::daemon_log("$session_id ERROR: cannot uninstall product '$productId', product do not has the action 'uninstall'", 1);
219 &add_content2xml_hash($out_hash, "error", "cannot uninstall product '$productId', product do not has the action 'uninstall'");
220 $error++;
221 }
222 }
224 # Set product state to "none"
225 # Do an action request for all these -> "setup".
226 if (not $error) {
227 my $callobj = {
228 method => 'setProductActionRequest',
229 params => [ $productId, $hostId, "none" ],
230 id => 1,
231 };
232 $sres = $main::opsi_client->call($main::opsi_url, $callobj);
233 ($sres_err, $sres_err_string) = &check_opsi_res($sres);
234 if ($sres_err){
235 &main::daemon_log("$session_id ERROR: cannot delete product: ".$sres_err_string, 1);
236 &add_content2xml_hash($out_hash, "error", $sres_err_string);
237 }
238 }
240 # Return message
241 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
242 return ( &create_xml_string($out_hash) );
243 }
245 ################################
246 # @brief Adds an Opsi client to Opsi.
247 # @param msg - STRING - xml message with tags hostId and macaddress
248 # @param msg_hash - HASHREF - message information parsed into a hash
249 # @param session_id - INTEGER - POE session id of the processing of this message
250 # @return out_msg - STRING - feedback to GOsa in success and error case
251 sub opsi_add_client {
252 my $startTime = Time::HiRes::time;
253 my ($msg, $msg_hash, $session_id) = @_;
254 my $header = @{$msg_hash->{'header'}}[0];
255 my $source = @{$msg_hash->{'source'}}[0];
256 my $target = @{$msg_hash->{'target'}}[0];
257 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
258 my ($hostId, $mac);
259 my $error = 0;
260 my ($sres, $sres_err, $sres_err_string);
262 # Build return message with twisted target and source
263 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
264 if (defined $forward_to_gosa) {
265 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
266 }
268 # Sanity check of needed parameter
269 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
270 $error++;
271 &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
272 &add_content2xml_hash($out_hash, "error", "hostId");
273 &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1);
274 }
275 if ((not exists $msg_hash->{'macaddress'}) || (@{$msg_hash->{'macaddress'}} != 1) || (@{$msg_hash->{'macaddress'}}[0] eq ref 'HASH')) {
276 $error++;
277 &add_content2xml_hash($out_hash, "error_string", "no macaddress specified or macaddress tag invalid");
278 &add_content2xml_hash($out_hash, "error", "macaddress");
279 &main::daemon_log("$session_id ERROR: no macaddress specified or macaddress tag invalid: $msg", 1);
280 }
282 if (not $error) {
283 # Get hostId
284 $hostId = @{$msg_hash->{'hostId'}}[0];
285 &add_content2xml_hash($out_hash, "hostId", $hostId);
287 # Get macaddress
288 $mac = @{$msg_hash->{'macaddress'}}[0];
289 &add_content2xml_hash($out_hash, "macaddress", $mac);
291 my $name= $hostId;
292 $name=~ s/^([^.]+).*$/$1/;
293 my $domain= $hostId;
294 $domain=~ s/^[^.]+\.(.*)$/$1/;
295 my ($description, $notes, $ip);
297 if (defined @{$msg_hash->{'description'}}[0]){
298 $description = @{$msg_hash->{'description'}}[0];
299 }
300 if (defined @{$msg_hash->{'notes'}}[0]){
301 $notes = @{$msg_hash->{'notes'}}[0];
302 }
303 if (defined @{$msg_hash->{'ip'}}[0]){
304 $ip = @{$msg_hash->{'ip'}}[0];
305 }
307 my $callobj;
308 $callobj = {
309 method => 'createClient',
310 params => [ $name, $domain, $description, $notes, $ip, $mac ],
311 id => 1,
312 };
314 $sres = $main::opsi_client->call($main::opsi_url, $callobj);
315 ($sres_err, $sres_err_string) = &check_opsi_res($sres);
316 if ($sres_err){
317 &main::daemon_log("$session_id ERROR: cannot create client: ".$sres_err_string, 1);
318 &add_content2xml_hash($out_hash, "error", $sres_err_string);
319 } else {
320 &main::daemon_log("$session_id INFO: add opsi client '$hostId' with mac '$mac'", 5);
321 }
322 }
324 # Return message
325 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
326 return ( &create_xml_string($out_hash) );
327 }
329 ################################
330 # @brief Modifies the parameters description, mac or notes for an Opsi client if the corresponding message tags are given.
331 # @param msg - STRING - xml message with tag hostId and optional description, mac or notes
332 # @param msg_hash - HASHREF - message information parsed into a hash
333 # @param session_id - INTEGER - POE session id of the processing of this message
334 # @return out_msg - STRING - feedback to GOsa in success and error case
335 sub opsi_modify_client {
336 my $startTime = Time::HiRes::time;
337 my ($msg, $msg_hash, $session_id) = @_;
338 my $header = @{$msg_hash->{'header'}}[0];
339 my $source = @{$msg_hash->{'source'}}[0];
340 my $target = @{$msg_hash->{'target'}}[0];
341 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
342 my $hostId;
343 my $error = 0;
344 my ($sres, $sres_err, $sres_err_string);
346 # Build return message with twisted target and source
347 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
348 if (defined $forward_to_gosa) {
349 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
350 }
352 # Sanity check of needed parameter
353 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
354 $error++;
355 &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
356 &add_content2xml_hash($out_hash, "error", "hostId");
357 &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1);
358 }
360 if (not $error) {
361 # Get hostId
362 $hostId = @{$msg_hash->{'hostId'}}[0];
363 &add_content2xml_hash($out_hash, "hostId", $hostId);
364 my $name= $hostId;
365 $name=~ s/^([^.]+).*$/$1/;
366 my $domain= $hostId;
367 $domain=~ s/^[^.]+(.*)$/$1/;
369 # Modify description, notes or mac if defined
370 my ($description, $notes, $mac);
371 my $callobj;
372 if ((exists $msg_hash->{'description'}) && (@{$msg_hash->{'description'}} == 1) ){
373 $description = @{$msg_hash->{'description'}}[0];
374 $callobj = {
375 method => 'setHostDescription',
376 params => [ $hostId, $description ],
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 description: ".$sres_err_string, 1);
383 &add_content2xml_hash($out_hash, "error", $sres_err_string);
384 }
385 }
386 if ((exists $msg_hash->{'notes'}) && (@{$msg_hash->{'notes'}} == 1)) {
387 $notes = @{$msg_hash->{'notes'}}[0];
388 $callobj = {
389 method => 'setHostNotes',
390 params => [ $hostId, $notes ],
391 id => 1,
392 };
393 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
394 my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
395 if ($sres_err){
396 &main::daemon_log("ERROR: cannot set notes: ".$sres_err_string, 1);
397 &add_content2xml_hash($out_hash, "error", $sres_err_string);
398 }
399 }
400 if ((exists $msg_hash->{'mac'}) && (@{$msg_hash->{'mac'}} == 1)){
401 $mac = @{$msg_hash->{'mac'}}[0];
402 $callobj = {
403 method => 'setMacAddress',
404 params => [ $hostId, $mac ],
405 id => 1,
406 };
407 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
408 my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
409 if ($sres_err){
410 &main::daemon_log("ERROR: cannot set mac address: ".$sres_err_string, 1);
411 &add_content2xml_hash($out_hash, "error", $sres_err_string);
412 }
413 }
414 }
416 # Return message
417 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
418 return ( &create_xml_string($out_hash) );
419 }
421 ################################
422 # @brief Get netboot products for specific host.
423 # @param msg - STRING - xml message with tag hostId
424 # @param msg_hash - HASHREF - message information parsed into a hash
425 # @param session_id - INTEGER - POE session id of the processing of this message
426 # @return out_msg - STRING - feedback to GOsa in success and error case
427 sub opsi_get_netboot_products {
428 my $startTime = Time::HiRes::time;
429 my ($msg, $msg_hash, $session_id) = @_;
430 my $header = @{$msg_hash->{'header'}}[0];
431 my $source = @{$msg_hash->{'source'}}[0];
432 my $target = @{$msg_hash->{'target'}}[0];
433 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
434 my $hostId;
436 # Build return message with twisted target and source
437 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
438 if (defined $forward_to_gosa) {
439 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
440 }
441 &add_content2xml_hash($out_hash, "xxx", "");
443 # Get hostId if defined
444 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1)) {
445 $hostId = @{$msg_hash->{'hostId'}}[0];
446 &add_content2xml_hash($out_hash, "hostId", $hostId);
447 }
449 # Move to XML string
450 my $xml_msg= &create_xml_string($out_hash);
452 my $callobj;
453 # Check if we need to get host or global information
454 if (defined $hostId){
455 $callobj = {
456 method => 'getProductHostInformation_list',
457 params => [ $hostId, undef, 'netboot'],
458 id => 1,
459 };
461 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
462 if (not &check_opsi_res($res)){
463 foreach my $product (@{$res->result}){
464 my $replace= "<item><productId>".xml_quote($product->{'productId'})."<\/productId><name>".xml_quote($product->{'name'})."<\/name><description>".xml_quote($product->{'description'})."<\/description><state>".xml_quote($product->{'installationStatus'})."</state><action>".xml_quote($product->{'actionRequest'})."</action><\/item><xxx><\/xxx>";
465 $xml_msg=~ s/<xxx><\/xxx>/\n$replace/;
466 }
467 }
469 } else {
471 # For hosts, only return the products that are or get installed
472 $callobj = {
473 method => 'getProductInformation_list',
474 params => [ undef, 'netboot' ],
475 id => 1,
476 };
478 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
479 if (not &check_opsi_res($res)){
480 foreach my $product (@{$res->result}) {
481 my $replace= "<item><productId>".xml_quote($product->{'productId'})."<\/productId><name>".xml_quote($product->{'name'})."<\/name><description>".xml_quote($product->{'description'})."<\/description><\/item><xxx><\/xxx>";
482 $xml_msg=~ s/<xxx><\/xxx>/\n$replace/;
483 }
484 }
485 }
487 $xml_msg=~ s/<xxx><\/xxx>//;
489 # Retrun Message
490 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
491 return ( $xml_msg );
492 }
494 ################################
495 # @brief Get product properties for a product and a specific host or gobally for a product.
496 # @param msg - STRING - xml message with tags productId and optional hostId
497 # @param msg_hash - HASHREF - message information parsed into a hash
498 # @param session_id - INTEGER - POE session id of the processing of this message
499 # @return out_msg - STRING - feedback to GOsa in success and error case
500 sub opsi_get_product_properties {
501 my $startTime = Time::HiRes::time;
502 my ($msg, $msg_hash, $session_id) = @_;
503 my $header = @{$msg_hash->{'header'}}[0];
504 my $source = @{$msg_hash->{'source'}}[0];
505 my $target = @{$msg_hash->{'target'}}[0];
506 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
507 my ($hostId, $productId);
508 my $xml_msg;
510 # Build return message with twisted target and source
511 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
512 if (defined $forward_to_gosa) {
513 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
514 }
516 # Sanity check of needed parameter
517 if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
518 &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
519 &add_content2xml_hash($out_hash, "error", "productId");
520 &main::daemon_log("$session_id ERROR: no productId specified or productId tag invalid: $msg", 1);
522 # Return message
523 return ( &create_xml_string($out_hash) );
524 }
526 # Get productid
527 $productId = @{$msg_hash->{'productId'}}[0];
528 &add_content2xml_hash($out_hash, "producId", "$productId");
530 # Get hostId if defined
531 if (defined @{$msg_hash->{'hostId'}}[0]){
532 $hostId = @{$msg_hash->{'hostId'}}[0];
533 &add_content2xml_hash($out_hash, "hostId", $hostId);
534 }
536 # Load actions
537 my $callobj = {
538 method => 'getPossibleProductActions_list',
539 params => [ $productId ],
540 id => 1,
541 };
542 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
543 if (not &check_opsi_res($res)){
544 foreach my $action (@{$res->result}){
545 &add_content2xml_hash($out_hash, "action", $action);
546 }
547 }
549 # Add place holder
550 &add_content2xml_hash($out_hash, "xxx", "");
552 # Move to XML string
553 $xml_msg= &create_xml_string($out_hash);
555 # JSON Query
556 if (defined $hostId){
557 $callobj = {
558 method => 'getProductProperties_hash',
559 params => [ $productId, $hostId ],
560 id => 1,
561 };
562 } else {
563 $callobj = {
564 method => 'getProductProperties_hash',
565 params => [ $productId ],
566 id => 1,
567 };
568 }
569 $res = $main::opsi_client->call($main::opsi_url, $callobj);
571 # JSON Query 2
572 $callobj = {
573 method => 'getProductPropertyDefinitions_listOfHashes',
574 params => [ $productId ],
575 id => 1,
576 };
578 # Assemble options
579 my $res2 = $main::opsi_client->call($main::opsi_url, $callobj);
580 my $values = {};
581 my $descriptions = {};
582 if (not &check_opsi_res($res2)){
583 my $r= $res2->result;
585 foreach my $entr (@$r){
586 # Unroll values
587 my $cnv;
588 if (UNIVERSAL::isa( $entr->{'values'}, "ARRAY" )){
589 foreach my $v (@{$entr->{'values'}}){
590 $cnv.= "<value>$v</value>";
591 }
592 } else {
593 $cnv= $entr->{'values'};
594 }
595 $values->{$entr->{'name'}}= $cnv;
596 $descriptions->{$entr->{'name'}}= "<description>".$entr->{'description'}."</description>";
597 }
598 }
600 if (not &check_opsi_res($res)){
601 my $r= $res->result;
602 foreach my $key (keys %{$r}) {
603 my $item= "\n<item>";
604 my $value= $r->{$key};
605 my $dsc= "";
606 my $vals= "";
607 if (defined $descriptions->{$key}){
608 $dsc= $descriptions->{$key};
609 }
610 if (defined $values->{$key}){
611 $vals= $values->{$key};
612 }
613 $item.= "<$key>$dsc<default>".xml_quote($value)."</default>$vals</$key>";
614 $item.= "</item>";
615 $xml_msg=~ s/<xxx><\/xxx>/$item<xxx><\/xxx>/;
616 }
617 }
619 $xml_msg=~ s/<xxx><\/xxx>//;
621 # Return message
622 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
623 return ( $xml_msg );
624 }
626 ################################
627 # @brief 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.
628 # @param msg - STRING - xml message with tags productId, action, state and optional hostId, action and state
629 # @param msg_hash - HASHREF - message information parsed into a hash
630 # @param session_id - INTEGER - POE session id of the processing of this message
631 # @return out_msg - STRING - feedback to GOsa in success and error case
632 sub opsi_set_product_properties {
633 my $startTime = Time::HiRes::time;
634 my ($msg, $msg_hash, $session_id) = @_;
635 my $header = @{$msg_hash->{'header'}}[0];
636 my $source = @{$msg_hash->{'source'}}[0];
637 my $target = @{$msg_hash->{'target'}}[0];
638 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
639 my ($productId, $hostId);
641 # Build return message with twisted target and source
642 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
643 if (defined $forward_to_gosa) {
644 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
645 }
647 # Sanity check of needed parameter
648 if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
649 &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
650 &add_content2xml_hash($out_hash, "error", "productId");
651 &main::daemon_log("$session_id ERROR: no productId specified or productId tag invalid: $msg", 1);
652 return ( &create_xml_string($out_hash) );
653 }
654 if (not exists $msg_hash->{'item'}) {
655 &add_content2xml_hash($out_hash, "error_string", "message needs one xml-tag 'item' and within the xml-tags 'name' and 'value'");
656 &add_content2xml_hash($out_hash, "error", "item");
657 &main::daemon_log("$session_id ERROR: message needs one xml-tag 'item' and within the xml-tags 'name' and 'value': $msg", 1);
658 return ( &create_xml_string($out_hash) );
659 } else {
660 if ((not exists @{$msg_hash->{'item'}}[0]->{'name'}) || (@{@{$msg_hash->{'item'}}[0]->{'name'}} != 1 )) {
661 &add_content2xml_hash($out_hash, "error_string", "message needs within the xml-tag 'item' one xml-tags 'name'");
662 &add_content2xml_hash($out_hash, "error", "name");
663 &main::daemon_log("$session_id ERROR: message needs within the xml-tag 'item' one xml-tags 'name': $msg", 1);
664 return ( &create_xml_string($out_hash) );
665 }
666 if ((not exists @{$msg_hash->{'item'}}[0]->{'value'}) || (@{@{$msg_hash->{'item'}}[0]->{'value'}} != 1 )) {
667 &add_content2xml_hash($out_hash, "error_string", "message needs within the xml-tag 'item' one xml-tags 'value'");
668 &add_content2xml_hash($out_hash, "error", "value");
669 &main::daemon_log("$session_id ERROR: message needs within the xml-tag 'item' one xml-tags 'value': $msg", 1);
670 return ( &create_xml_string($out_hash) );
671 }
672 }
673 # if no hostId is given, set_product_properties will act on globally
674 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} > 1)) {
675 &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
676 &add_content2xml_hash($out_hash, "error", "hostId");
677 &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1);
678 return ( &create_xml_string($out_hash) );
679 }
682 # Get productId
683 $productId = @{$msg_hash->{'productId'}}[0];
684 &add_content2xml_hash($out_hash, "productId", $productId);
686 # Get hostId if defined
687 if (exists $msg_hash->{'hostId'}){
688 $hostId = @{$msg_hash->{'hostId'}}[0];
689 &add_content2xml_hash($out_hash, "hostId", $hostId);
690 }
692 # Set product states if requested
693 if (defined @{$msg_hash->{'action'}}[0]){
694 &_set_action($productId, @{$msg_hash->{'action'}}[0], $hostId);
695 }
696 if (defined @{$msg_hash->{'state'}}[0]){
697 &_set_state($productId, @{$msg_hash->{'state'}}[0], $hostId);
698 }
700 # Find properties
701 foreach my $item (@{$msg_hash->{'item'}}){
702 # JSON Query
703 my $callobj;
705 if (defined $hostId){
706 $callobj = {
707 method => 'setProductProperty',
708 params => [ $productId, $item->{'name'}[0], $item->{'value'}[0], $hostId ],
709 id => 1,
710 };
711 } else {
712 $callobj = {
713 method => 'setProductProperty',
714 params => [ $productId, $item->{'name'}[0], $item->{'value'}[0] ],
715 id => 1,
716 };
717 }
719 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
720 my ($res_err, $res_err_string) = &check_opsi_res($res);
722 if ($res_err){
723 &main::daemon_log("$session_id ERROR: communication failed while setting '".$item->{'name'}[0]."': ".$res_err_string, 1);
724 &add_content2xml_hash($out_hash, "error", $res_err_string);
725 }
726 }
729 # Return message
730 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
731 return ( &create_xml_string($out_hash) );
732 }
734 ################################
735 # @brief Reports client hardware inventory.
736 # @param msg - STRING - xml message with tag hostId
737 # @param msg_hash - HASHREF - message information parsed into a hash
738 # @param session_id - INTEGER - POE session id of the processing of this message
739 # @return out_msg - STRING - feedback to GOsa in success and error case
740 sub opsi_get_client_hardware {
741 my $startTime = Time::HiRes::time;
742 my ($msg, $msg_hash, $session_id) = @_;
743 my $header = @{$msg_hash->{'header'}}[0];
744 my $source = @{$msg_hash->{'source'}}[0];
745 my $target = @{$msg_hash->{'target'}}[0];
746 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
747 my $hostId;
748 my $error = 0;
749 my $xml_msg;
751 # Sanity check of needed parameter
752 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
753 $hostId = @{$msg_hash->{'hostId'}}[0];
754 } else {
755 return &_giveErrorFeedback($msg_hash, $_, $session_id);
756 }
759 # Build return message with twisted target and source
760 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
761 if (defined $forward_to_gosa) {
762 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
763 }
764 &add_content2xml_hash($out_hash, "hostId", "$hostId");
765 &add_content2xml_hash($out_hash, "xxx", "");
767 # Move to XML string
768 $xml_msg= &create_xml_string($out_hash);
770 my $res = &_callOpsi(method=>'getHardwareInformation_hash', params=>[ $hostId ]);
771 if (not &check_opsi_res($res)){
772 my $result= $res->result;
773 if (ref $result eq "HASH") {
774 foreach my $r (keys %{$result}){
775 my $item= "\n<item><id>".xml_quote($r)."</id>";
776 my $value= $result->{$r};
777 foreach my $sres (@{$value}){
779 foreach my $dres (keys %{$sres}){
780 if (defined $sres->{$dres}){
781 $item.= "<$dres>".xml_quote($sres->{$dres})."</$dres>";
782 }
783 }
785 }
786 $item.= "</item>";
787 $xml_msg=~ s%<xxx></xxx>%$item<xxx></xxx>%;
789 }
790 }
791 }
793 $xml_msg=~ s/<xxx><\/xxx>//;
795 # Return message
796 my $endTime = Time::HiRes::time;
797 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
798 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
799 return ( $xml_msg );
800 }
802 ################################
803 # @brief Reports all Opsi clients.
804 # @param msg - STRING - xml message
805 # @param msg_hash - HASHREF - message information parsed into a hash
806 # @param session_id - INTEGER - POE session id of the processing of this message
807 # @return out_msg - STRING - feedback to GOsa in success and error case
808 sub opsi_list_clients {
809 my $startTime = Time::HiRes::time;
810 my ($msg, $msg_hash, $session_id) = @_;
811 my $header = @{$msg_hash->{'header'}}[0];
812 my $source = @{$msg_hash->{'source'}}[0];
813 my $target = @{$msg_hash->{'target'}}[0];
814 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
816 # Build return message with twisted target and source
817 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
818 if (defined $forward_to_gosa) {
819 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
820 }
821 &add_content2xml_hash($out_hash, "xxx", "");
823 # Move to XML string
824 my $xml_msg= &create_xml_string($out_hash);
826 # JSON Query
827 my $callobj = {
828 method => 'getClientsInformation_listOfHashes',
829 params => [ ],
830 id => 1,
831 };
833 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
834 if (not &check_opsi_res($res)){
835 foreach my $host (@{$res->result}){
836 my $item= "\n<item><name>".$host->{'hostId'}."</name>";
837 $item.= "<mac>".xml_quote($host->{'macAddress'})."</mac>";
838 if (defined($host->{'description'})){
839 $item.= "<description>".xml_quote($host->{'description'})."</description>";
840 }
841 if (defined($host->{'notes'})){
842 $item.= "<notes>".xml_quote($host->{'notes'})."</notes>";
843 }
844 if (defined($host->{'lastSeen'})){
845 $item.= "<lastSeen>".xml_quote($host->{'lastSeen'})."</lastSeen>";
846 }
848 $item.= "</item>";
849 $xml_msg=~ s%<xxx></xxx>%$item<xxx></xxx>%;
850 }
851 }
852 $xml_msg=~ s/<xxx><\/xxx>//;
854 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
855 return ( $xml_msg );
856 }
858 ################################
859 # @brief Reports client software inventory.
860 # @param msg - STRING - xml message with tag hostId
861 # @param msg_hash - HASHREF - message information parsed into a hash
862 # @param session_id - INTEGER - POE session id of the processing of this message
863 # @return out_msg - STRING - feedback to GOsa in success and error case
864 sub opsi_get_client_software {
865 my $startTime = Time::HiRes::time;
866 my ($msg, $msg_hash, $session_id) = @_;
867 my $header = @{$msg_hash->{'header'}}[0];
868 my $source = @{$msg_hash->{'source'}}[0];
869 my $target = @{$msg_hash->{'target'}}[0];
870 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
871 my $error = 0;
872 my $hostId;
873 my $xml_msg;
875 # Build return message with twisted target and source
876 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
877 if (defined $forward_to_gosa) {
878 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
879 }
881 # Sanity check of needed parameter
882 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
883 $error++;
884 &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
885 &add_content2xml_hash($out_hash, "error", "hostId");
886 &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1);
887 }
889 if (not $error) {
891 # Get hostId
892 $hostId = @{$msg_hash->{'hostId'}}[0];
893 &add_content2xml_hash($out_hash, "hostId", "$hostId");
894 &add_content2xml_hash($out_hash, "xxx", "");
895 }
897 $xml_msg= &create_xml_string($out_hash);
899 if (not $error) {
901 # JSON Query
902 my $callobj = {
903 method => 'getSoftwareInformation_hash',
904 params => [ $hostId ],
905 id => 1,
906 };
908 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
909 if (not &check_opsi_res($res)){
910 my $result= $res->result;
911 }
913 $xml_msg=~ s/<xxx><\/xxx>//;
915 }
917 # Return message
918 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
919 return ( $xml_msg );
920 }
922 ################################
923 # @brief Reports product for given hostId or globally.
924 # @param msg - STRING - xml message with optional tag hostId
925 # @param msg_hash - HASHREF - message information parsed into a hash
926 # @param session_id - INTEGER - POE session id of the processing of this message
927 # @return out_msg - STRING - feedback to GOsa in success and error case
928 sub opsi_get_local_products {
929 my $startTime = Time::HiRes::time;
930 my ($msg, $msg_hash, $session_id) = @_;
931 my $header = @{$msg_hash->{'header'}}[0];
932 my $source = @{$msg_hash->{'source'}}[0];
933 my $target = @{$msg_hash->{'target'}}[0];
934 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
935 my $hostId;
937 # Build return message with twisted target and source
938 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
939 if (defined $forward_to_gosa) {
940 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
941 }
942 &add_content2xml_hash($out_hash, "xxx", "");
944 # Get hostId if defined
945 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1)) {
946 $hostId = @{$msg_hash->{'hostId'}}[0];
947 &add_content2xml_hash($out_hash, "hostId", $hostId);
948 }
950 my $callobj;
952 # Move to XML string
953 my $xml_msg= &create_xml_string($out_hash);
955 # Check if we need to get host or global information
956 if (defined $hostId){
957 $callobj = {
958 method => 'getProductHostInformation_list',
959 params => [ $hostId ],
960 id => 1,
961 };
963 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
964 if (not &check_opsi_res($res)){
965 foreach my $product (@{$res->result}){
966 my $replace= "<item><productId>".xml_quote($product->{'productId'})."<\/productId><name>".xml_quote($product->{'name'})."<\/name><description>".xml_quote($product->{'description'})."<\/description><state>".xml_quote($product->{'installationStatus'})."</state><action>".xml_quote($product->{'actionRequest'})."</action><\/item><xxx><\/xxx>";
967 $xml_msg=~ s/<xxx><\/xxx>/\n$replace/;
968 }
969 }
971 } else {
973 # For hosts, only return the products that are or get installed
974 $callobj = {
975 method => 'getProductInformation_list',
976 params => [ undef, 'localboot' ],
977 id => 1,
978 };
980 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
981 if (not &check_opsi_res($res)){
982 foreach my $product (@{$res->result}) {
983 my $replace= "<item><productId>".xml_quote($product->{'productId'})."<\/productId><name>".xml_quote($product->{'name'})."<\/name><description>".xml_quote($product->{'description'})."<\/description><\/item><xxx><\/xxx>";
984 $xml_msg=~ s/<xxx><\/xxx>/\n$replace/;
985 }
986 }
987 }
989 $xml_msg=~ s/<xxx><\/xxx>//;
991 # Retrun Message
992 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
993 return ( $xml_msg );
994 }
996 ################################
997 # @brief Deletes a client from Opsi.
998 # @param msg - STRING - xml message with tag hostId
999 # @param msg_hash - HASHREF - message information parsed into a hash
1000 # @param session_id - INTEGER - POE session id of the processing of this message
1001 # @return out_msg - STRING - feedback to GOsa in success and error case
1002 sub opsi_del_client {
1003 my $startTime = Time::HiRes::time;
1004 my ($msg, $msg_hash, $session_id) = @_;
1005 my $header = @{$msg_hash->{'header'}}[0];
1006 my $source = @{$msg_hash->{'source'}}[0];
1007 my $target = @{$msg_hash->{'target'}}[0];
1008 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1009 my $hostId;
1010 my $error = 0;
1012 # Build return message with twisted target and source
1013 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1014 if (defined $forward_to_gosa) {
1015 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1016 }
1018 # Sanity check of needed parameter
1019 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
1020 $error++;
1021 &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
1022 &add_content2xml_hash($out_hash, "error", "hostId");
1023 &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1);
1024 }
1026 if (not $error) {
1028 # Get hostId
1029 $hostId = @{$msg_hash->{'hostId'}}[0];
1030 &add_content2xml_hash($out_hash, "hostId", "$hostId");
1032 # JSON Query
1033 my $callobj = {
1034 method => 'deleteClient',
1035 params => [ $hostId ],
1036 id => 1,
1037 };
1038 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1039 }
1041 # Move to XML string
1042 my $xml_msg= &create_xml_string($out_hash);
1044 # Return message
1045 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1046 return ( $xml_msg );
1047 }
1049 ################################
1050 # @brief Set a client in Opsi to install and trigger a wake on lan message (WOL).
1051 # @param msg - STRING - xml message with tags hostId, macaddress
1052 # @param msg_hash - HASHREF - message information parsed into a hash
1053 # @param session_id - INTEGER - POE session id of the processing of this message
1054 # @return out_msg - STRING - feedback to GOsa in success and error case
1055 sub opsi_install_client {
1056 my $startTime = Time::HiRes::time;
1057 my ($msg, $msg_hash, $session_id) = @_;
1058 my $header = @{$msg_hash->{'header'}}[0];
1059 my $source = @{$msg_hash->{'source'}}[0];
1060 my $target = @{$msg_hash->{'target'}}[0];
1061 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1062 my ($hostId, $macaddress);
1063 my $error = 0;
1064 my @out_msg_l;
1066 # Build return message with twisted target and source
1067 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1068 if (defined $forward_to_gosa) {
1069 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1070 }
1072 # Sanity check of needed parameter
1073 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
1074 $error++;
1075 &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
1076 &add_content2xml_hash($out_hash, "error", "hostId");
1077 &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1);
1078 }
1079 if ((not exists $msg_hash->{'macaddress'}) || (@{$msg_hash->{'macaddress'}} != 1) || (@{$msg_hash->{'macaddress'}}[0] eq ref 'HASH') ) {
1080 $error++;
1081 &add_content2xml_hash($out_hash, "error_string", "no macaddress specified or macaddress tag invalid");
1082 &add_content2xml_hash($out_hash, "error", "macaddress");
1083 &main::daemon_log("$session_id ERROR: no macaddress specified or macaddress tag invalid: $msg", 1);
1084 } else {
1085 if ((exists $msg_hash->{'macaddress'}) &&
1086 ($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)) {
1087 $macaddress = $1;
1088 } else {
1089 $error ++;
1090 &add_content2xml_hash($out_hash, "error_string", "given mac address is not correct");
1091 &add_content2xml_hash($out_hash, "error", "macaddress");
1092 &main::daemon_log("$session_id ERROR: given mac address is not correct: $msg", 1);
1093 }
1094 }
1096 if (not $error) {
1098 # Get hostId
1099 $hostId = @{$msg_hash->{'hostId'}}[0];
1100 &add_content2xml_hash($out_hash, "hostId", "$hostId");
1102 # Load all products for this host with status != "not_installed" or actionRequest != "none"
1103 my $callobj = {
1104 method => 'getProductStates_hash',
1105 params => [ $hostId ],
1106 id => 1,
1107 };
1109 my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
1110 if (not &check_opsi_res($hres)){
1111 my $htmp= $hres->result->{$hostId};
1113 # check state != not_installed or action == setup -> load and add
1114 foreach my $product (@{$htmp}){
1115 # Now we've a couple of hashes...
1116 if ($product->{'installationStatus'} ne "not_installed" or
1117 $product->{'actionRequest'} ne "none"){
1119 # Do an action request for all these -> "setup".
1120 $callobj = {
1121 method => 'setProductActionRequest',
1122 params => [ $product->{'productId'}, $hostId, "setup" ],
1123 id => 1,
1124 };
1125 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1126 my ($res_err, $res_err_string) = &check_opsi_res($res);
1127 if ($res_err){
1128 &main::daemon_log("$session_id ERROR: cannot set product action request for '$hostId': ".$product->{'productId'}, 1);
1129 } else {
1130 &main::daemon_log("$session_id INFO: requesting 'setup' for '".$product->{'productId'}."' on $hostId", 1);
1131 }
1132 }
1133 }
1134 }
1135 push(@out_msg_l, &create_xml_string($out_hash));
1138 # Build wakeup message for client
1139 if (not $error) {
1140 my $wakeup_hash = &create_xml_hash("trigger_wake", "GOSA", "KNOWN_SERVER");
1141 &add_content2xml_hash($wakeup_hash, 'macaddress', $macaddress);
1142 my $wakeup_msg = &create_xml_string($wakeup_hash);
1143 push(@out_msg_l, $wakeup_msg);
1145 # invoke trigger wake for this gosa-si-server
1146 &main::server_server_com::trigger_wake($wakeup_msg, $wakeup_hash, $session_id);
1147 }
1148 }
1150 # Return messages
1151 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1152 return @out_msg_l;
1153 }
1155 ################################
1156 # @brief Set action for an Opsi client
1157 # @param product - STRING - Opsi product
1158 # @param action - STRING - action
1159 # @param hostId - STRING - Opsi hostId
1160 sub _set_action {
1161 my $product= shift;
1162 my $action = shift;
1163 my $hostId = shift;
1164 my $callobj;
1166 $callobj = {
1167 method => 'setProductActionRequest',
1168 params => [ $product, $hostId, $action],
1169 id => 1,
1170 };
1172 $main::opsi_client->call($main::opsi_url, $callobj);
1173 }
1175 ################################
1176 # @brief Set state for an Opsi client
1177 # @param product - STRING - Opsi product
1178 # @param action - STRING - state
1179 # @param hostId - STRING - Opsi hostId
1180 sub _set_state {
1181 my $product = shift;
1182 my $state = shift;
1183 my $hostId = shift;
1184 my $callobj;
1186 $callobj = {
1187 method => 'setProductState',
1188 params => [ $product, $hostId, $state ],
1189 id => 1,
1190 };
1192 $main::opsi_client->call($main::opsi_url, $callobj);
1193 }
1195 ################################
1196 # @brief Create a license pool at Opsi server.
1197 # @param licensePoolId The name of the pool (optional).
1198 # @param description The description of the pool (optional).
1199 # @param productIds A list of assigned porducts of the pool (optional).
1200 # @param windowsSoftwareIds A list of windows software IDs associated to the pool (optional).
1201 sub opsi_createLicensePool {
1202 my $startTime = Time::HiRes::time;
1203 my ($msg, $msg_hash, $session_id) = @_;
1204 my $header = @{$msg_hash->{'header'}}[0];
1205 my $source = @{$msg_hash->{'source'}}[0];
1206 my $target = @{$msg_hash->{'target'}}[0];
1207 my $out_hash;
1208 my $licensePoolId = defined $msg_hash->{'licensePoolId'} ? @{$msg_hash->{'licensePoolId'}}[0] : undef;
1209 my $description = defined $msg_hash->{'description'} ? @{$msg_hash->{'description'}}[0] : undef;
1210 my @productIds = defined $msg_hash->{'productIds'} ? $msg_hash->{'productIds'} : undef;
1211 my @windowsSoftwareIds = defined $msg_hash->{'windowsSoftwareIds'} ? $msg_hash->{'windowsSoftwareIds'} : undef;
1213 # Create license Pool
1214 my $callobj = {
1215 method => 'createLicensePool',
1216 params => [ $licensePoolId, $description, @productIds, @windowsSoftwareIds],
1217 id => 1,
1218 };
1219 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1221 # Check Opsi error
1222 my ($res_error, $res_error_str) = &check_opsi_res($res);
1223 if ($res_error){
1224 # Create error message
1225 &main::daemon_log("$session_id ERROR: cannot create license pool at Opsi server: ".$res_error_str, 1);
1226 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1227 return ( &create_xml_string($out_hash) );
1228 }
1230 # Create function result message
1231 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source, $res->result);
1232 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1234 my $endTime = Time::HiRes::time;
1235 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1236 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1237 return ( &create_xml_string($out_hash) );
1238 }
1240 ################################
1241 # @brief Return licensePoolId, description, productIds and windowsSoftwareIds for all found license pools.
1242 sub opsi_getLicensePools_listOfHashes {
1243 my $startTime = Time::HiRes::time;
1244 my ($msg, $msg_hash, $session_id) = @_;
1245 my $header = @{$msg_hash->{'header'}}[0];
1246 my $source = @{$msg_hash->{'source'}}[0];
1247 my $out_hash;
1249 # Fetch infos from Opsi server
1250 my $callobj = {
1251 method => 'getLicensePools_listOfHashes',
1252 params => [ ],
1253 id => 1,
1254 };
1255 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1257 # Check Opsi error
1258 my ($res_error, $res_error_str) = &check_opsi_res($res);
1259 if ($res_error){
1260 # Create error message
1261 &main::daemon_log("$session_id ERROR: cannot get license pool ID list from Opsi server: ".$res_error_str, 1);
1262 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1263 return ( &create_xml_string($out_hash) );
1264 }
1266 # Create function result message
1267 my $res_hash = { 'hit'=> [] };
1268 foreach my $licensePool ( @{$res->result}) {
1269 my $licensePool_hash = { 'licensePoolId' => [$licensePool->{'licensePoolId'}],
1270 'description' => [$licensePool->{'description'}],
1271 'productIds' => $licensePool->{'productIds'},
1272 'windowsSoftwareIds' => $licensePool->{'windowsSoftwareIds'},
1273 };
1274 push( @{$res_hash->{hit}}, $licensePool_hash );
1275 }
1277 # Create function result message
1278 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1279 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1280 $out_hash->{result} = [$res_hash];
1282 my $endTime = Time::HiRes::time;
1283 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1284 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1285 return ( &create_xml_string($out_hash) );
1286 }
1288 ################################
1289 # @brief Return productIds, windowsSoftwareIds and description for a given licensePoolId
1290 # @param licensePoolId The name of the pool.
1291 sub opsi_getLicensePool_hash {
1292 my $startTime = Time::HiRes::time;
1293 my ($msg, $msg_hash, $session_id) = @_;
1294 my $header = @{$msg_hash->{'header'}}[0];
1295 my $source = @{$msg_hash->{'source'}}[0];
1296 my $target = @{$msg_hash->{'target'}}[0];
1297 my $licensePoolId;
1298 my $out_hash;
1300 # Check input sanity
1301 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1302 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1303 } else {
1304 return &_giveErrorFeedback($msg_hash, "", $session_id, $_);
1305 }
1307 # Fetch infos from Opsi server
1308 my $callobj = {
1309 method => 'getLicensePool_hash',
1310 params => [ $licensePoolId ],
1311 id => 1,
1312 };
1313 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1315 # Check Opsi error
1316 my ($res_error, $res_error_str) = &check_opsi_res($res);
1317 if ($res_error){
1318 # Create error message
1319 &main::daemon_log("$session_id ERROR: cannot get license pool from Opsi server: ".$res_error_str, 1);
1320 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source);
1321 &add_content2xml_hash($out_hash, "error", $res_error_str);
1322 return ( &create_xml_string($out_hash) );
1323 }
1325 # Create function result message
1326 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1327 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1328 &add_content2xml_hash($out_hash, "licensePoolId", $res->result->{'licensePoolId'});
1329 &add_content2xml_hash($out_hash, "description", $res->result->{'description'});
1330 map(&add_content2xml_hash($out_hash, "productIds", "$_"), @{ $res->result->{'productIds'} });
1331 map(&add_content2xml_hash($out_hash, "windowsSoftwareIds", "$_"), @{ $res->result->{'windowsSoftwareIds'} });
1333 my $endTime = Time::HiRes::time;
1334 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1335 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1336 return ( &create_xml_string($out_hash) );
1337 }
1339 sub _parse_getSoftwareLicenseUsages {
1340 my $res = shift;
1342 # Parse Opsi result
1343 my $tmp_licensePool_cache = {};
1344 my $res_hash = { 'hit'=> [] };
1345 foreach my $license ( @{$res}) {
1346 my $tmp_licensePool = $license->{'licensePoolId'};
1347 if (not exists $tmp_licensePool_cache->{$tmp_licensePool}) {
1348 # Fetch missing informations from Opsi and cache the results for a possible later usage
1349 my ($res, $err) = &_getLicensePool_hash('licensePoolId'=>$tmp_licensePool);
1350 if (not $err) {
1351 $tmp_licensePool_cache->{$tmp_licensePool} = $res;
1352 }
1353 }
1354 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
1355 'notes' => [$license->{'notes'}],
1356 'licenseKey' => [$license->{'licenseKey'}],
1357 'hostId' => [$license->{'hostId'}],
1358 'licensePoolId' => [$tmp_licensePool],
1359 };
1360 if (exists $tmp_licensePool_cache->{$tmp_licensePool}) {
1361 $license_hash->{$tmp_licensePool} = {'productIds'=>[], 'windowsSoftwareIds'=>[]};
1362 map (push (@{$license_hash->{$tmp_licensePool}->{productIds}}, $_), @{$tmp_licensePool_cache->{$tmp_licensePool}->{productIds}});
1363 map (push (@{$license_hash->{$tmp_licensePool}->{windowsSoftwareIds}}, $_), @{$tmp_licensePool_cache->{$tmp_licensePool}->{windowsSoftwareIds}});
1364 }
1365 push( @{$res_hash->{hit}}, $license_hash );
1366 }
1368 return $res_hash;
1369 }
1371 ################################
1372 # @brief Returns softwareLicenseId, notes, licenseKey, hostId and licensePoolId for optional given licensePoolId and hostId
1373 # @param hostid Something like client_1.intranet.mydomain.de (optional).
1374 # @param licensePoolId The name of the pool (optional).
1375 sub opsi_getSoftwareLicenseUsages {
1376 my $startTime = Time::HiRes::time;
1377 my ($msg, $msg_hash, $session_id) = @_;
1378 my $header = @{$msg_hash->{'header'}}[0];
1379 my $source = @{$msg_hash->{'source'}}[0];
1380 my $target = @{$msg_hash->{'target'}}[0];
1381 my $licensePoolId = defined $msg_hash->{'licensePoolId'} ? @{$msg_hash->{'licensePoolId'}}[0] : undef;
1382 my $hostId = defined $msg_hash->{'hostId'} ? @{$msg_hash->{'hostId'}}[0] : undef;
1383 my $out_hash;
1385 my ($res, $err) = &_getSoftwareLicenseUsages_listOfHashes('licensePoolId'=>$licensePoolId, 'hostId'=>$hostId);
1386 if ($err){
1387 return &_giveErrorFeedback($msg_hash, "cannot fetch software licenses from license pool : ".$res, $session_id);
1388 }
1390 # Parse Opsi result
1391 my $res_hash = &_parse_getSoftwareLicenseUsages($res);
1393 # Create function result message
1394 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1395 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1396 $out_hash->{result} = [$res_hash];
1398 my $endTime = Time::HiRes::time;
1399 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1400 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1401 return ( &create_xml_string($out_hash) );
1402 }
1404 ################################
1405 # @brief Returns softwareLicenseId, notes, licenseKey, hostId and licensePoolId. Function return is identical to opsi_getSoftwareLicenseUsages
1406 # @param productId Something like 'firefox', 'python' or anything else .
1407 sub opsi_getSoftwareLicenseUsagesForProductId {
1408 my $startTime = Time::HiRes::time;
1409 my ($msg, $msg_hash, $session_id) = @_;
1410 my $header = @{$msg_hash->{'header'}}[0];
1411 my $source = @{$msg_hash->{'source'}}[0];
1413 # Check input sanity
1414 my $productId;
1415 if (&_check_xml_tag_is_ok ($msg_hash, 'productId')) {
1416 $productId= @{$msg_hash->{'productId'}}[0];
1417 } else {
1418 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1419 }
1421 # Fetch licensePoolId for productId
1422 my ($res, $err) = &_getLicensePoolId('productId'=>$productId);
1423 if ($err){
1424 return &_giveErrorFeedback($msg_hash, "cannot fetch licensePoolId for given productId : ".$res, $session_id);
1425 }
1426 my $licensePoolId = $res; # We assume that there is only one pool for each productID!!!
1428 # Fetch softwareLiceceUsages for licensePoolId
1429 ($res, $err) = &_getSoftwareLicenseUsages_listOfHashes('licensePoolId'=>$licensePoolId);
1430 if ($err){
1431 return &_giveErrorFeedback($msg_hash, "cannot fetch software licenses from license pool : ".$res, $session_id);
1432 }
1433 # Parse Opsi result
1434 my $res_hash = &_parse_getSoftwareLicenseUsages($res);
1436 # Create function result message
1437 my $out_hash = &create_xml_hash("answer_$header", $main::server_address, $source);
1438 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1439 $out_hash->{result} = [$res_hash];
1441 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1442 return ( &create_xml_string($out_hash) );
1443 }
1445 ################################
1446 # @brief Returns expirationDate, boundToHost, maxInstallation, licenseTyp, licensePoolIds and licenseKeys for a given softwareLicense ID.
1447 # @param softwareLicenseId Identificator of a license.
1448 sub opsi_getSoftwareLicense_hash {
1449 my $startTime = Time::HiRes::time;
1450 my ($msg, $msg_hash, $session_id) = @_;
1451 my $header = @{$msg_hash->{'header'}}[0];
1452 my $source = @{$msg_hash->{'source'}}[0];
1453 my $target = @{$msg_hash->{'target'}}[0];
1454 my $softwareLicenseId;
1455 my $out_hash;
1457 # Check input sanity
1458 if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
1459 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
1460 } else {
1461 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1462 }
1464 my $callobj = {
1465 method => 'getSoftwareLicense_hash',
1466 params => [ $softwareLicenseId ],
1467 id => 1,
1468 };
1469 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1471 # Check Opsi error
1472 my ($res_error, $res_error_str) = &check_opsi_res($res);
1473 if ($res_error){
1474 # Create error message
1475 &main::daemon_log("$session_id ERROR: cannot fetch information for license '$softwareLicenseId': ".$res_error_str, 1);
1476 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1477 return ( &create_xml_string($out_hash) );
1478 }
1480 # Create function result message
1481 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1482 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1483 &add_content2xml_hash($out_hash, "expirationDate", $res->result->{'expirationDate'});
1484 &add_content2xml_hash($out_hash, "boundToHost", $res->result->{'boundToHost'});
1485 &add_content2xml_hash($out_hash, "maxInstallations", $res->result->{'maxInstallations'});
1486 &add_content2xml_hash($out_hash, "licenseTyp", $res->result->{'licenseTyp'});
1487 foreach my $licensePoolId ( @{$res->result->{'licensePoolIds'}}) {
1488 &add_content2xml_hash($out_hash, "licensePoolId", $licensePoolId);
1489 &add_content2xml_hash($out_hash, $licensePoolId, $res->result->{'licenseKeys'}->{$licensePoolId});
1490 }
1492 my $endTime = Time::HiRes::time;
1493 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1494 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1495 return ( &create_xml_string($out_hash) );
1496 }
1498 ################################
1499 # @brief Delete licnese pool by license pool ID. A pool can only be deleted if there are no software licenses bound to the pool.
1500 # The fixed parameter deleteLicenses=True specifies that all software licenses bound to the pool are being deleted.
1501 # @param licensePoolId The name of the pool.
1502 sub opsi_deleteLicensePool {
1503 my $startTime = Time::HiRes::time;
1504 my ($msg, $msg_hash, $session_id) = @_;
1505 my $header = @{$msg_hash->{'header'}}[0];
1506 my $source = @{$msg_hash->{'source'}}[0];
1507 my $target = @{$msg_hash->{'target'}}[0];
1508 my $licensePoolId;
1509 my $out_hash;
1511 # Check input sanity
1512 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1513 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1514 } else {
1515 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1516 }
1518 # Fetch softwareLicenseIds used in license pool
1519 # This has to be done because function deleteLicensePool deletes the pool and the corresponding software licenses
1520 # but not the license contracts of the software licenses. In our case each software license has exactly one license contract.
1521 my $callobj = {
1522 method => 'getSoftwareLicenses_listOfHashes',
1523 params => [ ],
1524 id => 1,
1525 };
1526 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1528 # Keep list of licenseContractIds in mind to delete it after the deletion of the software licenses
1529 my @lCI_toBeDeleted;
1530 foreach my $softwareLicenseHash ( @{$res->result} ) {
1531 if ((@{$softwareLicenseHash->{'licensePoolIds'}} == 0) || (@{$softwareLicenseHash->{'licensePoolIds'}}[0] ne $licensePoolId)) {
1532 next;
1533 }
1534 push (@lCI_toBeDeleted, $softwareLicenseHash->{'licenseContractId'});
1535 }
1537 # Delete license pool at Opsi server
1538 $callobj = {
1539 method => 'deleteLicensePool',
1540 params => [ $licensePoolId, 'deleteLicenses=True' ],
1541 id => 1,
1542 };
1543 $res = $main::opsi_client->call($main::opsi_url, $callobj);
1544 my ($res_error, $res_error_str) = &check_opsi_res($res);
1545 if ($res_error){
1546 # Create error message
1547 &main::daemon_log("$session_id ERROR: cannot delete license pool at Opsi server: ".$res_error_str, 1);
1548 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1549 return ( &create_xml_string($out_hash) );
1550 }
1552 # Delete each license contract connected with the license pool
1553 foreach my $licenseContractId ( @lCI_toBeDeleted ) {
1554 my $callobj = {
1555 method => 'deleteLicenseContract',
1556 params => [ $licenseContractId ],
1557 id => 1,
1558 };
1559 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1560 my ($res_error, $res_error_str) = &check_opsi_res($res);
1561 if ($res_error){
1562 # Create error message
1563 &main::daemon_log("$session_id ERROR: cannot delete license contract '$licenseContractId' connected with license pool '$licensePoolId' at Opsi server: ".$res_error_str, 1);
1564 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1565 return ( &create_xml_string($out_hash) );
1566 }
1567 }
1569 # Create function result message
1570 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1571 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1573 my $endTime = Time::HiRes::time;
1574 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1575 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1576 return ( &create_xml_string($out_hash) );
1577 }
1579 ################################
1580 # @brief Create a license contract, create a software license and add the software license to the license pool
1581 # @param licensePoolId The name of the pool the license should be assigned.
1582 # @param licenseKey The license key.
1583 # @param partner Name of the license partner (optional).
1584 # @param conclusionDate Date of conclusion of license contract (optional)
1585 # @param notificationDate Date of notification that license is running out soon (optional).
1586 # @param notes This is the place for some notes (optional)
1587 # @param softwareLicenseId Identificator of a license (optional).
1588 # @param licenseTyp Typ of a licnese, either "OEM", "VOLUME" or "RETAIL" (optional).
1589 # @param maxInstallations The number of clients use this license (optional).
1590 # @param boundToHost The name of the client the license is bound to (optional).
1591 # @param expirationDate The date when the license is running down (optional).
1592 sub opsi_createLicense {
1593 my $startTime = Time::HiRes::time;
1594 my ($msg, $msg_hash, $session_id) = @_;
1595 my $header = @{$msg_hash->{'header'}}[0];
1596 my $source = @{$msg_hash->{'source'}}[0];
1597 my $target = @{$msg_hash->{'target'}}[0];
1598 my $partner = defined $msg_hash->{'partner'} ? @{$msg_hash->{'partner'}}[0] : undef;
1599 my $conclusionDate = defined $msg_hash->{'conclusionDate'} ? @{$msg_hash->{'conclusionDate'}}[0] : undef;
1600 my $notificationDate = defined $msg_hash->{'notificationDate'} ? @{$msg_hash->{'notificationDate'}}[0] : undef;
1601 my $notes = defined $msg_hash->{'notes'} ? @{$msg_hash->{'notes'}}[0] : undef;
1602 my $licenseContractId = undef;
1603 my $softwareLicenseId = defined $msg_hash->{'softwareLicenseId'} ? @{$msg_hash->{'softwareLicenseId'}}[0] : undef;
1604 my $licenseType = defined $msg_hash->{'licenseType'} ? @{$msg_hash->{'licenseType'}}[0] : undef;
1605 my $maxInstallations = defined $msg_hash->{'maxInstallations'} ? @{$msg_hash->{'maxInstallations'}}[0] : undef;
1606 my $boundToHost = defined $msg_hash->{'boundToHost'} ? @{$msg_hash->{'boundToHost'}}[0] : undef;
1607 my $expirationDate = defined $msg_hash->{'expirationDate'} ? @{$msg_hash->{'expirationDate'}}[0] : undef;
1608 my $licensePoolId;
1609 my $licenseKey;
1610 my $out_hash;
1612 # Check input sanity
1613 if (&_check_xml_tag_is_ok ($msg_hash, 'licenseKey')) {
1614 $licenseKey = @{$msg_hash->{'licenseKey'}}[0];
1615 } else {
1616 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1617 }
1618 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1619 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1620 } else {
1621 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1622 }
1623 if ((defined $licenseType) && (not exists $licenseTyp_hash->{$licenseType})) {
1624 return &_giveErrorFeedback($msg_hash, "The typ of a license can be either 'OEM', 'VOLUME' or 'RETAIL'.", $session_id);
1625 }
1627 # Automatically define licenseContractId if ID is not given
1628 if (defined $softwareLicenseId) {
1629 $licenseContractId = "c_".$softwareLicenseId;
1630 }
1632 # Create license contract at Opsi server
1633 my $callobj = {
1634 method => 'createLicenseContract',
1635 params => [ $licenseContractId, $partner, $conclusionDate, $notificationDate, undef, $notes ],
1636 id => 1,
1637 };
1638 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1640 # Check Opsi error
1641 my ($res_error, $res_error_str) = &check_opsi_res($res);
1642 if ($res_error){
1643 # Create error message
1644 &main::daemon_log("$session_id ERROR: cannot create license contract at Opsi server: ".$res_error_str, 1);
1645 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1646 return ( &create_xml_string($out_hash) );
1647 }
1649 $licenseContractId = $res->result;
1651 # Create software license at Opsi server
1652 $callobj = {
1653 method => 'createSoftwareLicense',
1654 params => [ $softwareLicenseId, $licenseContractId, $licenseType, $maxInstallations, $boundToHost, $expirationDate ],
1655 id => 1,
1656 };
1657 $res = $main::opsi_client->call($main::opsi_url, $callobj);
1659 # Check Opsi error
1660 ($res_error, $res_error_str) = &check_opsi_res($res);
1661 if ($res_error){
1662 # Create error message
1663 &main::daemon_log("$session_id ERROR: cannot create software license at Opsi server: ".$res_error_str, 1);
1664 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1665 return ( &create_xml_string($out_hash) );
1666 }
1668 $softwareLicenseId = $res->result;
1670 # Add software license to license pool
1671 $callobj = {
1672 method => 'addSoftwareLicenseToLicensePool',
1673 params => [ $softwareLicenseId, $licensePoolId, $licenseKey ],
1674 id => 1,
1675 };
1676 $res = $main::opsi_client->call($main::opsi_url, $callobj);
1678 # Check Opsi error
1679 ($res_error, $res_error_str) = &check_opsi_res($res);
1680 if ($res_error){
1681 # Create error message
1682 &main::daemon_log("$session_id ERROR: cannot add software license to license pool at Opsi server: ".$res_error_str, 1);
1683 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1684 return ( &create_xml_string($out_hash) );
1685 }
1687 # Create function result message
1688 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1689 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1691 my $endTime = Time::HiRes::time;
1692 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1693 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1694 return ( &create_xml_string($out_hash) );
1695 }
1697 ################################
1698 # @brief Assign a software license to a host
1699 # @param hostid Something like client_1.intranet.mydomain.de
1700 # @param licensePoolId The name of the pool.
1701 sub opsi_assignSoftwareLicenseToHost {
1702 my $startTime = Time::HiRes::time;
1703 my ($msg, $msg_hash, $session_id) = @_;
1704 my $header = @{$msg_hash->{'header'}}[0];
1705 my $source = @{$msg_hash->{'source'}}[0];
1706 my $target = @{$msg_hash->{'target'}}[0];
1707 my $hostId;
1708 my $licensePoolId;
1710 # Check input sanity
1711 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1712 $hostId = @{$msg_hash->{'hostId'}}[0];
1713 } else {
1714 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1715 }
1716 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1717 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1718 } else {
1719 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1720 }
1722 # Assign a software license to a host
1723 my $callobj = {
1724 method => 'getAndAssignSoftwareLicenseKey',
1725 params => [ $hostId, $licensePoolId ],
1726 id => 1,
1727 };
1728 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1730 # Check Opsi error
1731 my ($res_error, $res_error_str) = &check_opsi_res($res);
1732 if ($res_error){
1733 # Create error message
1734 &main::daemon_log("$session_id ERROR: cannot assign a software license to a host at Opsi server: ".$res_error_str, 1);
1735 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1736 return ( &create_xml_string($out_hash) );
1737 }
1739 # Create function result message
1740 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1741 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1743 my $endTime = Time::HiRes::time;
1744 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1745 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1746 return ( &create_xml_string($out_hash) );
1747 }
1749 ################################
1750 # @brief Unassign a software license from a host.
1751 # @param hostid Something like client_1.intranet.mydomain.de
1752 # @param licensePoolId The name of the pool.
1753 sub opsi_unassignSoftwareLicenseFromHost {
1754 my $startTime = Time::HiRes::time;
1755 my ($msg, $msg_hash, $session_id) = @_;
1756 my $header = @{$msg_hash->{'header'}}[0];
1757 my $source = @{$msg_hash->{'source'}}[0];
1758 my $target = @{$msg_hash->{'target'}}[0];
1759 my $hostId;
1760 my $licensePoolId;
1762 # Check input sanity
1763 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1764 $hostId = @{$msg_hash->{'hostId'}}[0];
1765 } else {
1766 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1767 }
1768 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1769 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1770 } else {
1771 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1772 }
1774 # Unassign a software license from a host
1775 my $callobj = {
1776 method => 'deleteSoftwareLicenseUsage',
1777 params => [ $hostId, '', $licensePoolId ],
1778 id => 1,
1779 };
1780 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1782 # Check Opsi error
1783 my ($res_error, $res_error_str) = &check_opsi_res($res);
1784 if ($res_error){
1785 # Create error message
1786 &main::daemon_log("$session_id ERROR: cannot unassign a software license from a host at Opsi server: ".$res_error_str, 1);
1787 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1788 return ( &create_xml_string($out_hash) );
1789 }
1791 # Create function result message
1792 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1793 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1795 my $endTime = Time::HiRes::time;
1796 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1797 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1798 return ( &create_xml_string($out_hash) );
1799 }
1801 ################################
1802 # @brief Unassign all software licenses from a host
1803 # @param hostid Something like client_1.intranet.mydomain.de
1804 sub opsi_unassignAllSoftwareLicensesFromHost {
1805 my $startTime = Time::HiRes::time;
1806 my ($msg, $msg_hash, $session_id) = @_;
1807 my $header = @{$msg_hash->{'header'}}[0];
1808 my $source = @{$msg_hash->{'source'}}[0];
1809 my $target = @{$msg_hash->{'target'}}[0];
1810 my $hostId;
1812 # Check input sanity
1813 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1814 $hostId = @{$msg_hash->{'hostId'}}[0];
1815 } else {
1816 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1817 }
1819 # Unassign all software licenses from a host
1820 my $callobj = {
1821 method => 'deleteAllSoftwareLicenseUsages',
1822 params => [ $hostId ],
1823 id => 1,
1824 };
1825 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1827 # Check Opsi error
1828 my ($res_error, $res_error_str) = &check_opsi_res($res);
1829 if ($res_error){
1830 # Create error message
1831 &main::daemon_log("$session_id ERROR: cannot unassign a software license from a host at Opsi server: ".$res_error_str, 1);
1832 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1833 return ( &create_xml_string($out_hash) );
1834 }
1836 # Create function result message
1837 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1838 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1840 my $endTime = Time::HiRes::time;
1841 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1842 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1843 return ( &create_xml_string($out_hash) );
1844 }
1847 ################################
1848 # @brief Returns the assigned licensePoolId and licenses, how often the product is installed and at which host
1849 # and the number of max and remaining installations for a given OPSI product.
1850 # @param productId Identificator of an OPSI product.
1851 sub opsi_getLicenseInformationForProduct {
1852 my $startTime = Time::HiRes::time;
1853 my ($msg, $msg_hash, $session_id) = @_;
1854 my $header = @{$msg_hash->{'header'}}[0];
1855 my $source = @{$msg_hash->{'source'}}[0];
1856 my $productId;
1857 my $out_hash;
1859 # Check input sanity
1860 if (&_check_xml_tag_is_ok ($msg_hash, 'productId')) {
1861 $productId = @{$msg_hash->{'productId'}}[0];
1862 } else {
1863 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1864 }
1866 # Fetch infos from Opsi server
1867 my $callobj = {
1868 method => 'getLicensePoolId',
1869 params => [ $productId ],
1870 id => 1,
1871 };
1872 #my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1873 my $res = $opsi_client->call($opsi_url, $callobj);
1875 # Check Opsi error
1876 my ($res_error, $res_error_str) = &check_opsi_res($res);
1877 if ($res_error){
1878 return &_giveErrorFeedback($msg_hash, "cannot get license pool for product '$productId' : ".$res_error_str, $session_id);
1879 }
1881 my $licensePoolId = $res->result;
1883 # Fetch statistic information for given pool ID
1884 $callobj = {
1885 method => 'getLicenseStatistics_hash',
1886 params => [ ],
1887 id => 1,
1888 };
1889 $res = $opsi_client->call($opsi_url, $callobj);
1891 # Check Opsi error
1892 ($res_error, $res_error_str) = &check_opsi_res($res);
1893 if ($res_error){
1894 # Create error message
1895 &main::daemon_log("$session_id ERROR: cannot get statistic informations for license pools : ".$res_error_str, 1);
1896 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1897 return ( &create_xml_string($out_hash) );
1898 }
1900 # Create function result message
1901 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1902 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1903 &add_content2xml_hash($out_hash, "licensePoolId", $licensePoolId);
1904 &add_content2xml_hash($out_hash, "licenses", $res->result->{$licensePoolId}->{'licenses'});
1905 &add_content2xml_hash($out_hash, "usageCount", $res->result->{$licensePoolId}->{'usageCount'});
1906 &add_content2xml_hash($out_hash, "maxInstallations", $res->result->{$licensePoolId}->{'maxInstallations'});
1907 &add_content2xml_hash($out_hash, "remainingInstallations", $res->result->{$licensePoolId}->{'remainingInstallations'});
1908 map(&add_content2xml_hash($out_hash, "usedBy", "$_"), @{ $res->result->{$licensePoolId}->{'usedBy'}});
1910 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1911 return ( &create_xml_string($out_hash) );
1912 }
1915 ################################
1916 # @brief Returns licensePoolId, description, a list of productIds, al list of windowsSoftwareIds and a list of licenses for a given licensePoolId.
1917 # Each license contains softwareLicenseId, maxInstallations, licenseType, licensePoolIds, licenseKeys, hostIds, expirationDate, boundToHost and licenseContractId.
1918 # The licenseContract contains conclusionDate, expirationDate, notes, notificationDate and partner.
1919 # @param licensePoolId The name of the pool.
1920 sub opsi_getPool {
1921 my $startTime = Time::HiRes::time;
1922 my ($msg, $msg_hash, $session_id) = @_;
1923 my $header = @{$msg_hash->{'header'}}[0];
1924 my $source = @{$msg_hash->{'source'}}[0];
1926 # Check input sanity
1927 my $licensePoolId;
1928 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1929 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1930 } else {
1931 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1932 }
1934 # Create hash for the answer
1935 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1936 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1938 # Call Opsi
1939 my ($res, $err) = &_getLicensePool_hash( 'licensePoolId'=> $licensePoolId );
1940 if ($err){
1941 return &_giveErrorFeedback($msg_hash, "cannot get license pool from Opsi server: ".$res, $session_id);
1942 }
1943 # Add data to outgoing hash
1944 &add_content2xml_hash($out_hash, "licensePoolId", $res->{'licensePoolId'});
1945 &add_content2xml_hash($out_hash, "description", $res->{'description'});
1946 map(&add_content2xml_hash($out_hash, "productIds", "$_"), @{ $res->{'productIds'} });
1947 map(&add_content2xml_hash($out_hash, "windowsSoftwareIds", "$_"), @{ $res->{'windowsSoftwareIds'} });
1950 # Call Opsi two times
1951 my ($usages_res, $usages_err) = &_getSoftwareLicenseUsages_listOfHashes('licensePoolId'=>$licensePoolId);
1952 if ($usages_err){
1953 return &_giveErrorFeedback($msg_hash, "cannot get software license usage information from Opsi server: ".$usages_res, $session_id);
1954 }
1955 my ($licenses_res, $licenses_err) = &_getSoftwareLicenses_listOfHashes();
1956 if ($licenses_err){
1957 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server: ".$licenses_res, $session_id);
1958 }
1960 # Add data to outgoing hash
1961 # Parse through all software licenses and select those associated to the pool
1962 my $res_hash = { 'hit'=> [] };
1963 foreach my $license ( @$licenses_res) {
1964 # Each license hash has a list of licensePoolIds so go through this list and search for matching licensePoolIds
1965 my $found = 0;
1966 my @licensePoolIds_list = @{$license->{licensePoolIds}};
1967 foreach my $lPI ( @licensePoolIds_list) {
1968 if ($lPI eq $licensePoolId) { $found++ }
1969 }
1970 if (not $found ) { next; };
1971 # Found matching licensePoolId
1972 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
1973 'licenseKeys' => {},
1974 'expirationDate' => [$license->{'expirationDate'}],
1975 'boundToHost' => [$license->{'boundToHost'}],
1976 'maxInstallations' => [$license->{'maxInstallations'}],
1977 'licenseType' => [$license->{'licenseType'}],
1978 'licenseContractId' => [$license->{'licenseContractId'}],
1979 'licensePoolIds' => [],
1980 'hostIds' => [],
1981 };
1982 foreach my $licensePoolId (@{ $license->{'licensePoolIds'}}) {
1983 push( @{$license_hash->{'licensePoolIds'}}, $licensePoolId);
1984 $license_hash->{licenseKeys}->{$licensePoolId} = [ $license->{'licenseKeys'}->{$licensePoolId} ];
1985 }
1986 foreach my $usage (@$usages_res) {
1987 # Search for hostIds with matching softwareLicenseId
1988 if ($license->{'softwareLicenseId'} eq $usage->{'softwareLicenseId'}) {
1989 push( @{ $license_hash->{hostIds}}, $usage->{hostId});
1990 }
1991 }
1993 # Each softwareLicenseId has one licenseContractId, fetch contract details for each licenseContractId
1994 my ($lContract_res, $lContract_err) = &_getLicenseContract_hash('licenseContractId'=>$license->{licenseContractId});
1995 if ($lContract_err){
1996 return &_giveErrorFeedback($msg_hash, "cannot get software license contract information from Opsi server: ".$licenses_res, $session_id);
1997 }
1998 $license_hash->{$license->{'licenseContractId'}} = [];
1999 my $licenseContract_hash = { 'conclusionDate' => [$lContract_res->{conclusionDate}],
2000 'notificationDate' => [$lContract_res->{notificationDate}],
2001 'notes' => [$lContract_res->{notes}],
2002 'exirationDate' => [$lContract_res->{expirationDate}],
2003 'partner' => [$lContract_res->{partner}],
2004 };
2005 push( @{$license_hash->{licenseContractData}}, $licenseContract_hash );
2007 push( @{$res_hash->{hit}}, $license_hash );
2008 }
2009 $out_hash->{licenses} = [$res_hash];
2011 my $endTime = Time::HiRes::time;
2012 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2013 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2014 return ( &create_xml_string($out_hash) );
2015 }
2018 ################################
2019 # @brief Removes at first the software license from license pool and than deletes the software license.
2020 # Attention, the software license has to exists otherwise it will lead to an Opsi internal server error.
2021 # @param softwareLicenseId Identificator of a license.
2022 # @param licensePoolId The name of the pool.
2023 sub opsi_removeLicense {
2024 my $startTime = Time::HiRes::time;
2025 my ($msg, $msg_hash, $session_id) = @_;
2026 my $header = @{$msg_hash->{'header'}}[0];
2027 my $source = @{$msg_hash->{'source'}}[0];
2029 # Check input sanity
2030 my $softwareLicenseId;
2031 if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
2032 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
2033 } else {
2034 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2035 }
2036 my $licensePoolId;
2037 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
2038 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
2039 } else {
2040 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2041 }
2043 # Call Opsi
2044 my ($res, $err) = &_removeSoftwareLicenseFromLicensePool( 'licensePoolId' => $licensePoolId, 'softwareLicenseId' => $softwareLicenseId );
2045 if ($err){
2046 return &_giveErrorFeedback($msg_hash, "cannot delete software license from pool: ".$res, $session_id);
2047 }
2049 # Call Opsi
2050 ($res, $err) = &_deleteSoftwareLicense( 'softwareLicenseId'=>$softwareLicenseId );
2051 if ($err){
2052 return &_giveErrorFeedback($msg_hash, "cannot delete software license from Opsi server: ".$res, $session_id);
2053 }
2055 # Create hash for the answer
2056 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2057 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2058 my $endTime = Time::HiRes::time;
2059 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2060 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2061 return ( &create_xml_string($out_hash) );
2062 }
2065 ################################
2066 # @brief Return softwareLicenseId, maxInstallations, licenseType, licensePoolIds, licenseContractId, expirationDate, boundToHost and a list of productIds.
2067 # @param hostId Something like client_1.intranet.mydomain.de
2068 sub opsi_getReservedLicenses {
2069 my $startTime = Time::HiRes::time;
2070 my ($msg, $msg_hash, $session_id) = @_;
2071 my $header = @{$msg_hash->{'header'}}[0];
2072 my $source = @{$msg_hash->{'source'}}[0];
2074 # Check input sanity
2075 my $hostId;
2076 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
2077 $hostId = @{$msg_hash->{'hostId'}}[0];
2078 } else {
2079 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2080 }
2082 # Fetch informations from Opsi server
2083 my ($license_res, $license_err) = &_getSoftwareLicenses_listOfHashes();
2084 if ($license_err){
2085 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server: ".$license_res, $session_id);
2086 }
2088 # Parse result
2089 my $res_hash = { 'hit'=> [] };
2090 foreach my $license ( @$license_res) {
2091 if ($license->{boundToHost} ne $hostId) { next; }
2093 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
2094 'maxInstallations' => [$license->{'maxInstallations'}],
2095 'boundToHost' => [$license->{'boundToHost'}],
2096 'expirationDate' => [$license->{'expirationDate'}],
2097 'licenseContractId' => [$license->{'licenseContractId'}],
2098 'licenseType' => [$license->{'licenseType'}],
2099 'licensePoolIds' => [],
2100 };
2102 foreach my $licensePoolId (@{$license->{'licensePoolIds'}}) {
2103 # Fetch information for license pools containing a software license which is bound to given host
2104 my ($pool_res, $pool_err) = &_getLicensePool_hash( 'licensePoolId'=>$licensePoolId );
2105 if ($pool_err){
2106 return &_giveErrorFeedback($msg_hash, "cannot get license pool from Opsi server: ".$pool_res, $session_id);
2107 }
2109 # Add licensePool information to result hash
2110 push (@{$license_hash->{licensePoolIds}}, $licensePoolId);
2111 $license_hash->{$licensePoolId} = {'productIds'=>[], 'windowsSoftwareIds'=>[]};
2112 map (push (@{$license_hash->{$licensePoolId}->{productIds}}, $_), @{$pool_res->{productIds}});
2113 map (push (@{$license_hash->{$licensePoolId}->{windowsSoftwareIds}}, $_), @{$pool_res->{windowsSoftwareIds}});
2114 }
2115 push( @{$res_hash->{hit}}, $license_hash );
2116 }
2117 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2118 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2119 $out_hash->{licenses} = [$res_hash];
2121 my $endTime = Time::HiRes::time;
2122 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2123 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2124 return ( &create_xml_string($out_hash) );
2125 }
2127 ################################
2128 # @brief Bound the given softwareLicenseId to the given host.
2129 # @param hostId Opsi hostId
2130 # @param softwareLicenseId Identificator of a license (optional).
2131 sub opsi_boundHostToLicense {
2132 my $startTime = Time::HiRes::time;
2133 my ($msg, $msg_hash, $session_id) = @_;
2134 my $header = @{$msg_hash->{'header'}}[0];
2135 my $source = @{$msg_hash->{'source'}}[0];
2137 # Check input sanity
2138 my $hostId;
2139 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
2140 $hostId = @{$msg_hash->{'hostId'}}[0];
2141 } else {
2142 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2143 }
2144 my $softwareLicenseId;
2145 if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
2146 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
2147 } else {
2148 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2149 }
2151 # Fetch informations from Opsi server
2152 my ($license_res, $license_err) = &_getSoftwareLicenses_listOfHashes();
2153 if ($license_err){
2154 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server: ".$license_res, $session_id);
2155 }
2157 # Memorize parameter for given softwareLicenseId
2158 my $licenseContractId;
2159 my $licenseType;
2160 my $maxInstallations;
2161 my $boundToHost;
2162 my $expirationDate = "";
2163 my $found;
2164 foreach my $license (@$license_res) {
2165 if ($license->{softwareLicenseId} ne $softwareLicenseId) { next; }
2166 $licenseContractId = $license->{licenseContractId};
2167 $licenseType = $license->{licenseType};
2168 $maxInstallations = $license->{maxInstallations};
2169 $expirationDate = $license->{expirationDate};
2170 $found++;
2171 }
2173 if (not $found) {
2174 return &_giveErrorFeedback($msg_hash, "no softwarelicenseId found with name '".$softwareLicenseId."'", $session_id);
2175 }
2177 # Set boundToHost option for a given software license
2178 my ($bound_res, $bound_err) = &_createSoftwareLicense('softwareLicenseId'=>$softwareLicenseId,
2179 'licenseContractId' => $licenseContractId,
2180 'licenseType' => $licenseType,
2181 'maxInstallations' => $maxInstallations,
2182 'boundToHost' => $hostId,
2183 'expirationDate' => $expirationDate);
2184 if ($bound_err) {
2185 return &_giveErrorFeedback($msg_hash, "cannot set boundToHost for given softwareLicenseId and hostId: ".$bound_res, $session_id);
2186 }
2188 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2189 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2191 my $endTime = Time::HiRes::time;
2192 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2193 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2194 return ( &create_xml_string($out_hash) );
2195 }
2197 ################################
2198 # @brief Release a software license formerly bound to a host.
2199 # @param softwareLicenseId Identificator of a license.
2200 sub opsi_unboundHostFromLicense {
2201 # This is really mad! Opsi is not able to unbound a lincense from a host. To provide the functionality for GOsa
2202 # 4 rpc calls to Opsi are necessary. First, fetch all data for the given softwareLicenseId, then all details for the associated
2203 # licenseContractId, then delete the softwareLicense and finally recreate the softwareLicense without the boundToHost option. NASTY!
2204 my $startTime = Time::HiRes::time;
2205 my ($msg, $msg_hash, $session_id) = @_;
2206 my $header = @{$msg_hash->{'header'}}[0];
2207 my $source = @{$msg_hash->{'source'}}[0];
2209 # Check input sanity
2210 my $softwareLicenseId;
2211 if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
2212 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
2213 } else {
2214 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2215 }
2217 # Memorize parameter witch are required for this procedure
2218 my $licenseContractId;
2219 my $licenseType;
2220 my $maxInstallations;
2221 my $expirationDate;
2222 my $partner;
2223 my $conclusionDate;
2224 my $notificationDate;
2225 my $notes;
2226 my $licensePoolId;
2227 my $licenseKey;
2229 # Fetch license informations from Opsi server
2230 my ($license_res, $license_err) = &_getSoftwareLicenses_listOfHashes();
2231 if ($license_err){
2232 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server, required to unbound license from host: ".$license_res, $session_id);
2233 }
2234 my $found = 0;
2235 foreach my $license (@$license_res) {
2236 if (($found > 0) || ($license->{softwareLicenseId} ne $softwareLicenseId)) { next; }
2237 $licenseContractId = $license->{licenseContractId};
2238 $licenseType = $license->{licenseType};
2239 $maxInstallations = $license->{maxInstallations};
2240 $expirationDate = $license->{expirationDate};
2241 $licensePoolId = @{$license->{licensePoolIds}}[0];
2242 $licenseKey = $license->{licenseKeys}->{$licensePoolId};
2243 $found++;
2244 }
2246 # Fetch contract informations from Opsi server
2247 my ($contract_res, $contract_err) = &_getLicenseContract_hash('licenseContractId'=>$licenseContractId);
2248 if ($contract_err){
2249 return &_giveErrorFeedback($msg_hash, "cannot get contract license information from Opsi server, required to unbound license from host: ".$license_res, $session_id);
2250 }
2251 $partner = $contract_res->{partner};
2252 $conclusionDate = $contract_res->{conclusionDate};
2253 $notificationDate = $contract_res->{notificationDate};
2254 $expirationDate = $contract_res->{expirationDate};
2255 $notes = $contract_res->{notes};
2257 # Delete software license
2258 my ($res, $err) = &_deleteSoftwareLicense( 'softwareLicenseId' => $softwareLicenseId, 'removeFromPools'=> "true" );
2259 if ($err) {
2260 return &_giveErrorFeedback($msg_hash, "cannot delet license from Opsi server, required to unbound license from host : ".$res, $session_id);
2261 }
2263 # Recreate software license without boundToHost
2264 ($res, $err) = &_createLicenseContract( 'licenseContractId' => $licenseContractId, 'partner' => $partner, 'conclusionDate' => $conclusionDate,
2265 'notificationDate' => $notificationDate, 'expirationDate' => $expirationDate, 'notes' => $notes );
2266 if ($err) {
2267 return &_giveErrorFeedback($msg_hash, "cannot create license contract at Opsi server, required to unbound license from host : ".$res, $session_id);
2268 }
2269 ($res, $err) = &_createSoftwareLicense( 'softwareLicenseId' => $softwareLicenseId, 'licenseContractId' => $licenseContractId, 'licenseType' => $licenseType,
2270 'maxInstallations' => $maxInstallations, 'boundToHost' => "", 'expirationDate' => $expirationDate );
2271 if ($err) {
2272 return &_giveErrorFeedback($msg_hash, "cannot create software license at Opsi server, required to unbound license from host : ".$res, $session_id);
2273 }
2274 ($res, $err) = &_addSoftwareLicenseToLicensePool( 'softwareLicenseId' => $softwareLicenseId, 'licensePoolId' => $licensePoolId, 'licenseKey' => $licenseKey );
2275 if ($err) {
2276 return &_giveErrorFeedback($msg_hash, "cannot add software license to license pool at Opsi server, required to unbound license from host : ".$res, $session_id);
2277 }
2279 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2280 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2282 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
2283 return ( &create_xml_string($out_hash) );
2284 }
2286 ################################
2287 # @brief Returns a list of licenses with softwaerLicenseId, maxInstallations, boundToHost, expirationDate, licenseContractId, licenseType, a list of licensePoolIds with associated licenseKeys
2288 sub opsi_getAllSoftwareLicenses {
2289 my $startTime = Time::HiRes::time;
2290 my ($msg, $msg_hash, $session_id) = @_;
2291 my $header = @{$msg_hash->{'header'}}[0];
2292 my $source = @{$msg_hash->{'source'}}[0];
2294 my ($res, $err) = &_getSoftwareLicenses_listOfHashes();
2295 if ($err) {
2296 return &_giveErrorFeedback($msg_hash, "cannot fetch software licenses from Opsi server : ".$res, $session_id);
2297 }
2299 # Parse result
2300 my $res_hash = { 'hit'=> [] };
2301 foreach my $license ( @$res) {
2302 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
2303 'maxInstallations' => [$license->{'maxInstallations'}],
2304 'boundToHost' => [$license->{'boundToHost'}],
2305 'expirationDate' => [$license->{'expirationDate'}],
2306 'licenseContractId' => [$license->{'licenseContractId'}],
2307 'licenseType' => [$license->{'licenseType'}],
2308 'licensePoolIds' => [],
2309 'licenseKeys'=> {}
2310 };
2311 foreach my $licensePoolId (@{$license->{'licensePoolIds'}}) {
2312 push( @{$license_hash->{'licensePoolIds'}}, $licensePoolId);
2313 $license_hash->{licenseKeys}->{$licensePoolId} = [ $license->{'licenseKeys'}->{$licensePoolId} ];
2314 }
2315 push( @{$res_hash->{hit}}, $license_hash );
2316 }
2318 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2319 $out_hash->{licenses} = [$res_hash];
2320 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2322 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
2323 return ( &create_xml_string($out_hash) );
2324 }
2327 ################################
2328 # @brief Returns a list of values for a given host. Values: priority, onceScript, licenseRequired, packageVersion, productVersion, advice, setupScript, windowsSoftwareIds, installationStatus, pxeConfigTemplate, name, creationTimestamp, alwaysScript, productId, description, properties, actionRequest, uninstallScript, action, updateScript and productClassNames
2329 # @param hostId Opsi hostId
2330 sub opsi_get_full_product_host_information {
2331 my $startTime = Time::HiRes::time;
2332 my ($msg, $msg_hash, $session_id) = @_;
2333 my $header = @{$msg_hash->{'header'}}[0];
2334 my $source = @{$msg_hash->{'source'}}[0];
2336 my ($res, $err) = &_get_full_product_host_information( hostId=>@{$msg_hash->{'hostId'}}[0]);
2337 if ($err) {
2338 return &_giveErrorFeedback($msg_hash, "cannot fetch full_product_host_information from Opsi server : ".$res, $session_id);
2339 }
2341 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2342 $out_hash->{hit} = $res;
2343 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2345 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
2346 return ( &myXmlHashToString($out_hash) );
2347 }
2350 sub opsi_test {
2351 my ($msg, $msg_hash, $session_id) = @_;
2352 my $header = @{$msg_hash->{'header'}}[0];
2353 my $source = @{$msg_hash->{'source'}}[0];
2354 my $pram1 = @{$msg_hash->{'productId'}}[0];
2357 # Fetch infos from Opsi server
2358 my $callobj = {
2359 method => 'getLicensePoolId',
2360 params => [ $pram1 ],
2361 id => 1,
2362 };
2363 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
2365 return ();
2366 }
2369 # ----------------------------------------------------------------------------
2370 # internal methods handling the comunication with Opsi
2371 # ----------------------------------------------------------------------------
2373 ################################
2374 # @brief Checks if there is a specified tag and if the the tag has a content.
2375 sub _check_xml_tag_is_ok {
2376 my ($msg_hash,$tag) = @_;
2377 if (not defined $msg_hash->{$tag}) {
2378 $_ = "message contains no tag '$tag'";
2379 return 0;
2380 }
2381 if (ref @{$msg_hash->{$tag}}[0] eq 'HASH') {
2382 $_ = "message tag '$tag' has no content";
2383 return 0;
2384 }
2385 return 1;
2386 }
2388 ################################
2389 # @brief Writes the log line and returns the error message for GOsa.
2390 sub _giveErrorFeedback {
2391 my ($msg_hash, $err_string, $session_id) = @_;
2392 &main::daemon_log("$session_id ERROR: $err_string", 1);
2393 my $out_hash = &main::create_xml_hash("error", $main::server_address, @{$msg_hash->{source}}[0], $err_string);
2394 if (exists $msg_hash->{forward_to_gosa}) {
2395 &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]);
2396 }
2397 return ( &create_xml_string($out_hash) );
2398 }
2401 ################################
2402 # @brief Perform the call to the Opsi server and measure the time for the call
2403 sub _callOpsi {
2404 my %arg = ('method'=>undef, 'params'=>[], 'id'=>1, @_);
2406 my $callObject = {
2407 method => $arg{method},
2408 params => $arg{params},
2409 id => $arg{id},
2410 };
2412 my $startTime = Time::HiRes::time;
2413 my $opsiResult = $opsi_client->call($opsi_url, $callObject);
2414 my $endTime = Time::HiRes::time;
2415 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2417 &main::daemon_log("0 DEBUG: time to process opsi call '$arg{method}' : $elapsedTime seconds", 1034);
2419 return $opsiResult;
2420 }
2422 sub _getLicensePool_hash {
2423 my %arg = ( 'licensePoolId' => undef, @_ );
2425 if (not defined $arg{licensePoolId} ) {
2426 return ("function requires licensePoolId as parameter", 1);
2427 }
2429 my $res = &_callOpsi( method => 'getLicensePool_hash', params =>[$arg{licensePoolId}], id => 1 );
2430 my ($res_error, $res_error_str) = &check_opsi_res($res);
2431 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2433 return ($res->result, 0);
2434 }
2436 sub _getSoftwareLicenses_listOfHashes {
2438 my $res = &_callOpsi( method => 'getSoftwareLicenses_listOfHashes' );
2439 my ($res_error, $res_error_str) = &check_opsi_res($res);
2440 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2442 return ($res->result, 0);
2443 }
2445 sub _getSoftwareLicenseUsages_listOfHashes {
2446 my %arg = ( 'hostId' => "", 'licensePoolId' => "", @_ );
2448 my $res = &_callOpsi( method=>'getSoftwareLicenseUsages_listOfHashes', params=>[ $arg{hostId}, $arg{licensePoolId} ] );
2449 my ($res_error, $res_error_str) = &check_opsi_res($res);
2450 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2452 return ($res->result, 0);
2453 }
2455 sub _removeSoftwareLicenseFromLicensePool {
2456 my %arg = ( 'softwareLicenseId' => undef, 'licensePoolId' => undef, @_ );
2458 if (not defined $arg{softwareLicenseId} ) {
2459 return ("function requires softwareLicenseId as parameter", 1);
2460 }
2461 if (not defined $arg{licensePoolId} ) {
2462 return ("function requires licensePoolId as parameter", 1);
2463 }
2465 my $res = &_callOpsi( method=>'removeSoftwareLicenseFromLicensePool', params=>[ $arg{softwareLicenseId}, $arg{licensePoolId} ] );
2466 my ($res_error, $res_error_str) = &check_opsi_res($res);
2467 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2469 return ($res->result, 0);
2470 }
2472 sub _deleteSoftwareLicense {
2473 my %arg = ( 'softwareLicenseId' => undef, 'removeFromPools' => "false", @_ );
2475 if (not defined $arg{softwareLicenseId} ) {
2476 return ("function requires softwareLicenseId as parameter", 1);
2477 }
2478 my $removeFromPools = "";
2479 if ((defined $arg{removeFromPools}) && ($arg{removeFromPools} eq "true")) {
2480 $removeFromPools = "removeFromPools";
2481 }
2483 my $res = &_callOpsi( method=>'deleteSoftwareLicense', params=>[ $arg{softwareLicenseId}, $removeFromPools ] );
2484 my ($res_error, $res_error_str) = &check_opsi_res($res);
2485 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2487 return ($res->result, 0);
2488 }
2490 sub _getLicensePoolId {
2491 my %arg = ( 'productId' => undef, @_ );
2493 if (not defined $arg{productId} ) {
2494 return ("function requires productId as parameter", 1);
2495 }
2497 my $res = &_callOpsi( method => 'getLicensePoolId', params => [ $arg{productId} ] );
2498 my ($res_error, $res_error_str) = &check_opsi_res($res);
2499 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2501 return ($res->result, 0);
2502 }
2504 sub _getLicenseContract_hash {
2505 my %arg = ( 'licenseContractId' => undef, @_ );
2507 if (not defined $arg{licenseContractId} ) {
2508 return ("function requires licenseContractId as parameter", 1);
2509 }
2511 my $res = &_callOpsi( method => 'getLicenseContract_hash', params => [ $arg{licenseContractId} ] );
2512 my ($res_error, $res_error_str) = &check_opsi_res($res);
2513 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2515 return ($res->result, 0);
2516 }
2518 sub _createLicenseContract {
2519 my %arg = (
2520 'licenseContractId' => undef,
2521 'partner' => undef,
2522 'conclusionDate' => undef,
2523 'notificationDate' => undef,
2524 'expirationDate' => undef,
2525 'notes' => undef,
2526 @_ );
2528 my $res = &_callOpsi( method => 'createLicenseContract',
2529 params => [ $arg{licenseContractId}, $arg{partner}, $arg{conclusionDate}, $arg{notificationDate}, $arg{expirationDate}, $arg{notes} ],
2530 );
2531 my ($res_error, $res_error_str) = &check_opsi_res($res);
2532 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2534 return ($res->result, 0);
2535 }
2537 sub _createSoftwareLicense {
2538 my %arg = (
2539 'softwareLicenseId' => undef,
2540 'licenseContractId' => undef,
2541 'licenseType' => undef,
2542 'maxInstallations' => undef,
2543 'boundToHost' => undef,
2544 'expirationDate' => undef,
2545 @_ );
2547 my $res = &_callOpsi( method => 'createSoftwareLicense',
2548 params => [ $arg{softwareLicenseId}, $arg{licenseContractId}, $arg{licenseType}, $arg{maxInstallations}, $arg{boundToHost}, $arg{expirationDate} ],
2549 );
2550 my ($res_error, $res_error_str) = &check_opsi_res($res);
2551 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2553 return ($res->result, 0);
2554 }
2556 sub _addSoftwareLicenseToLicensePool {
2557 my %arg = (
2558 'softwareLicenseId' => undef,
2559 'licensePoolId' => undef,
2560 'licenseKey' => undef,
2561 @_ );
2563 if (not defined $arg{softwareLicenseId} ) {
2564 return ("function requires softwareLicenseId as parameter", 1);
2565 }
2566 if (not defined $arg{licensePoolId} ) {
2567 return ("function requires licensePoolId as parameter", 1);
2568 }
2570 my $res = &_callOpsi( method => 'addSoftwareLicenseToLicensePool', params => [ $arg{softwareLicenseId}, $arg{licensePoolId}, $arg{licenseKey} ] );
2571 my ($res_error, $res_error_str) = &check_opsi_res($res);
2572 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2574 return ($res->result, 0);
2575 }
2577 sub _getProductStates_hash {
2578 my %arg = ( 'hostId' => undef, @_ );
2580 if (not defined $arg{hostId} ) {
2581 return ("function requires hostId as parameter", 1);
2582 }
2584 my $res = &_callOpsi( method => 'getProductStates_hash', params => [$arg{hostId}]);
2585 my ($res_error, $res_error_str) = &check_opsi_res($res);
2586 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2588 return ($res->result, 0);
2589 }
2591 sub _get_full_product_host_information {
2592 my %arg = ( 'hostId' => undef, @_ );
2594 if (not defined $arg{hostId}) {
2595 return ("function requires hostId as parameter", 1);
2596 }
2598 my $res = &_callOpsi( method => 'getFullProductHostInformation_list', params => [$arg{hostId}]);
2599 my ($res_error, $res_error_str) = &check_opsi_res($res);
2600 if ($res_error){ return ((caller(0))[3]." : ".$res_error_str, 1); }
2602 return ($res->result, 0);
2603 }
2605 1;