1 ## @file
2 # @details A GOsa-SI-server event module containing all functions for message handling.
3 # @brief Implementation of an event module for GOsa-SI-server.
6 package opsi_com;
7 use Exporter;
8 @ISA = qw(Exporter);
9 my @events = (
10 "get_events",
11 "opsi_install_client",
12 "opsi_get_netboot_products",
13 "opsi_get_local_products",
14 "opsi_get_client_hardware",
15 "opsi_get_client_software",
16 "opsi_get_product_properties",
17 "opsi_set_product_properties",
18 "opsi_list_clients",
19 "opsi_del_client",
20 "opsi_add_client",
21 "opsi_modify_client",
22 "opsi_add_product_to_client",
23 "opsi_del_product_from_client",
24 "opsi_createLicensePool",
25 "opsi_deleteLicensePool",
26 "opsi_createLicense",
27 "opsi_assignSoftwareLicenseToHost",
28 "opsi_unassignSoftwareLicenseFromHost",
29 "opsi_unassignAllSoftwareLicensesFromHost",
30 "opsi_getSoftwareLicense_hash",
31 "opsi_getLicensePool_hash",
32 "opsi_getSoftwareLicenseUsages",
33 "opsi_getSoftwareLicenseUsagesForProductId",
34 "opsi_getLicensePools_listOfHashes",
35 "opsi_getLicenseInformationForProduct",
36 "opsi_getPool",
37 "opsi_getAllSoftwareLicenses",
38 "opsi_removeLicense",
39 "opsi_getReservedLicenses",
40 "opsi_boundHostToLicense",
41 "opsi_unboundHostFromLicense",
42 "opsi_test",
43 );
44 @EXPORT = @events;
46 use strict;
47 use warnings;
48 use GOSA::GosaSupportDaemon;
49 use Data::Dumper;
50 use XML::Quote qw(:all);
52 BEGIN {}
54 END {}
56 # ----------------------------------------------------------------------------
57 # D E C L A R A T I O N S
58 # ----------------------------------------------------------------------------
60 my $licenseTyp_hash = { 'OEM'=>'', 'VOLUME'=>'', 'RETAIL'=>''};
61 my ($opsi_enabled, $opsi_server, $opsi_admin, $opsi_password, $opsi_url, $opsi_client);
62 my %cfg_defaults = (
63 "Opsi" => {
64 "enabled" => [\$opsi_enabled, "false"],
65 "server" => [\$opsi_server, "localhost"],
66 "admin" => [\$opsi_admin, "opsi-admin"],
67 "password" => [\$opsi_password, "secret"],
68 },
69 );
70 &read_configfile($main::cfg_file, %cfg_defaults);
71 if ($opsi_enabled eq "true") {
72 use JSON::RPC::Client;
73 use XML::Quote qw(:all);
74 use Time::HiRes qw( time );
75 $opsi_url= "https://".$opsi_admin.":".$opsi_password."@".$opsi_server.":4447/rpc";
76 $opsi_client = new JSON::RPC::Client;
77 }
79 # ----------------------------------------------------------------------------
80 # external methods handling the comunication with GOsa/GOsa-si
81 # ----------------------------------------------------------------------------
83 ################################
84 # @brief A function returning a list of functions which are exported by importing the module.
85 # @return List of all provided functions
86 sub get_events {
87 return \@events;
88 }
90 ################################
91 # @brief Adds an Opsi product to an Opsi client.
92 # @param msg - STRING - xml message with tags hostId and productId
93 # @param msg_hash - HASHREF - message information parsed into a hash
94 # @param session_id - INTEGER - POE session id of the processing of this message
95 # @return out_msg - STRING - feedback to GOsa in success and error case
96 sub opsi_add_product_to_client {
97 my $startTime = Time::HiRes::time;
98 my ($msg, $msg_hash, $session_id) = @_;
99 my $header = @{$msg_hash->{'header'}}[0];
100 my $source = @{$msg_hash->{'source'}}[0];
101 my $target = @{$msg_hash->{'target'}}[0];
102 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
104 # Build return message
105 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
106 if (defined $forward_to_gosa) {
107 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
108 }
110 # Sanity check of needed parameter
111 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
112 return &_giveErrorFeedback($msg_hash, "no hostId specified or hostId tag invalid", $session_id);
113 }
114 if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
115 return &_giveErrorFeedback($msg_hash, "no productId specified or productId tag invalid", $session_id);
116 }
118 # Get hostId
119 my $hostId = @{$msg_hash->{'hostId'}}[0];
120 &add_content2xml_hash($out_hash, "hostId", $hostId);
122 # Get productID
123 my $productId = @{$msg_hash->{'productId'}}[0];
124 &add_content2xml_hash($out_hash, "productId", $productId);
126 # Do an action request for all these -> "setup".
127 my $callobj = {
128 method => 'setProductActionRequest',
129 params => [ $productId, $hostId, "setup" ],
130 id => 1, };
131 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
133 if (&check_opsi_res($res)) { return ( (caller(0))[3]." : ".$_, 1 ); };
135 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
136 return ( &create_xml_string($out_hash) );
137 }
139 ################################
140 # @brief Deletes an Opsi-product from an Opsi-client.
141 # @param msg - STRING - xml message with tags hostId and productId
142 # @param msg_hash - HASHREF - message information parsed into a hash
143 # @param session_id - INTEGER - POE session id of the processing of this message
144 # @return out_msg - STRING - feedback to GOsa in success and error case
145 sub opsi_del_product_from_client {
146 my $startTime = Time::HiRes::time;
147 my ($msg, $msg_hash, $session_id) = @_;
148 my $header = @{$msg_hash->{'header'}}[0];
149 my $source = @{$msg_hash->{'source'}}[0];
150 my $target = @{$msg_hash->{'target'}}[0];
151 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
152 my ($hostId, $productId);
153 my $error = 0;
154 my ($sres, $sres_err, $sres_err_string);
156 # Build return message
157 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
158 if (defined $forward_to_gosa) {
159 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
160 }
162 # Sanity check of needed parameter
163 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
164 $error++;
165 &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
166 &add_content2xml_hash($out_hash, "error", "hostId");
167 &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1);
169 }
170 if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
171 $error++;
172 &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
173 &add_content2xml_hash($out_hash, "error", "productId");
174 &main::daemon_log("$session_id ERROR: no productId specified or procutId tag invalid: $msg", 1);
175 }
177 # All parameter available
178 if (not $error) {
179 # Get hostId
180 $hostId = @{$msg_hash->{'hostId'}}[0];
181 &add_content2xml_hash($out_hash, "hostId", $hostId);
183 # Get productID
184 $productId = @{$msg_hash->{'productId'}}[0];
185 &add_content2xml_hash($out_hash, "productId", $productId);
187 # Check to get product action list
188 my $callobj = {
189 method => 'getPossibleProductActions_list',
190 params => [ $productId ],
191 id => 1, };
192 $sres = $main::opsi_client->call($main::opsi_url, $callobj);
193 ($sres_err, $sres_err_string) = &check_opsi_res($sres);
194 if ($sres_err){
195 &main::daemon_log("$session_id ERROR: cannot get product action list: ".$sres_err_string, 1);
196 &add_content2xml_hash($out_hash, "error", $sres_err_string);
197 $error++;
198 }
199 }
201 # Check action uninstall of product
202 if (not $error) {
203 my $uninst_possible= 0;
204 foreach my $r (@{$sres->result}) {
205 if ($r eq 'uninstall') {
206 $uninst_possible= 1;
207 }
208 }
209 if (!$uninst_possible){
210 &main::daemon_log("$session_id ERROR: cannot uninstall product '$productId', product do not has the action 'uninstall'", 1);
211 &add_content2xml_hash($out_hash, "error", "cannot uninstall product '$productId', product do not has the action 'uninstall'");
212 $error++;
213 }
214 }
216 # Set product state to "none"
217 # Do an action request for all these -> "setup".
218 if (not $error) {
219 my $callobj = {
220 method => 'setProductActionRequest',
221 params => [ $productId, $hostId, "none" ],
222 id => 1,
223 };
224 $sres = $main::opsi_client->call($main::opsi_url, $callobj);
225 ($sres_err, $sres_err_string) = &check_opsi_res($sres);
226 if ($sres_err){
227 &main::daemon_log("$session_id ERROR: cannot delete product: ".$sres_err_string, 1);
228 &add_content2xml_hash($out_hash, "error", $sres_err_string);
229 }
230 }
232 # Return message
233 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
234 return ( &create_xml_string($out_hash) );
235 }
237 ################################
238 # @brief Adds an Opsi client to Opsi.
239 # @param msg - STRING - xml message with tags hostId and macaddress
240 # @param msg_hash - HASHREF - message information parsed into a hash
241 # @param session_id - INTEGER - POE session id of the processing of this message
242 # @return out_msg - STRING - feedback to GOsa in success and error case
243 sub opsi_add_client {
244 my $startTime = Time::HiRes::time;
245 my ($msg, $msg_hash, $session_id) = @_;
246 my $header = @{$msg_hash->{'header'}}[0];
247 my $source = @{$msg_hash->{'source'}}[0];
248 my $target = @{$msg_hash->{'target'}}[0];
249 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
250 my ($hostId, $mac);
251 my $error = 0;
252 my ($sres, $sres_err, $sres_err_string);
254 # Build return message with twisted target and source
255 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
256 if (defined $forward_to_gosa) {
257 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
258 }
260 # Sanity check of needed parameter
261 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
262 $error++;
263 &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
264 &add_content2xml_hash($out_hash, "error", "hostId");
265 &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1);
266 }
267 if ((not exists $msg_hash->{'macaddress'}) || (@{$msg_hash->{'macaddress'}} != 1) || (@{$msg_hash->{'macaddress'}}[0] eq ref 'HASH')) {
268 $error++;
269 &add_content2xml_hash($out_hash, "error_string", "no macaddress specified or macaddress tag invalid");
270 &add_content2xml_hash($out_hash, "error", "macaddress");
271 &main::daemon_log("$session_id ERROR: no macaddress specified or macaddress tag invalid: $msg", 1);
272 }
274 if (not $error) {
275 # Get hostId
276 $hostId = @{$msg_hash->{'hostId'}}[0];
277 &add_content2xml_hash($out_hash, "hostId", $hostId);
279 # Get macaddress
280 $mac = @{$msg_hash->{'macaddress'}}[0];
281 &add_content2xml_hash($out_hash, "macaddress", $mac);
283 my $name= $hostId;
284 $name=~ s/^([^.]+).*$/$1/;
285 my $domain= $hostId;
286 $domain=~ s/^[^.]+\.(.*)$/$1/;
287 my ($description, $notes, $ip);
289 if (defined @{$msg_hash->{'description'}}[0]){
290 $description = @{$msg_hash->{'description'}}[0];
291 }
292 if (defined @{$msg_hash->{'notes'}}[0]){
293 $notes = @{$msg_hash->{'notes'}}[0];
294 }
295 if (defined @{$msg_hash->{'ip'}}[0]){
296 $ip = @{$msg_hash->{'ip'}}[0];
297 }
299 my $callobj;
300 $callobj = {
301 method => 'createClient',
302 params => [ $name, $domain, $description, $notes, $ip, $mac ],
303 id => 1,
304 };
306 $sres = $main::opsi_client->call($main::opsi_url, $callobj);
307 ($sres_err, $sres_err_string) = &check_opsi_res($sres);
308 if ($sres_err){
309 &main::daemon_log("$session_id ERROR: cannot create client: ".$sres_err_string, 1);
310 &add_content2xml_hash($out_hash, "error", $sres_err_string);
311 } else {
312 &main::daemon_log("$session_id INFO: add opsi client '$hostId' with mac '$mac'", 5);
313 }
314 }
316 # Return message
317 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
318 return ( &create_xml_string($out_hash) );
319 }
321 ################################
322 # @brief Modifies the parameters description, mac or notes for an Opsi client if the corresponding message tags are given.
323 # @param msg - STRING - xml message with tag hostId and optional description, mac or notes
324 # @param msg_hash - HASHREF - message information parsed into a hash
325 # @param session_id - INTEGER - POE session id of the processing of this message
326 # @return out_msg - STRING - feedback to GOsa in success and error case
327 sub opsi_modify_client {
328 my $startTime = Time::HiRes::time;
329 my ($msg, $msg_hash, $session_id) = @_;
330 my $header = @{$msg_hash->{'header'}}[0];
331 my $source = @{$msg_hash->{'source'}}[0];
332 my $target = @{$msg_hash->{'target'}}[0];
333 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
334 my $hostId;
335 my $error = 0;
336 my ($sres, $sres_err, $sres_err_string);
338 # Build return message with twisted target and source
339 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
340 if (defined $forward_to_gosa) {
341 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
342 }
344 # Sanity check of needed parameter
345 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
346 $error++;
347 &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
348 &add_content2xml_hash($out_hash, "error", "hostId");
349 &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1);
350 }
352 if (not $error) {
353 # Get hostId
354 $hostId = @{$msg_hash->{'hostId'}}[0];
355 &add_content2xml_hash($out_hash, "hostId", $hostId);
356 my $name= $hostId;
357 $name=~ s/^([^.]+).*$/$1/;
358 my $domain= $hostId;
359 $domain=~ s/^[^.]+(.*)$/$1/;
361 # Modify description, notes or mac if defined
362 my ($description, $notes, $mac);
363 my $callobj;
364 if ((exists $msg_hash->{'description'}) && (@{$msg_hash->{'description'}} == 1) ){
365 $description = @{$msg_hash->{'description'}}[0];
366 $callobj = {
367 method => 'setHostDescription',
368 params => [ $hostId, $description ],
369 id => 1,
370 };
371 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
372 my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
373 if ($sres_err){
374 &main::daemon_log("ERROR: cannot set description: ".$sres_err_string, 1);
375 &add_content2xml_hash($out_hash, "error", $sres_err_string);
376 }
377 }
378 if ((exists $msg_hash->{'notes'}) && (@{$msg_hash->{'notes'}} == 1)) {
379 $notes = @{$msg_hash->{'notes'}}[0];
380 $callobj = {
381 method => 'setHostNotes',
382 params => [ $hostId, $notes ],
383 id => 1,
384 };
385 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
386 my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
387 if ($sres_err){
388 &main::daemon_log("ERROR: cannot set notes: ".$sres_err_string, 1);
389 &add_content2xml_hash($out_hash, "error", $sres_err_string);
390 }
391 }
392 if ((exists $msg_hash->{'mac'}) && (@{$msg_hash->{'mac'}} == 1)){
393 $mac = @{$msg_hash->{'mac'}}[0];
394 $callobj = {
395 method => 'setMacAddress',
396 params => [ $hostId, $mac ],
397 id => 1,
398 };
399 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
400 my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
401 if ($sres_err){
402 &main::daemon_log("ERROR: cannot set mac address: ".$sres_err_string, 1);
403 &add_content2xml_hash($out_hash, "error", $sres_err_string);
404 }
405 }
406 }
408 # Return message
409 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
410 return ( &create_xml_string($out_hash) );
411 }
413 ################################
414 # @brief Get netboot products for specific host.
415 # @param msg - STRING - xml message with tag hostId
416 # @param msg_hash - HASHREF - message information parsed into a hash
417 # @param session_id - INTEGER - POE session id of the processing of this message
418 # @return out_msg - STRING - feedback to GOsa in success and error case
419 sub opsi_get_netboot_products {
420 my $startTime = Time::HiRes::time;
421 my ($msg, $msg_hash, $session_id) = @_;
422 my $header = @{$msg_hash->{'header'}}[0];
423 my $source = @{$msg_hash->{'source'}}[0];
424 my $target = @{$msg_hash->{'target'}}[0];
425 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
426 my $hostId;
427 my $xml_msg;
429 # Build return message with twisted target and source
430 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
431 if (defined $forward_to_gosa) {
432 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
433 }
435 # Get hostId if defined
436 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1)) {
437 $hostId = @{$msg_hash->{'hostId'}}[0];
438 &add_content2xml_hash($out_hash, "hostId", $hostId);
439 }
441 &add_content2xml_hash($out_hash, "xxx", "");
442 $xml_msg = &create_xml_string($out_hash);
443 # For hosts, only return the products that are or get installed
444 my $callobj;
445 $callobj = {
446 method => 'getNetBootProductIds_list',
447 params => [ ],
448 id => 1,
449 };
450 &main::daemon_log("$session_id DEBUG: send callobj to opsi_client: ".&opsi_callobj2string($callobj), 7);
451 &main::daemon_log("$session_id DEBUG: opsi_url $main::opsi_url", 7);
452 &main::daemon_log("$session_id DEBUG: waiting for answer from opsi_client!", 7);
453 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
454 &main::daemon_log("$session_id DEBUG: get answer from opsi_client", 7);
455 my %r = ();
456 for (@{$res->result}) { $r{$_} = 1 }
458 if (not &check_opsi_res($res)){
460 if (defined $hostId){
462 $callobj = {
463 method => 'getProductStates_hash',
464 params => [ $hostId ],
465 id => 1,
466 };
468 my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
469 if (not &check_opsi_res($hres)){
470 my $htmp= $hres->result->{$hostId};
472 # check state != not_installed or action == setup -> load and add
473 foreach my $product (@{$htmp}){
475 if (!defined ($r{$product->{'productId'}})){
476 next;
477 }
479 # Now we've a couple of hashes...
480 if ($product->{'installationStatus'} ne "not_installed" or
481 $product->{'actionRequest'} eq "setup"){
482 my $state= "<state>".$product->{'installationStatus'}."</state><action>".$product->{'actionRequest'}."</action>";
484 $callobj = {
485 method => 'getProduct_hash',
486 params => [ $product->{'productId'} ],
487 id => 1,
488 };
490 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
491 if (not &check_opsi_res($sres)){
492 my $tres= $sres->result;
494 my $name= xml_quote($tres->{'name'});
495 my $r= $product->{'productId'};
496 my $description= xml_quote($tres->{'description'});
497 $name=~ s/\//\\\//;
498 $description=~ s/\//\\\//;
499 $xml_msg=~ s/<xxx><\/xxx>/\n<item><productId>$r<\/productId><name>$name<\/name><description>$description<\/description><\/item>$state<xxx><\/xxx>/;
500 }
501 }
502 }
504 }
506 } else {
507 foreach my $r (@{$res->result}) {
508 $callobj = {
509 method => 'getProduct_hash',
510 params => [ $r ],
511 id => 1,
512 };
514 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
515 if (not &check_opsi_res($sres)){
516 my $tres= $sres->result;
518 my $name= xml_quote($tres->{'name'});
519 my $description= xml_quote($tres->{'description'});
520 $name=~ s/\//\\\//;
521 $description=~ s/\//\\\//;
522 $xml_msg=~ s/<xxx><\/xxx>/\n<item><productId>$r<\/productId><name>$name<\/name><description>$description<\/description><\/item><xxx><\/xxx>/;
523 }
524 }
526 }
527 }
528 $xml_msg=~ s/<xxx><\/xxx>//;
530 # Return message
531 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
532 return ( $xml_msg );
533 }
535 ################################
536 # @brief Get product properties for a product and a specific host or gobally for a product.
537 # @param msg - STRING - xml message with tags productId and optional hostId
538 # @param msg_hash - HASHREF - message information parsed into a hash
539 # @param session_id - INTEGER - POE session id of the processing of this message
540 # @return out_msg - STRING - feedback to GOsa in success and error case
541 sub opsi_get_product_properties {
542 my $startTime = Time::HiRes::time;
543 my ($msg, $msg_hash, $session_id) = @_;
544 my $header = @{$msg_hash->{'header'}}[0];
545 my $source = @{$msg_hash->{'source'}}[0];
546 my $target = @{$msg_hash->{'target'}}[0];
547 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
548 my ($hostId, $productId);
549 my $xml_msg;
551 # Build return message with twisted target and source
552 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
553 if (defined $forward_to_gosa) {
554 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
555 }
557 # Sanity check of needed parameter
558 if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
559 &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
560 &add_content2xml_hash($out_hash, "error", "productId");
561 &main::daemon_log("$session_id ERROR: no productId specified or productId tag invalid: $msg", 1);
563 # Return message
564 return ( &create_xml_string($out_hash) );
565 }
567 # Get productid
568 $productId = @{$msg_hash->{'productId'}}[0];
569 &add_content2xml_hash($out_hash, "producId", "$productId");
571 # Get hostId if defined
572 if (defined @{$msg_hash->{'hostId'}}[0]){
573 $hostId = @{$msg_hash->{'hostId'}}[0];
574 &add_content2xml_hash($out_hash, "hostId", $hostId);
575 }
577 # Load actions
578 my $callobj = {
579 method => 'getPossibleProductActions_list',
580 params => [ $productId ],
581 id => 1,
582 };
583 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
584 if (not &check_opsi_res($res)){
585 foreach my $action (@{$res->result}){
586 &add_content2xml_hash($out_hash, "action", $action);
587 }
588 }
590 # Add place holder
591 &add_content2xml_hash($out_hash, "xxx", "");
593 # Move to XML string
594 $xml_msg= &create_xml_string($out_hash);
596 # JSON Query
597 if (defined $hostId){
598 $callobj = {
599 method => 'getProductProperties_hash',
600 params => [ $productId, $hostId ],
601 id => 1,
602 };
603 } else {
604 $callobj = {
605 method => 'getProductProperties_hash',
606 params => [ $productId ],
607 id => 1,
608 };
609 }
610 $res = $main::opsi_client->call($main::opsi_url, $callobj);
612 # JSON Query 2
613 $callobj = {
614 method => 'getProductPropertyDefinitions_listOfHashes',
615 params => [ $productId ],
616 id => 1,
617 };
619 # Assemble options
620 my $res2 = $main::opsi_client->call($main::opsi_url, $callobj);
621 my $values = {};
622 my $descriptions = {};
623 if (not &check_opsi_res($res2)){
624 my $r= $res2->result;
626 foreach my $entr (@$r){
627 # Unroll values
628 my $cnv;
629 if (UNIVERSAL::isa( $entr->{'values'}, "ARRAY" )){
630 foreach my $v (@{$entr->{'values'}}){
631 $cnv.= "<value>$v</value>";
632 }
633 } else {
634 $cnv= $entr->{'values'};
635 }
636 $values->{$entr->{'name'}}= $cnv;
637 $descriptions->{$entr->{'name'}}= "<description>".$entr->{'description'}."</description>";
638 }
639 }
641 if (not &check_opsi_res($res)){
642 my $r= $res->result;
643 foreach my $key (keys %{$r}) {
644 my $item= "\n<item>";
645 my $value= $r->{$key};
646 my $dsc= "";
647 my $vals= "";
648 if (defined $descriptions->{$key}){
649 $dsc= $descriptions->{$key};
650 }
651 if (defined $values->{$key}){
652 $vals= $values->{$key};
653 }
654 $item.= "<$key>$dsc<default>".xml_quote($value)."</default>$vals</$key>";
655 $item.= "</item>";
656 $xml_msg=~ s/<xxx><\/xxx>/$item<xxx><\/xxx>/;
657 }
658 }
660 $xml_msg=~ s/<xxx><\/xxx>//;
662 # Return message
663 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
664 return ( $xml_msg );
665 }
667 ################################
668 # @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.
669 # @param msg - STRING - xml message with tags productId, action, state and optional hostId, action and state
670 # @param msg_hash - HASHREF - message information parsed into a hash
671 # @param session_id - INTEGER - POE session id of the processing of this message
672 # @return out_msg - STRING - feedback to GOsa in success and error case
673 sub opsi_set_product_properties {
674 my $startTime = Time::HiRes::time;
675 my ($msg, $msg_hash, $session_id) = @_;
676 my $header = @{$msg_hash->{'header'}}[0];
677 my $source = @{$msg_hash->{'source'}}[0];
678 my $target = @{$msg_hash->{'target'}}[0];
679 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
680 my ($productId, $hostId);
682 # Build return message with twisted target and source
683 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
684 if (defined $forward_to_gosa) {
685 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
686 }
688 # Sanity check of needed parameter
689 if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
690 &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
691 &add_content2xml_hash($out_hash, "error", "productId");
692 &main::daemon_log("$session_id ERROR: no productId specified or productId tag invalid: $msg", 1);
693 return ( &create_xml_string($out_hash) );
694 }
695 if (not exists $msg_hash->{'item'}) {
696 &add_content2xml_hash($out_hash, "error_string", "message needs one xml-tag 'item' and within the xml-tags 'name' and 'value'");
697 &add_content2xml_hash($out_hash, "error", "item");
698 &main::daemon_log("$session_id ERROR: message needs one xml-tag 'item' and within the xml-tags 'name' and 'value': $msg", 1);
699 return ( &create_xml_string($out_hash) );
700 } else {
701 if ((not exists @{$msg_hash->{'item'}}[0]->{'name'}) || (@{@{$msg_hash->{'item'}}[0]->{'name'}} != 1 )) {
702 &add_content2xml_hash($out_hash, "error_string", "message needs within the xml-tag 'item' one xml-tags 'name'");
703 &add_content2xml_hash($out_hash, "error", "name");
704 &main::daemon_log("$session_id ERROR: message needs within the xml-tag 'item' one xml-tags 'name': $msg", 1);
705 return ( &create_xml_string($out_hash) );
706 }
707 if ((not exists @{$msg_hash->{'item'}}[0]->{'value'}) || (@{@{$msg_hash->{'item'}}[0]->{'value'}} != 1 )) {
708 &add_content2xml_hash($out_hash, "error_string", "message needs within the xml-tag 'item' one xml-tags 'value'");
709 &add_content2xml_hash($out_hash, "error", "value");
710 &main::daemon_log("$session_id ERROR: message needs within the xml-tag 'item' one xml-tags 'value': $msg", 1);
711 return ( &create_xml_string($out_hash) );
712 }
713 }
714 # if no hostId is given, set_product_properties will act on globally
715 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} > 1)) {
716 &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
717 &add_content2xml_hash($out_hash, "error", "hostId");
718 &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1);
719 return ( &create_xml_string($out_hash) );
720 }
723 # Get productId
724 $productId = @{$msg_hash->{'productId'}}[0];
725 &add_content2xml_hash($out_hash, "productId", $productId);
727 # Get hostId if defined
728 if (exists $msg_hash->{'hostId'}){
729 $hostId = @{$msg_hash->{'hostId'}}[0];
730 &add_content2xml_hash($out_hash, "hostId", $hostId);
731 }
733 # Set product states if requested
734 if (defined @{$msg_hash->{'action'}}[0]){
735 &_set_action($productId, @{$msg_hash->{'action'}}[0], $hostId);
736 }
737 if (defined @{$msg_hash->{'state'}}[0]){
738 &_set_state($productId, @{$msg_hash->{'state'}}[0], $hostId);
739 }
741 # Find properties
742 foreach my $item (@{$msg_hash->{'item'}}){
743 # JSON Query
744 my $callobj;
746 if (defined $hostId){
747 $callobj = {
748 method => 'setProductProperty',
749 params => [ $productId, $item->{'name'}[0], $item->{'value'}[0], $hostId ],
750 id => 1,
751 };
752 } else {
753 $callobj = {
754 method => 'setProductProperty',
755 params => [ $productId, $item->{'name'}[0], $item->{'value'}[0] ],
756 id => 1,
757 };
758 }
760 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
761 my ($res_err, $res_err_string) = &check_opsi_res($res);
763 if ($res_err){
764 &main::daemon_log("$session_id ERROR: communication failed while setting '".$item->{'name'}[0]."': ".$res_err_string, 1);
765 &add_content2xml_hash($out_hash, "error", $res_err_string);
766 }
767 }
770 # Return message
771 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
772 return ( &create_xml_string($out_hash) );
773 }
775 ################################
776 # @brief Reports client hardware inventory.
777 # @param msg - STRING - xml message with tag hostId
778 # @param msg_hash - HASHREF - message information parsed into a hash
779 # @param session_id - INTEGER - POE session id of the processing of this message
780 # @return out_msg - STRING - feedback to GOsa in success and error case
781 sub opsi_get_client_hardware {
782 my $startTime = Time::HiRes::time;
783 my ($msg, $msg_hash, $session_id) = @_;
784 my $header = @{$msg_hash->{'header'}}[0];
785 my $source = @{$msg_hash->{'source'}}[0];
786 my $target = @{$msg_hash->{'target'}}[0];
787 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
788 my $hostId;
789 my $error = 0;
790 my $xml_msg;
792 # Sanity check of needed parameter
793 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
794 $hostId = @{$msg_hash->{'hostId'}}[0];
795 } else {
796 return &_giveErrorFeedback($msg_hash, $_, $session_id);
797 }
800 # Build return message with twisted target and source
801 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
802 if (defined $forward_to_gosa) {
803 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
804 }
805 &add_content2xml_hash($out_hash, "hostId", "$hostId");
806 &add_content2xml_hash($out_hash, "xxx", "");
808 # Move to XML string
809 $xml_msg= &create_xml_string($out_hash);
811 my $res = &_callOpsi(method=>'getHardwareInformation_hash', params=>[ $hostId ]);
812 if (not &check_opsi_res($res)){
813 my $result= $res->result;
814 if (ref $result eq "HASH") {
815 foreach my $r (keys %{$result}){
816 my $item= "\n<item><id>".xml_quote($r)."</id>";
817 my $value= $result->{$r};
818 foreach my $sres (@{$value}){
820 foreach my $dres (keys %{$sres}){
821 if (defined $sres->{$dres}){
822 $item.= "<$dres>".xml_quote($sres->{$dres})."</$dres>";
823 }
824 }
826 }
827 $item.= "</item>";
828 $xml_msg=~ s%<xxx></xxx>%$item<xxx></xxx>%;
830 }
831 }
832 }
834 $xml_msg=~ s/<xxx><\/xxx>//;
836 # Return message
837 my $endTime = Time::HiRes::time;
838 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
839 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
840 return ( $xml_msg );
841 }
843 ################################
844 # @brief Reports all Opsi clients.
845 # @param msg - STRING - xml message
846 # @param msg_hash - HASHREF - message information parsed into a hash
847 # @param session_id - INTEGER - POE session id of the processing of this message
848 # @return out_msg - STRING - feedback to GOsa in success and error case
849 sub opsi_list_clients {
850 my $startTime = Time::HiRes::time;
851 my ($msg, $msg_hash, $session_id) = @_;
852 my $header = @{$msg_hash->{'header'}}[0];
853 my $source = @{$msg_hash->{'source'}}[0];
854 my $target = @{$msg_hash->{'target'}}[0];
855 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
857 # Build return message with twisted target and source
858 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
859 if (defined $forward_to_gosa) {
860 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
861 }
862 &add_content2xml_hash($out_hash, "xxx", "");
864 # Move to XML string
865 my $xml_msg= &create_xml_string($out_hash);
867 # JSON Query
868 my $callobj = {
869 method => 'getClients_listOfHashes',
870 params => [ ],
871 id => 1,
872 };
873 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
874 if (not &check_opsi_res($res)){
875 foreach my $host (@{$res->result}){
876 my $item= "\n<item><name>".$host->{'hostId'}."</name>";
877 if (defined($host->{'description'})){
878 $item.= "<description>".xml_quote($host->{'description'})."</description>";
879 }
880 if (defined($host->{'notes'})){
881 $item.= "<notes>".xml_quote($host->{'notes'})."</notes>";
882 }
883 if (defined($host->{'lastSeen'})){
884 $item.= "<lastSeen>".xml_quote($host->{'lastSeen'})."</lastSeen>";
885 }
887 $callobj = {
888 method => 'getIpAddress',
889 params => [ $host->{'hostId'} ],
890 id => 1,
891 };
892 my $sres= $main::opsi_client->call($main::opsi_url, $callobj);
893 if ( not &check_opsi_res($sres)){
894 $item.= "<ip>".xml_quote($sres->result)."</ip>";
895 }
897 $callobj = {
898 method => 'getMacAddress',
899 params => [ $host->{'hostId'} ],
900 id => 1,
901 };
902 $sres= $main::opsi_client->call($main::opsi_url, $callobj);
903 if ( not &check_opsi_res($sres)){
904 $item.= "<mac>".xml_quote($sres->result)."</mac>";
905 }
906 $item.= "</item>";
907 $xml_msg=~ s%<xxx></xxx>%$item<xxx></xxx>%;
908 }
909 }
910 $xml_msg=~ s/<xxx><\/xxx>//;
912 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
913 return ( $xml_msg );
914 }
916 ################################
917 # @brief Reports client software inventory.
918 # @param msg - STRING - xml message with tag hostId
919 # @param msg_hash - HASHREF - message information parsed into a hash
920 # @param session_id - INTEGER - POE session id of the processing of this message
921 # @return out_msg - STRING - feedback to GOsa in success and error case
922 sub opsi_get_client_software {
923 my $startTime = Time::HiRes::time;
924 my ($msg, $msg_hash, $session_id) = @_;
925 my $header = @{$msg_hash->{'header'}}[0];
926 my $source = @{$msg_hash->{'source'}}[0];
927 my $target = @{$msg_hash->{'target'}}[0];
928 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
929 my $error = 0;
930 my $hostId;
931 my $xml_msg;
933 # Build return message with twisted target and source
934 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
935 if (defined $forward_to_gosa) {
936 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
937 }
939 # Sanity check of needed parameter
940 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
941 $error++;
942 &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
943 &add_content2xml_hash($out_hash, "error", "hostId");
944 &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1);
945 }
947 if (not $error) {
949 # Get hostId
950 $hostId = @{$msg_hash->{'hostId'}}[0];
951 &add_content2xml_hash($out_hash, "hostId", "$hostId");
952 &add_content2xml_hash($out_hash, "xxx", "");
953 }
955 $xml_msg= &create_xml_string($out_hash);
957 if (not $error) {
959 # JSON Query
960 my $callobj = {
961 method => 'getSoftwareInformation_hash',
962 params => [ $hostId ],
963 id => 1,
964 };
966 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
967 if (not &check_opsi_res($res)){
968 my $result= $res->result;
969 }
971 $xml_msg=~ s/<xxx><\/xxx>//;
973 }
975 # Return message
976 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
977 return ( $xml_msg );
978 }
980 ################################
981 # @brief Reports product for given hostId or globally.
982 # @param msg - STRING - xml message with optional tag hostId
983 # @param msg_hash - HASHREF - message information parsed into a hash
984 # @param session_id - INTEGER - POE session id of the processing of this message
985 # @return out_msg - STRING - feedback to GOsa in success and error case
986 sub opsi_get_local_products {
987 my $startTime = Time::HiRes::time;
988 my ($msg, $msg_hash, $session_id) = @_;
989 my $header = @{$msg_hash->{'header'}}[0];
990 my $source = @{$msg_hash->{'source'}}[0];
991 my $target = @{$msg_hash->{'target'}}[0];
992 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
993 my $hostId;
995 # Build return message with twisted target and source
996 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
997 if (defined $forward_to_gosa) {
998 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
999 }
1000 &add_content2xml_hash($out_hash, "xxx", "");
1002 # Get hostId if defined
1003 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1)) {
1004 $hostId = @{$msg_hash->{'hostId'}}[0];
1005 &add_content2xml_hash($out_hash, "hostId", $hostId);
1006 }
1008 # Move to XML string
1009 my $xml_msg= &create_xml_string($out_hash);
1011 # For hosts, only return the products that are or get installed
1012 my $callobj;
1013 $callobj = {
1014 method => 'getLocalBootProductIds_list',
1015 params => [ ],
1016 id => 1,
1017 };
1019 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1020 my %r = ();
1021 for (@{$res->result}) { $r{$_} = 1 }
1023 if (not &check_opsi_res($res)){
1025 if (defined $hostId){
1026 $callobj = {
1027 method => 'getProductStates_hash',
1028 params => [ $hostId ],
1029 id => 1,
1030 };
1032 my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
1033 if (not &check_opsi_res($hres)){
1034 my $htmp= $hres->result->{$hostId};
1036 # Check state != not_installed or action == setup -> load and add
1037 foreach my $product (@{$htmp}){
1039 if (!defined ($r{$product->{'productId'}})){
1040 next;
1041 }
1043 # Now we've a couple of hashes...
1044 if ($product->{'installationStatus'} ne "not_installed" or
1045 $product->{'actionRequest'} eq "setup"){
1046 my $state= "<state>".$product->{'installationStatus'}."</state><action>".$product->{'actionRequest'}."</action>";
1048 $callobj = {
1049 method => 'getProduct_hash',
1050 params => [ $product->{'productId'} ],
1051 id => 1,
1052 };
1054 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
1055 if (not &check_opsi_res($sres)){
1056 my $tres= $sres->result;
1058 my $name= xml_quote($tres->{'name'});
1059 my $r= $product->{'productId'};
1060 my $description= xml_quote($tres->{'description'});
1061 $name=~ s/\//\\\//;
1062 $description=~ s/\//\\\//;
1063 $xml_msg=~ s/<xxx><\/xxx>/\n<item><productId>$r<\/productId><name>$name<\/name><description>$description<\/description><\/item>$state<xxx><\/xxx>/;
1064 }
1066 }
1067 }
1069 }
1071 } else {
1072 foreach my $r (@{$res->result}) {
1073 $callobj = {
1074 method => 'getProduct_hash',
1075 params => [ $r ],
1076 id => 1,
1077 };
1079 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
1080 if (not &check_opsi_res($sres)){
1081 my $tres= $sres->result;
1083 my $name= xml_quote($tres->{'name'});
1084 my $description= xml_quote($tres->{'description'});
1085 $name=~ s/\//\\\//;
1086 $description=~ s/\//\\\//;
1087 $xml_msg=~ s/<xxx><\/xxx>/\n<item><productId>$r<\/productId><name>$name<\/name><description>$description<\/description><\/item><xxx><\/xxx>/;
1088 }
1090 }
1092 }
1093 }
1095 $xml_msg=~ s/<xxx><\/xxx>//;
1097 # Retrun Message
1098 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1099 return ( $xml_msg );
1100 }
1102 ################################
1103 # @brief Deletes a client from Opsi.
1104 # @param msg - STRING - xml message with tag hostId
1105 # @param msg_hash - HASHREF - message information parsed into a hash
1106 # @param session_id - INTEGER - POE session id of the processing of this message
1107 # @return out_msg - STRING - feedback to GOsa in success and error case
1108 sub opsi_del_client {
1109 my $startTime = Time::HiRes::time;
1110 my ($msg, $msg_hash, $session_id) = @_;
1111 my $header = @{$msg_hash->{'header'}}[0];
1112 my $source = @{$msg_hash->{'source'}}[0];
1113 my $target = @{$msg_hash->{'target'}}[0];
1114 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1115 my $hostId;
1116 my $error = 0;
1118 # Build return message with twisted target and source
1119 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1120 if (defined $forward_to_gosa) {
1121 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1122 }
1124 # Sanity check of needed parameter
1125 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
1126 $error++;
1127 &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
1128 &add_content2xml_hash($out_hash, "error", "hostId");
1129 &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1);
1130 }
1132 if (not $error) {
1134 # Get hostId
1135 $hostId = @{$msg_hash->{'hostId'}}[0];
1136 &add_content2xml_hash($out_hash, "hostId", "$hostId");
1138 # JSON Query
1139 my $callobj = {
1140 method => 'deleteClient',
1141 params => [ $hostId ],
1142 id => 1,
1143 };
1144 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1145 }
1147 # Move to XML string
1148 my $xml_msg= &create_xml_string($out_hash);
1150 # Return message
1151 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1152 return ( $xml_msg );
1153 }
1155 ################################
1156 # @brief Set a client in Opsi to install and trigger a wake on lan message (WOL).
1157 # @param msg - STRING - xml message with tags hostId, macaddress
1158 # @param msg_hash - HASHREF - message information parsed into a hash
1159 # @param session_id - INTEGER - POE session id of the processing of this message
1160 # @return out_msg - STRING - feedback to GOsa in success and error case
1161 sub opsi_install_client {
1162 my $startTime = Time::HiRes::time;
1163 my ($msg, $msg_hash, $session_id) = @_;
1164 my $header = @{$msg_hash->{'header'}}[0];
1165 my $source = @{$msg_hash->{'source'}}[0];
1166 my $target = @{$msg_hash->{'target'}}[0];
1167 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1168 my ($hostId, $macaddress);
1169 my $error = 0;
1170 my @out_msg_l;
1172 # Build return message with twisted target and source
1173 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1174 if (defined $forward_to_gosa) {
1175 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1176 }
1178 # Sanity check of needed parameter
1179 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
1180 $error++;
1181 &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
1182 &add_content2xml_hash($out_hash, "error", "hostId");
1183 &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1);
1184 }
1185 if ((not exists $msg_hash->{'macaddress'}) || (@{$msg_hash->{'macaddress'}} != 1) || (@{$msg_hash->{'macaddress'}}[0] eq ref 'HASH') ) {
1186 $error++;
1187 &add_content2xml_hash($out_hash, "error_string", "no macaddress specified or macaddress tag invalid");
1188 &add_content2xml_hash($out_hash, "error", "macaddress");
1189 &main::daemon_log("$session_id ERROR: no macaddress specified or macaddress tag invalid: $msg", 1);
1190 } else {
1191 if ((exists $msg_hash->{'macaddress'}) &&
1192 ($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)) {
1193 $macaddress = $1;
1194 } else {
1195 $error ++;
1196 &add_content2xml_hash($out_hash, "error_string", "given mac address is not correct");
1197 &add_content2xml_hash($out_hash, "error", "macaddress");
1198 &main::daemon_log("$session_id ERROR: given mac address is not correct: $msg", 1);
1199 }
1200 }
1202 if (not $error) {
1204 # Get hostId
1205 $hostId = @{$msg_hash->{'hostId'}}[0];
1206 &add_content2xml_hash($out_hash, "hostId", "$hostId");
1208 # Load all products for this host with status != "not_installed" or actionRequest != "none"
1209 my $callobj = {
1210 method => 'getProductStates_hash',
1211 params => [ $hostId ],
1212 id => 1,
1213 };
1215 my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
1216 if (not &check_opsi_res($hres)){
1217 my $htmp= $hres->result->{$hostId};
1219 # check state != not_installed or action == setup -> load and add
1220 foreach my $product (@{$htmp}){
1221 # Now we've a couple of hashes...
1222 if ($product->{'installationStatus'} ne "not_installed" or
1223 $product->{'actionRequest'} ne "none"){
1225 # Do an action request for all these -> "setup".
1226 $callobj = {
1227 method => 'setProductActionRequest',
1228 params => [ $product->{'productId'}, $hostId, "setup" ],
1229 id => 1,
1230 };
1231 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1232 my ($res_err, $res_err_string) = &check_opsi_res($res);
1233 if ($res_err){
1234 &main::daemon_log("$session_id ERROR: cannot set product action request for '$hostId': ".$product->{'productId'}, 1);
1235 } else {
1236 &main::daemon_log("$session_id INFO: requesting 'setup' for '".$product->{'productId'}."' on $hostId", 1);
1237 }
1238 }
1239 }
1240 }
1241 push(@out_msg_l, &create_xml_string($out_hash));
1244 # Build wakeup message for client
1245 if (not $error) {
1246 my $wakeup_hash = &create_xml_hash("trigger_wake", "GOSA", "KNOWN_SERVER");
1247 &add_content2xml_hash($wakeup_hash, 'macaddress', $macaddress);
1248 my $wakeup_msg = &create_xml_string($wakeup_hash);
1249 push(@out_msg_l, $wakeup_msg);
1251 # invoke trigger wake for this gosa-si-server
1252 &main::server_server_com::trigger_wake($wakeup_msg, $wakeup_hash, $session_id);
1253 }
1254 }
1256 # Return messages
1257 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1258 return @out_msg_l;
1259 }
1261 ################################
1262 # @brief Set action for an Opsi client
1263 # @param product - STRING - Opsi product
1264 # @param action - STRING - action
1265 # @param hostId - STRING - Opsi hostId
1266 sub _set_action {
1267 my $product= shift;
1268 my $action = shift;
1269 my $hostId = shift;
1270 my $callobj;
1272 $callobj = {
1273 method => 'setProductActionRequest',
1274 params => [ $product, $hostId, $action],
1275 id => 1,
1276 };
1278 $main::opsi_client->call($main::opsi_url, $callobj);
1279 }
1281 ################################
1282 # @brief Set state for an Opsi client
1283 # @param product - STRING - Opsi product
1284 # @param action - STRING - state
1285 # @param hostId - STRING - Opsi hostId
1286 sub _set_state {
1287 my $product = shift;
1288 my $state = shift;
1289 my $hostId = shift;
1290 my $callobj;
1292 $callobj = {
1293 method => 'setProductState',
1294 params => [ $product, $hostId, $state ],
1295 id => 1,
1296 };
1298 $main::opsi_client->call($main::opsi_url, $callobj);
1299 }
1301 ################################
1302 # @brief Create a license pool at Opsi server.
1303 # @param licensePoolId The name of the pool (optional).
1304 # @param description The description of the pool (optional).
1305 # @param productIds A list of assigned porducts of the pool (optional).
1306 # @param windowsSoftwareIds A list of windows software IDs associated to the pool (optional).
1307 sub opsi_createLicensePool {
1308 my $startTime = Time::HiRes::time;
1309 my ($msg, $msg_hash, $session_id) = @_;
1310 my $header = @{$msg_hash->{'header'}}[0];
1311 my $source = @{$msg_hash->{'source'}}[0];
1312 my $target = @{$msg_hash->{'target'}}[0];
1313 my $out_hash;
1314 my $licensePoolId = defined $msg_hash->{'licensePoolId'} ? @{$msg_hash->{'licensePoolId'}}[0] : undef;
1315 my $description = defined $msg_hash->{'description'} ? @{$msg_hash->{'description'}}[0] : undef;
1316 my @productIds = defined $msg_hash->{'productIds'} ? $msg_hash->{'productIds'} : undef;
1317 my @windowsSoftwareIds = defined $msg_hash->{'windowsSoftwareIds'} ? $msg_hash->{'windowsSoftwareIds'} : undef;
1319 # Create license Pool
1320 my $callobj = {
1321 method => 'createLicensePool',
1322 params => [ $licensePoolId, $description, @productIds, @windowsSoftwareIds],
1323 id => 1,
1324 };
1325 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1327 # Check Opsi error
1328 my ($res_error, $res_error_str) = &check_opsi_res($res);
1329 if ($res_error){
1330 # Create error message
1331 &main::daemon_log("$session_id ERROR: cannot create license pool at Opsi server: ".$res_error_str, 1);
1332 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1333 return ( &create_xml_string($out_hash) );
1334 }
1336 # Create function result message
1337 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source, $res->result);
1338 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1340 my $endTime = Time::HiRes::time;
1341 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1342 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1343 return ( &create_xml_string($out_hash) );
1344 }
1346 ################################
1347 # @brief Return licensePoolId, description, productIds and windowsSoftwareIds for all found license pools.
1348 sub opsi_getLicensePools_listOfHashes {
1349 my $startTime = Time::HiRes::time;
1350 my ($msg, $msg_hash, $session_id) = @_;
1351 my $header = @{$msg_hash->{'header'}}[0];
1352 my $source = @{$msg_hash->{'source'}}[0];
1353 my $out_hash;
1355 # Fetch infos from Opsi server
1356 my $callobj = {
1357 method => 'getLicensePools_listOfHashes',
1358 params => [ ],
1359 id => 1,
1360 };
1361 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1363 # Check Opsi error
1364 my ($res_error, $res_error_str) = &check_opsi_res($res);
1365 if ($res_error){
1366 # Create error message
1367 &main::daemon_log("$session_id ERROR: cannot get license pool ID list from Opsi server: ".$res_error_str, 1);
1368 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1369 return ( &create_xml_string($out_hash) );
1370 }
1372 # Create function result message
1373 my $res_hash = { 'hit'=> [] };
1374 foreach my $licensePool ( @{$res->result}) {
1375 my $licensePool_hash = { 'licensePoolId' => [$licensePool->{'licensePoolId'}],
1376 'description' => [$licensePool->{'description'}],
1377 'productIds' => $licensePool->{'productIds'},
1378 'windowsSoftwareIds' => $licensePool->{'windowsSoftwareIds'},
1379 };
1380 push( @{$res_hash->{hit}}, $licensePool_hash );
1381 }
1383 # Create function result message
1384 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1385 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1386 $out_hash->{result} = [$res_hash];
1388 my $endTime = Time::HiRes::time;
1389 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1390 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1391 return ( &create_xml_string($out_hash) );
1392 }
1394 ################################
1395 # @brief Return productIds, windowsSoftwareIds and description for a given licensePoolId
1396 # @param licensePoolId The name of the pool.
1397 sub opsi_getLicensePool_hash {
1398 my $startTime = Time::HiRes::time;
1399 my ($msg, $msg_hash, $session_id) = @_;
1400 my $header = @{$msg_hash->{'header'}}[0];
1401 my $source = @{$msg_hash->{'source'}}[0];
1402 my $target = @{$msg_hash->{'target'}}[0];
1403 my $licensePoolId;
1404 my $out_hash;
1406 # Check input sanity
1407 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1408 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1409 } else {
1410 return &_giveErrorFeedback($msg_hash, "", $session_id, $_);
1411 }
1413 # Fetch infos from Opsi server
1414 my $callobj = {
1415 method => 'getLicensePool_hash',
1416 params => [ $licensePoolId ],
1417 id => 1,
1418 };
1419 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1421 # Check Opsi error
1422 my ($res_error, $res_error_str) = &check_opsi_res($res);
1423 if ($res_error){
1424 # Create error message
1425 &main::daemon_log("$session_id ERROR: cannot get license pool from Opsi server: ".$res_error_str, 1);
1426 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source);
1427 &add_content2xml_hash($out_hash, "error", $res_error_str);
1428 return ( &create_xml_string($out_hash) );
1429 }
1431 # Create function result message
1432 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1433 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1434 &add_content2xml_hash($out_hash, "licensePoolId", $res->result->{'licensePoolId'});
1435 &add_content2xml_hash($out_hash, "description", $res->result->{'description'});
1436 map(&add_content2xml_hash($out_hash, "productIds", "$_"), @{ $res->result->{'productIds'} });
1437 map(&add_content2xml_hash($out_hash, "windowsSoftwareIds", "$_"), @{ $res->result->{'windowsSoftwareIds'} });
1439 my $endTime = Time::HiRes::time;
1440 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1441 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1442 return ( &create_xml_string($out_hash) );
1443 }
1445 sub _parse_getSoftwareLicenseUsages {
1446 my $res = shift;
1448 # Parse Opsi result
1449 my $tmp_licensePool_cache = {};
1450 my $res_hash = { 'hit'=> [] };
1451 foreach my $license ( @{$res}) {
1452 my $tmp_licensePool = $license->{'licensePoolId'};
1453 if (not exists $tmp_licensePool_cache->{$tmp_licensePool}) {
1454 # Fetch missing informations from Opsi and cache the results for a possible later usage
1455 my ($res, $err) = &_getLicensePool_hash('licensePoolId'=>$tmp_licensePool);
1456 if (not $err) {
1457 $tmp_licensePool_cache->{$tmp_licensePool} = $res;
1458 }
1459 }
1460 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
1461 'notes' => [$license->{'notes'}],
1462 'licenseKey' => [$license->{'licenseKey'}],
1463 'hostId' => [$license->{'hostId'}],
1464 'licensePoolId' => [$tmp_licensePool],
1465 };
1466 if (exists $tmp_licensePool_cache->{$tmp_licensePool}) {
1467 $license_hash->{$tmp_licensePool} = {'productIds'=>[], 'windowsSoftwareIds'=>[]};
1468 map (push (@{$license_hash->{$tmp_licensePool}->{productIds}}, $_), @{$tmp_licensePool_cache->{$tmp_licensePool}->{productIds}});
1469 map (push (@{$license_hash->{$tmp_licensePool}->{windowsSoftwareIds}}, $_), @{$tmp_licensePool_cache->{$tmp_licensePool}->{windowsSoftwareIds}});
1470 }
1471 push( @{$res_hash->{hit}}, $license_hash );
1472 }
1474 return $res_hash;
1475 }
1477 ################################
1478 # @brief Returns softwareLicenseId, notes, licenseKey, hostId and licensePoolId for optional given licensePoolId and hostId
1479 # @param hostid Something like client_1.intranet.mydomain.de (optional).
1480 # @param licensePoolId The name of the pool (optional).
1481 sub opsi_getSoftwareLicenseUsages {
1482 my $startTime = Time::HiRes::time;
1483 my ($msg, $msg_hash, $session_id) = @_;
1484 my $header = @{$msg_hash->{'header'}}[0];
1485 my $source = @{$msg_hash->{'source'}}[0];
1486 my $target = @{$msg_hash->{'target'}}[0];
1487 my $licensePoolId = defined $msg_hash->{'licensePoolId'} ? @{$msg_hash->{'licensePoolId'}}[0] : undef;
1488 my $hostId = defined $msg_hash->{'hostId'} ? @{$msg_hash->{'hostId'}}[0] : undef;
1489 my $out_hash;
1491 my ($res, $err) = &_getSoftwareLicenseUsages_listOfHashes('licensePoolId'=>$licensePoolId, 'hostId'=>$hostId);
1492 if ($err){
1493 return &_giveErrorFeedback($msg_hash, "cannot fetch software licenses from license pool : ".$res, $session_id);
1494 }
1496 # Parse Opsi result
1497 my $res_hash = &_parse_getSoftwareLicenseUsages($res);
1499 # Create function result message
1500 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1501 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1502 $out_hash->{result} = [$res_hash];
1504 my $endTime = Time::HiRes::time;
1505 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1506 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1507 return ( &create_xml_string($out_hash) );
1508 }
1510 ################################
1511 # @brief Returns softwareLicenseId, notes, licenseKey, hostId and licensePoolId. Function return is identical to opsi_getSoftwareLicenseUsages
1512 # @param productId Something like 'firefox', 'python' or anything else .
1513 sub opsi_getSoftwareLicenseUsagesForProductId {
1514 my $startTime = Time::HiRes::time;
1515 my ($msg, $msg_hash, $session_id) = @_;
1516 my $header = @{$msg_hash->{'header'}}[0];
1517 my $source = @{$msg_hash->{'source'}}[0];
1519 # Check input sanity
1520 my $productId;
1521 if (&_check_xml_tag_is_ok ($msg_hash, 'productId')) {
1522 $productId= @{$msg_hash->{'productId'}}[0];
1523 } else {
1524 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1525 }
1527 # Fetch licensePoolId for productId
1528 my ($res, $err) = &_getLicensePoolId('productId'=>$productId);
1529 if ($err){
1530 return &_giveErrorFeedback($msg_hash, "cannot fetch licensePoolId for given productId : ".$res, $session_id);
1531 }
1533 my $licensePoolId;
1535 # Fetch softwareLiceceUsages for licensePoolId
1536 ($res, $err) = &_getSoftwareLicenseUsages_listOfHashes('licensePoolId'=>$licensePoolId);
1537 if ($err){
1538 return &_giveErrorFeedback($msg_hash, "cannot fetch software licenses from license pool : ".$res, $session_id);
1539 }
1541 # Parse Opsi result
1542 my $res_hash = &_parse_getSoftwareLicenseUsages($res);
1544 # Create function result message
1545 my $out_hash = &create_xml_hash("answer_$header", $main::server_address, $source);
1546 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1547 $out_hash->{result} = [$res_hash];
1549 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1550 return ( &create_xml_string($out_hash) );
1551 }
1553 ################################
1554 # @brief Returns expirationDate, boundToHost, maxInstallation, licenseTyp, licensePoolIds and licenseKeys for a given softwareLicense ID.
1555 # @param softwareLicenseId Identificator of a license.
1556 sub opsi_getSoftwareLicense_hash {
1557 my $startTime = Time::HiRes::time;
1558 my ($msg, $msg_hash, $session_id) = @_;
1559 my $header = @{$msg_hash->{'header'}}[0];
1560 my $source = @{$msg_hash->{'source'}}[0];
1561 my $target = @{$msg_hash->{'target'}}[0];
1562 my $softwareLicenseId;
1563 my $out_hash;
1565 # Check input sanity
1566 if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
1567 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
1568 } else {
1569 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1570 }
1572 my $callobj = {
1573 method => 'getSoftwareLicense_hash',
1574 params => [ $softwareLicenseId ],
1575 id => 1,
1576 };
1577 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1579 # Check Opsi error
1580 my ($res_error, $res_error_str) = &check_opsi_res($res);
1581 if ($res_error){
1582 # Create error message
1583 &main::daemon_log("$session_id ERROR: cannot fetch information for license '$softwareLicenseId': ".$res_error_str, 1);
1584 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1585 return ( &create_xml_string($out_hash) );
1586 }
1588 # Create function result message
1589 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1590 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1591 &add_content2xml_hash($out_hash, "expirationDate", $res->result->{'expirationDate'});
1592 &add_content2xml_hash($out_hash, "boundToHost", $res->result->{'boundToHost'});
1593 &add_content2xml_hash($out_hash, "maxInstallations", $res->result->{'maxInstallations'});
1594 &add_content2xml_hash($out_hash, "licenseTyp", $res->result->{'licenseTyp'});
1595 foreach my $licensePoolId ( @{$res->result->{'licensePoolIds'}}) {
1596 &add_content2xml_hash($out_hash, "licensePoolId", $licensePoolId);
1597 &add_content2xml_hash($out_hash, $licensePoolId, $res->result->{'licenseKeys'}->{$licensePoolId});
1598 }
1600 my $endTime = Time::HiRes::time;
1601 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1602 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1603 return ( &create_xml_string($out_hash) );
1604 }
1606 ################################
1607 # @brief Delete licnese pool by license pool ID. A pool can only be deleted if there are no software licenses bound to the pool.
1608 # The fixed parameter deleteLicenses=True specifies that all software licenses bound to the pool are being deleted.
1609 # @param licensePoolId The name of the pool.
1610 sub opsi_deleteLicensePool {
1611 my $startTime = Time::HiRes::time;
1612 my ($msg, $msg_hash, $session_id) = @_;
1613 my $header = @{$msg_hash->{'header'}}[0];
1614 my $source = @{$msg_hash->{'source'}}[0];
1615 my $target = @{$msg_hash->{'target'}}[0];
1616 my $licensePoolId;
1617 my $out_hash;
1619 # Check input sanity
1620 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1621 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1622 } else {
1623 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1624 }
1626 # Fetch softwareLicenseIds used in license pool
1627 # This has to be done because function deleteLicensePool deletes the pool and the corresponding software licenses
1628 # but not the license contracts of the software licenses. In our case each software license has exactly one license contract.
1629 my $callobj = {
1630 method => 'getSoftwareLicenses_listOfHashes',
1631 params => [ ],
1632 id => 1,
1633 };
1634 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1636 # Keep list of licenseContractIds in mind to delete it after the deletion of the software licenses
1637 my @lCI_toBeDeleted;
1638 foreach my $softwareLicenseHash ( @{$res->result} ) {
1639 if ((@{$softwareLicenseHash->{'licensePoolIds'}} == 0) || (@{$softwareLicenseHash->{'licensePoolIds'}}[0] ne $licensePoolId)) {
1640 next;
1641 }
1642 push (@lCI_toBeDeleted, $softwareLicenseHash->{'licenseContractId'});
1643 }
1645 # Delete license pool at Opsi server
1646 $callobj = {
1647 method => 'deleteLicensePool',
1648 params => [ $licensePoolId, 'deleteLicenses=True' ],
1649 id => 1,
1650 };
1651 $res = $main::opsi_client->call($main::opsi_url, $callobj);
1652 my ($res_error, $res_error_str) = &check_opsi_res($res);
1653 if ($res_error){
1654 # Create error message
1655 &main::daemon_log("$session_id ERROR: cannot delete license pool at Opsi server: ".$res_error_str, 1);
1656 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1657 return ( &create_xml_string($out_hash) );
1658 }
1660 # Delete each license contract connected with the license pool
1661 foreach my $licenseContractId ( @lCI_toBeDeleted ) {
1662 my $callobj = {
1663 method => 'deleteLicenseContract',
1664 params => [ $licenseContractId ],
1665 id => 1,
1666 };
1667 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1668 my ($res_error, $res_error_str) = &check_opsi_res($res);
1669 if ($res_error){
1670 # Create error message
1671 &main::daemon_log("$session_id ERROR: cannot delete license contract '$licenseContractId' connected with license pool '$licensePoolId' at Opsi server: ".$res_error_str, 1);
1672 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1673 return ( &create_xml_string($out_hash) );
1674 }
1675 }
1677 # Create function result message
1678 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1679 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1681 my $endTime = Time::HiRes::time;
1682 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1683 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1684 return ( &create_xml_string($out_hash) );
1685 }
1687 ################################
1688 # @brief Create a license contract, create a software license and add the software license to the license pool
1689 # @param licensePoolId The name of the pool the license should be assigned.
1690 # @param licenseKey The license key.
1691 # @param partner Name of the license partner (optional).
1692 # @param conclusionDate Date of conclusion of license contract (optional)
1693 # @param notificationDate Date of notification that license is running out soon (optional).
1694 # @param notes This is the place for some notes (optional)
1695 # @param softwareLicenseId Identificator of a license (optional).
1696 # @param licenseTyp Typ of a licnese, either "OEM", "VOLUME" or "RETAIL" (optional).
1697 # @param maxInstallations The number of clients use this license (optional).
1698 # @param boundToHost The name of the client the license is bound to (optional).
1699 # @param expirationDate The date when the license is running down (optional).
1700 sub opsi_createLicense {
1701 my $startTime = Time::HiRes::time;
1702 my ($msg, $msg_hash, $session_id) = @_;
1703 my $header = @{$msg_hash->{'header'}}[0];
1704 my $source = @{$msg_hash->{'source'}}[0];
1705 my $target = @{$msg_hash->{'target'}}[0];
1706 my $partner = defined $msg_hash->{'partner'} ? @{$msg_hash->{'partner'}}[0] : undef;
1707 my $conclusionDate = defined $msg_hash->{'conclusionDate'} ? @{$msg_hash->{'conclusionDate'}}[0] : undef;
1708 my $notificationDate = defined $msg_hash->{'notificationDate'} ? @{$msg_hash->{'notificationDate'}}[0] : undef;
1709 my $notes = defined $msg_hash->{'notes'} ? @{$msg_hash->{'notes'}}[0] : undef;
1710 my $licenseContractId = undef;
1711 my $softwareLicenseId = defined $msg_hash->{'softwareLicenseId'} ? @{$msg_hash->{'softwareLicenseId'}}[0] : undef;
1712 my $licenseType = defined $msg_hash->{'licenseType'} ? @{$msg_hash->{'licenseType'}}[0] : undef;
1713 my $maxInstallations = defined $msg_hash->{'maxInstallations'} ? @{$msg_hash->{'maxInstallations'}}[0] : undef;
1714 my $boundToHost = defined $msg_hash->{'boundToHost'} ? @{$msg_hash->{'boundToHost'}}[0] : undef;
1715 my $expirationDate = defined $msg_hash->{'expirationDate'} ? @{$msg_hash->{'expirationDate'}}[0] : undef;
1716 my $licensePoolId;
1717 my $licenseKey;
1718 my $out_hash;
1720 # Check input sanity
1721 if (&_check_xml_tag_is_ok ($msg_hash, 'licenseKey')) {
1722 $licenseKey = @{$msg_hash->{'licenseKey'}}[0];
1723 } else {
1724 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1725 }
1726 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1727 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1728 } else {
1729 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1730 }
1731 if ((defined $licenseType) && (not exists $licenseTyp_hash->{$licenseType})) {
1732 return &_giveErrorFeedback($msg_hash, "The typ of a license can be either 'OEM', 'VOLUME' or 'RETAIL'.", $session_id);
1733 }
1735 # Automatically define licenseContractId if ID is not given
1736 if (defined $softwareLicenseId) {
1737 $licenseContractId = "c_".$softwareLicenseId;
1738 }
1740 # Create license contract at Opsi server
1741 my $callobj = {
1742 method => 'createLicenseContract',
1743 params => [ $licenseContractId, $partner, $conclusionDate, $notificationDate, undef, $notes ],
1744 id => 1,
1745 };
1746 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1748 # Check Opsi error
1749 my ($res_error, $res_error_str) = &check_opsi_res($res);
1750 if ($res_error){
1751 # Create error message
1752 &main::daemon_log("$session_id ERROR: cannot create license contract at Opsi server: ".$res_error_str, 1);
1753 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1754 return ( &create_xml_string($out_hash) );
1755 }
1757 $licenseContractId = $res->result;
1759 # Create software license at Opsi server
1760 $callobj = {
1761 method => 'createSoftwareLicense',
1762 params => [ $softwareLicenseId, $licenseContractId, $licenseType, $maxInstallations, $boundToHost, $expirationDate ],
1763 id => 1,
1764 };
1765 $res = $main::opsi_client->call($main::opsi_url, $callobj);
1767 # Check Opsi error
1768 ($res_error, $res_error_str) = &check_opsi_res($res);
1769 if ($res_error){
1770 # Create error message
1771 &main::daemon_log("$session_id ERROR: cannot create software license at Opsi server: ".$res_error_str, 1);
1772 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1773 return ( &create_xml_string($out_hash) );
1774 }
1776 $softwareLicenseId = $res->result;
1778 # Add software license to license pool
1779 $callobj = {
1780 method => 'addSoftwareLicenseToLicensePool',
1781 params => [ $softwareLicenseId, $licensePoolId, $licenseKey ],
1782 id => 1,
1783 };
1784 $res = $main::opsi_client->call($main::opsi_url, $callobj);
1786 # Check Opsi error
1787 ($res_error, $res_error_str) = &check_opsi_res($res);
1788 if ($res_error){
1789 # Create error message
1790 &main::daemon_log("$session_id ERROR: cannot add software license to license pool at Opsi server: ".$res_error_str, 1);
1791 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1792 return ( &create_xml_string($out_hash) );
1793 }
1795 # Create function result message
1796 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1797 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1799 my $endTime = Time::HiRes::time;
1800 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1801 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1802 return ( &create_xml_string($out_hash) );
1803 }
1805 ################################
1806 # @brief Assign a software license to a host
1807 # @param hostid Something like client_1.intranet.mydomain.de
1808 # @param licensePoolId The name of the pool.
1809 sub opsi_assignSoftwareLicenseToHost {
1810 my $startTime = Time::HiRes::time;
1811 my ($msg, $msg_hash, $session_id) = @_;
1812 my $header = @{$msg_hash->{'header'}}[0];
1813 my $source = @{$msg_hash->{'source'}}[0];
1814 my $target = @{$msg_hash->{'target'}}[0];
1815 my $hostId;
1816 my $licensePoolId;
1818 # Check input sanity
1819 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1820 $hostId = @{$msg_hash->{'hostId'}}[0];
1821 } else {
1822 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1823 }
1824 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1825 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1826 } else {
1827 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1828 }
1830 # Assign a software license to a host
1831 my $callobj = {
1832 method => 'getAndAssignSoftwareLicenseKey',
1833 params => [ $hostId, $licensePoolId ],
1834 id => 1,
1835 };
1836 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1838 # Check Opsi error
1839 my ($res_error, $res_error_str) = &check_opsi_res($res);
1840 if ($res_error){
1841 # Create error message
1842 &main::daemon_log("$session_id ERROR: cannot assign a software license to a host at Opsi server: ".$res_error_str, 1);
1843 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1844 return ( &create_xml_string($out_hash) );
1845 }
1847 # Create function result message
1848 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1849 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1851 my $endTime = Time::HiRes::time;
1852 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1853 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1854 return ( &create_xml_string($out_hash) );
1855 }
1857 ################################
1858 # @brief Unassign a software license from a host.
1859 # @param hostid Something like client_1.intranet.mydomain.de
1860 # @param licensePoolId The name of the pool.
1861 sub opsi_unassignSoftwareLicenseFromHost {
1862 my $startTime = Time::HiRes::time;
1863 my ($msg, $msg_hash, $session_id) = @_;
1864 my $header = @{$msg_hash->{'header'}}[0];
1865 my $source = @{$msg_hash->{'source'}}[0];
1866 my $target = @{$msg_hash->{'target'}}[0];
1867 my $hostId;
1868 my $licensePoolId;
1870 # Check input sanity
1871 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1872 $hostId = @{$msg_hash->{'hostId'}}[0];
1873 } else {
1874 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1875 }
1876 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1877 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1878 } else {
1879 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1880 }
1882 # Unassign a software license from a host
1883 my $callobj = {
1884 method => 'deleteSoftwareLicenseUsage',
1885 params => [ $hostId, '', $licensePoolId ],
1886 id => 1,
1887 };
1888 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1890 # Check Opsi error
1891 my ($res_error, $res_error_str) = &check_opsi_res($res);
1892 if ($res_error){
1893 # Create error message
1894 &main::daemon_log("$session_id ERROR: cannot unassign a software license from a host at Opsi server: ".$res_error_str, 1);
1895 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1896 return ( &create_xml_string($out_hash) );
1897 }
1899 # Create function result message
1900 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1901 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1903 my $endTime = Time::HiRes::time;
1904 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1905 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1906 return ( &create_xml_string($out_hash) );
1907 }
1909 ################################
1910 # @brief Unassign all software licenses from a host
1911 # @param hostid Something like client_1.intranet.mydomain.de
1912 sub opsi_unassignAllSoftwareLicensesFromHost {
1913 my $startTime = Time::HiRes::time;
1914 my ($msg, $msg_hash, $session_id) = @_;
1915 my $header = @{$msg_hash->{'header'}}[0];
1916 my $source = @{$msg_hash->{'source'}}[0];
1917 my $target = @{$msg_hash->{'target'}}[0];
1918 my $hostId;
1920 # Check input sanity
1921 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1922 $hostId = @{$msg_hash->{'hostId'}}[0];
1923 } else {
1924 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1925 }
1927 # Unassign all software licenses from a host
1928 my $callobj = {
1929 method => 'deleteAllSoftwareLicenseUsages',
1930 params => [ $hostId ],
1931 id => 1,
1932 };
1933 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1935 # Check Opsi error
1936 my ($res_error, $res_error_str) = &check_opsi_res($res);
1937 if ($res_error){
1938 # Create error message
1939 &main::daemon_log("$session_id ERROR: cannot unassign a software license from a host at Opsi server: ".$res_error_str, 1);
1940 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1941 return ( &create_xml_string($out_hash) );
1942 }
1944 # Create function result message
1945 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1946 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1948 my $endTime = Time::HiRes::time;
1949 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1950 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1951 return ( &create_xml_string($out_hash) );
1952 }
1955 ################################
1956 # @brief Returns the assigned licensePoolId and licenses, how often the product is installed and at which host
1957 # and the number of max and remaining installations for a given OPSI product.
1958 # @param productId Identificator of an OPSI product.
1959 sub opsi_getLicenseInformationForProduct {
1960 my $startTime = Time::HiRes::time;
1961 my ($msg, $msg_hash, $session_id) = @_;
1962 my $header = @{$msg_hash->{'header'}}[0];
1963 my $source = @{$msg_hash->{'source'}}[0];
1964 my $productId;
1965 my $out_hash;
1967 # Check input sanity
1968 if (&_check_xml_tag_is_ok ($msg_hash, 'productId')) {
1969 $productId = @{$msg_hash->{'productId'}}[0];
1970 } else {
1971 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1972 }
1974 # Fetch infos from Opsi server
1975 my $callobj = {
1976 method => 'getLicensePoolId',
1977 params => [ $productId ],
1978 id => 1,
1979 };
1980 #my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1981 my $res = $opsi_client->call($opsi_url, $callobj);
1983 # Check Opsi error
1984 my ($res_error, $res_error_str) = &check_opsi_res($res);
1985 if ($res_error){
1986 return &_giveErrorFeedback($msg_hash, "cannot get license pool for product '$productId' : ".$res_error_str, $session_id);
1987 }
1989 my $licensePoolId = $res->result;
1991 # Fetch statistic information for given pool ID
1992 $callobj = {
1993 method => 'getLicenseStatistics_hash',
1994 params => [ ],
1995 id => 1,
1996 };
1997 $res = $opsi_client->call($opsi_url, $callobj);
1999 # Check Opsi error
2000 ($res_error, $res_error_str) = &check_opsi_res($res);
2001 if ($res_error){
2002 # Create error message
2003 &main::daemon_log("$session_id ERROR: cannot get statistic informations for license pools : ".$res_error_str, 1);
2004 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
2005 return ( &create_xml_string($out_hash) );
2006 }
2008 # Create function result message
2009 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2010 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2011 &add_content2xml_hash($out_hash, "licensePoolId", $licensePoolId);
2012 &add_content2xml_hash($out_hash, "licenses", $res->result->{$licensePoolId}->{'licenses'});
2013 &add_content2xml_hash($out_hash, "usageCount", $res->result->{$licensePoolId}->{'usageCount'});
2014 &add_content2xml_hash($out_hash, "maxInstallations", $res->result->{$licensePoolId}->{'maxInstallations'});
2015 &add_content2xml_hash($out_hash, "remainingInstallations", $res->result->{$licensePoolId}->{'remainingInstallations'});
2016 map(&add_content2xml_hash($out_hash, "usedBy", "$_"), @{ $res->result->{$licensePoolId}->{'usedBy'}});
2018 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
2019 return ( &create_xml_string($out_hash) );
2020 }
2023 ################################
2024 # @brief Returns licensePoolId, description, a list of productIds, al list of windowsSoftwareIds and a list of licenses for a given licensePoolId.
2025 # Each license contains softwareLicenseId, maxInstallations, licenseType, licensePoolIds, licenseKeys, hostIds, expirationDate, boundToHost and licenseContractId.
2026 # The licenseContract contains conclusionDate, expirationDate, notes, notificationDate and partner.
2027 # @param licensePoolId The name of the pool.
2028 sub opsi_getPool {
2029 my $startTime = Time::HiRes::time;
2030 my ($msg, $msg_hash, $session_id) = @_;
2031 my $header = @{$msg_hash->{'header'}}[0];
2032 my $source = @{$msg_hash->{'source'}}[0];
2034 # Check input sanity
2035 my $licensePoolId;
2036 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
2037 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
2038 } else {
2039 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2040 }
2042 # Create hash for the answer
2043 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2044 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2046 # Call Opsi
2047 my ($res, $err) = &_getLicensePool_hash( 'licensePoolId'=> $licensePoolId );
2048 if ($err){
2049 return &_giveErrorFeedback($msg_hash, "cannot get license pool from Opsi server: ".$res, $session_id);
2050 }
2051 # Add data to outgoing hash
2052 &add_content2xml_hash($out_hash, "licensePoolId", $res->{'licensePoolId'});
2053 &add_content2xml_hash($out_hash, "description", $res->{'description'});
2054 map(&add_content2xml_hash($out_hash, "productIds", "$_"), @{ $res->{'productIds'} });
2055 map(&add_content2xml_hash($out_hash, "windowsSoftwareIds", "$_"), @{ $res->{'windowsSoftwareIds'} });
2058 # Call Opsi two times
2059 my ($usages_res, $usages_err) = &_getSoftwareLicenseUsages_listOfHashes('licensePoolId'=>$licensePoolId);
2060 if ($usages_err){
2061 return &_giveErrorFeedback($msg_hash, "cannot get software license usage information from Opsi server: ".$usages_res, $session_id);
2062 }
2063 my ($licenses_res, $licenses_err) = &_getSoftwareLicenses_listOfHashes();
2064 if ($licenses_err){
2065 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server: ".$licenses_res, $session_id);
2066 }
2068 # Add data to outgoing hash
2069 # Parse through all software licenses and select those associated to the pool
2070 my $res_hash = { 'hit'=> [] };
2071 foreach my $license ( @$licenses_res) {
2072 # Each license hash has a list of licensePoolIds so go through this list and search for matching licensePoolIds
2073 my $found = 0;
2074 my @licensePoolIds_list = @{$license->{licensePoolIds}};
2075 foreach my $lPI ( @licensePoolIds_list) {
2076 if ($lPI eq $licensePoolId) { $found++ }
2077 }
2078 if (not $found ) { next; };
2079 # Found matching licensePoolId
2080 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
2081 'licenseKeys' => {},
2082 'expirationDate' => [$license->{'expirationDate'}],
2083 'boundToHost' => [$license->{'boundToHost'}],
2084 'maxInstallations' => [$license->{'maxInstallations'}],
2085 'licenseType' => [$license->{'licenseType'}],
2086 'licenseContractId' => [$license->{'licenseContractId'}],
2087 'licensePoolIds' => [],
2088 'hostIds' => [],
2089 };
2090 foreach my $licensePoolId (@{ $license->{'licensePoolIds'}}) {
2091 push( @{$license_hash->{'licensePoolIds'}}, $licensePoolId);
2092 $license_hash->{licenseKeys}->{$licensePoolId} = [ $license->{'licenseKeys'}->{$licensePoolId} ];
2093 }
2094 foreach my $usage (@$usages_res) {
2095 # Search for hostIds with matching softwareLicenseId
2096 if ($license->{'softwareLicenseId'} eq $usage->{'softwareLicenseId'}) {
2097 push( @{ $license_hash->{hostIds}}, $usage->{hostId});
2098 }
2099 }
2101 # Each softwareLicenseId has one licenseContractId, fetch contract details for each licenseContractId
2102 my ($lContract_res, $lContract_err) = &_getLicenseContract_hash('licenseContractId'=>$license->{licenseContractId});
2103 if ($lContract_err){
2104 return &_giveErrorFeedback($msg_hash, "cannot get software license contract information from Opsi server: ".$licenses_res, $session_id);
2105 }
2106 $license_hash->{$license->{'licenseContractId'}} = [];
2107 my $licenseContract_hash = { 'conclusionDate' => [$lContract_res->{conclusionDate}],
2108 'notificationDate' => [$lContract_res->{notificationDate}],
2109 'notes' => [$lContract_res->{notes}],
2110 'exirationDate' => [$lContract_res->{expirationDate}],
2111 'partner' => [$lContract_res->{partner}],
2112 };
2113 push( @{$license_hash->{licenseContractData}}, $licenseContract_hash );
2115 push( @{$res_hash->{hit}}, $license_hash );
2116 }
2117 $out_hash->{licenses} = [$res_hash];
2119 my $endTime = Time::HiRes::time;
2120 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2121 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2122 return ( &create_xml_string($out_hash) );
2123 }
2126 ################################
2127 # @brief Removes at first the software license from license pool and than deletes the software license.
2128 # Attention, the software license has to exists otherwise it will lead to an Opsi internal server error.
2129 # @param softwareLicenseId Identificator of a license.
2130 # @param licensePoolId The name of the pool.
2131 sub opsi_removeLicense {
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 $softwareLicenseId;
2139 if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
2140 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
2141 } else {
2142 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2143 }
2144 my $licensePoolId;
2145 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
2146 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
2147 } else {
2148 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2149 }
2151 # Call Opsi
2152 my ($res, $err) = &_removeSoftwareLicenseFromLicensePool( 'licensePoolId' => $licensePoolId, 'softwareLicenseId' => $softwareLicenseId );
2153 if ($err){
2154 return &_giveErrorFeedback($msg_hash, "cannot delete software license from pool: ".$res, $session_id);
2155 }
2157 # Call Opsi
2158 ($res, $err) = &_deleteSoftwareLicense( 'softwareLicenseId'=>$softwareLicenseId );
2159 if ($err){
2160 return &_giveErrorFeedback($msg_hash, "cannot delete software license from Opsi server: ".$res, $session_id);
2161 }
2163 # Create hash for the answer
2164 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2165 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2166 my $endTime = Time::HiRes::time;
2167 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2168 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2169 return ( &create_xml_string($out_hash) );
2170 }
2173 ################################
2174 # @brief Return softwareLicenseId, maxInstallations, licenseType, licensePoolIds, licenseContractId, expirationDate, boundToHost and a list of productIds.
2175 # @param hostId Something like client_1.intranet.mydomain.de
2176 sub opsi_getReservedLicenses {
2177 my $startTime = Time::HiRes::time;
2178 my ($msg, $msg_hash, $session_id) = @_;
2179 my $header = @{$msg_hash->{'header'}}[0];
2180 my $source = @{$msg_hash->{'source'}}[0];
2182 # Check input sanity
2183 my $hostId;
2184 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
2185 $hostId = @{$msg_hash->{'hostId'}}[0];
2186 } else {
2187 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2188 }
2190 # Fetch informations from Opsi server
2191 my ($license_res, $license_err) = &_getSoftwareLicenses_listOfHashes();
2192 if ($license_err){
2193 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server: ".$license_res, $session_id);
2194 }
2196 # Parse result
2197 my $res_hash = { 'hit'=> [] };
2198 foreach my $license ( @$license_res) {
2199 if ($license->{boundToHost} ne $hostId) { next; }
2201 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
2202 'maxInstallations' => [$license->{'maxInstallations'}],
2203 'boundToHost' => [$license->{'boundToHost'}],
2204 'expirationDate' => [$license->{'expirationDate'}],
2205 'licenseContractId' => [$license->{'licenseContractId'}],
2206 'licenseType' => [$license->{'licenseType'}],
2207 'licensePoolIds' => [],
2208 };
2210 foreach my $licensePoolId (@{$license->{'licensePoolIds'}}) {
2211 # Fetch information for license pools containing a software license which is bound to given host
2212 my ($pool_res, $pool_err) = &_getLicensePool_hash( 'licensePoolId'=>$licensePoolId );
2213 if ($pool_err){
2214 return &_giveErrorFeedback($msg_hash, "cannot get license pool from Opsi server: ".$pool_res, $session_id);
2215 }
2217 # Add licensePool information to result hash
2218 push (@{$license_hash->{licensePoolIds}}, $licensePoolId);
2219 $license_hash->{$licensePoolId} = {'productIds'=>[], 'windowsSoftwareIds'=>[]};
2220 map (push (@{$license_hash->{$licensePoolId}->{productIds}}, $_), @{$pool_res->{productIds}});
2221 map (push (@{$license_hash->{$licensePoolId}->{windowsSoftwareIds}}, $_), @{$pool_res->{windowsSoftwareIds}});
2222 }
2223 push( @{$res_hash->{hit}}, $license_hash );
2224 }
2225 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2226 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2227 $out_hash->{licenses} = [$res_hash];
2229 my $endTime = Time::HiRes::time;
2230 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2231 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2232 return ( &create_xml_string($out_hash) );
2233 }
2235 ################################
2236 # @brief Bound the given softwareLicenseId to the given host.
2237 # @param hostId Opsi hostId
2238 # @param softwareLicenseId Identificator of a license (optional).
2239 sub opsi_boundHostToLicense {
2240 my $startTime = Time::HiRes::time;
2241 my ($msg, $msg_hash, $session_id) = @_;
2242 my $header = @{$msg_hash->{'header'}}[0];
2243 my $source = @{$msg_hash->{'source'}}[0];
2245 # Check input sanity
2246 my $hostId;
2247 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
2248 $hostId = @{$msg_hash->{'hostId'}}[0];
2249 } else {
2250 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2251 }
2252 my $softwareLicenseId;
2253 if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
2254 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
2255 } else {
2256 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2257 }
2259 # Fetch informations from Opsi server
2260 my ($license_res, $license_err) = &_getSoftwareLicenses_listOfHashes();
2261 if ($license_err){
2262 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server: ".$license_res, $session_id);
2263 }
2265 # Memorize parameter for given softwareLicenseId
2266 my $licenseContractId;
2267 my $licenseType;
2268 my $maxInstallations;
2269 my $boundToHost;
2270 my $expirationDate = "";
2271 my $found;
2272 foreach my $license (@$license_res) {
2273 if ($license->{softwareLicenseId} ne $softwareLicenseId) { next; }
2274 $licenseContractId = $license->{licenseContractId};
2275 $licenseType = $license->{licenseType};
2276 $maxInstallations = $license->{maxInstallations};
2277 $expirationDate = $license->{expirationDate};
2278 $found++;
2279 }
2281 if (not $found) {
2282 return &_giveErrorFeedback($msg_hash, "no softwarelicenseId found with name '".$softwareLicenseId."'", $session_id);
2283 }
2285 # Set boundToHost option for a given software license
2286 my ($bound_res, $bound_err) = &_createSoftwareLicense('softwareLicenseId'=>$softwareLicenseId,
2287 'licenseContractId' => $licenseContractId,
2288 'licenseType' => $licenseType,
2289 'maxInstallations' => $maxInstallations,
2290 'boundToHost' => $hostId,
2291 'expirationDate' => $expirationDate);
2292 if ($bound_err) {
2293 return &_giveErrorFeedback($msg_hash, "cannot set boundToHost for given softwareLicenseId and hostId: ".$bound_res, $session_id);
2294 }
2296 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2297 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2299 my $endTime = Time::HiRes::time;
2300 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2301 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2302 return ( &create_xml_string($out_hash) );
2303 }
2305 ################################
2306 # @brief Release a software license formerly bound to a host.
2307 # @param softwareLicenseId Identificator of a license.
2308 sub opsi_unboundHostFromLicense {
2309 # This is really mad! Opsi is not able to unbound a lincense from a host. To provide the functionality for GOsa
2310 # 4 rpc calls to Opsi are necessary. First, fetch all data for the given softwareLicenseId, then all details for the associated
2311 # licenseContractId, then delete the softwareLicense and finally recreate the softwareLicense without the boundToHost option. NASTY!
2312 my $startTime = Time::HiRes::time;
2313 my ($msg, $msg_hash, $session_id) = @_;
2314 my $header = @{$msg_hash->{'header'}}[0];
2315 my $source = @{$msg_hash->{'source'}}[0];
2317 # Check input sanity
2318 my $softwareLicenseId;
2319 if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
2320 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
2321 } else {
2322 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2323 }
2325 # Memorize parameter witch are required for this procedure
2326 my $licenseContractId;
2327 my $licenseType;
2328 my $maxInstallations;
2329 my $expirationDate;
2330 my $partner;
2331 my $conclusionDate;
2332 my $notificationDate;
2333 my $notes;
2334 my $licensePoolId;
2335 my $licenseKey;
2337 # Fetch license informations from Opsi server
2338 my ($license_res, $license_err) = &_getSoftwareLicenses_listOfHashes();
2339 if ($license_err){
2340 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server, required to unbound license from host: ".$license_res, $session_id);
2341 }
2342 my $found = 0;
2343 foreach my $license (@$license_res) {
2344 if (($found > 0) || ($license->{softwareLicenseId} ne $softwareLicenseId)) { next; }
2345 $licenseContractId = $license->{licenseContractId};
2346 $licenseType = $license->{licenseType};
2347 $maxInstallations = $license->{maxInstallations};
2348 $expirationDate = $license->{expirationDate};
2349 $licensePoolId = @{$license->{licensePoolIds}}[0];
2350 $licenseKey = $license->{licenseKeys}->{$licensePoolId};
2351 $found++;
2352 }
2354 # Fetch contract informations from Opsi server
2355 my ($contract_res, $contract_err) = &_getLicenseContract_hash('licenseContractId'=>$licenseContractId);
2356 if ($contract_err){
2357 return &_giveErrorFeedback($msg_hash, "cannot get contract license information from Opsi server, required to unbound license from host: ".$license_res, $session_id);
2358 }
2359 $partner = $contract_res->{partner};
2360 $conclusionDate = $contract_res->{conclusionDate};
2361 $notificationDate = $contract_res->{notificationDate};
2362 $expirationDate = $contract_res->{expirationDate};
2363 $notes = $contract_res->{notes};
2365 # Delete software license
2366 my ($res, $err) = &_deleteSoftwareLicense( 'softwareLicenseId' => $softwareLicenseId, 'removeFromPools'=> "true" );
2367 if ($err) {
2368 return &_giveErrorFeedback($msg_hash, "cannot delet license from Opsi server, required to unbound license from host : ".$res, $session_id);
2369 }
2371 # Recreate software license without boundToHost
2372 ($res, $err) = &_createLicenseContract( 'licenseContractId' => $licenseContractId, 'partner' => $partner, 'conclusionDate' => $conclusionDate,
2373 'notificationDate' => $notificationDate, 'expirationDate' => $expirationDate, 'notes' => $notes );
2374 if ($err) {
2375 return &_giveErrorFeedback($msg_hash, "cannot create license contract at Opsi server, required to unbound license from host : ".$res, $session_id);
2376 }
2377 ($res, $err) = &_createSoftwareLicense( 'softwareLicenseId' => $softwareLicenseId, 'licenseContractId' => $licenseContractId, 'licenseType' => $licenseType,
2378 'maxInstallations' => $maxInstallations, 'boundToHost' => "", 'expirationDate' => $expirationDate );
2379 if ($err) {
2380 return &_giveErrorFeedback($msg_hash, "cannot create software license at Opsi server, required to unbound license from host : ".$res, $session_id);
2381 }
2382 ($res, $err) = &_addSoftwareLicenseToLicensePool( 'softwareLicenseId' => $softwareLicenseId, 'licensePoolId' => $licensePoolId, 'licenseKey' => $licenseKey );
2383 if ($err) {
2384 return &_giveErrorFeedback($msg_hash, "cannot add software license to license pool at Opsi server, required to unbound license from host : ".$res, $session_id);
2385 }
2387 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2388 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2390 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
2391 return ( &create_xml_string($out_hash) );
2392 }
2394 ################################
2395 # @brief Returns a list of licenses with softwaerLicenseId, maxInstallations, boundToHost, expirationDate, licenseContractId, licenseType, a list of licensePoolIds with associated licenseKeys
2396 sub opsi_getAllSoftwareLicenses {
2397 my $startTime = Time::HiRes::time;
2398 my ($msg, $msg_hash, $session_id) = @_;
2399 my $header = @{$msg_hash->{'header'}}[0];
2400 my $source = @{$msg_hash->{'source'}}[0];
2402 my ($res, $err) = &_getSoftwareLicenses_listOfHashes();
2403 if ($err) {
2404 return &_giveErrorFeedback($msg_hash, "cannot fetch software licenses from Opsi server : ".$res, $session_id);
2405 }
2407 # Parse result
2408 my $res_hash = { 'hit'=> [] };
2409 foreach my $license ( @$res) {
2410 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
2411 'maxInstallations' => [$license->{'maxInstallations'}],
2412 'boundToHost' => [$license->{'boundToHost'}],
2413 'expirationDate' => [$license->{'expirationDate'}],
2414 'licenseContractId' => [$license->{'licenseContractId'}],
2415 'licenseType' => [$license->{'licenseType'}],
2416 'licensePoolIds' => [],
2417 'licenseKeys'=> {}
2418 };
2419 foreach my $licensePoolId (@{$license->{'licensePoolIds'}}) {
2420 push( @{$license_hash->{'licensePoolIds'}}, $licensePoolId);
2421 $license_hash->{licenseKeys}->{$licensePoolId} = [ $license->{'licenseKeys'}->{$licensePoolId} ];
2422 }
2423 push( @{$res_hash->{hit}}, $license_hash );
2424 }
2426 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2427 $out_hash->{licenses} = [$res_hash];
2428 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2430 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
2431 return ( &create_xml_string($out_hash) );
2432 }
2434 sub opsi_test {
2435 my ($msg, $msg_hash, $session_id) = @_;
2436 my $header = @{$msg_hash->{'header'}}[0];
2437 my $source = @{$msg_hash->{'source'}}[0];
2438 my $pram1 = @{$msg_hash->{'productId'}}[0];
2440 print STDERR Dumper $pram1;
2442 # Fetch infos from Opsi server
2443 my $callobj = {
2444 method => 'getLicensePoolId',
2445 params => [ $pram1 ],
2446 id => 1,
2447 };
2448 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
2450 print STDERR Dumper $res;
2451 return ();
2452 }
2455 # ----------------------------------------------------------------------------
2456 # internal methods handling the comunication with Opsi
2457 # ----------------------------------------------------------------------------
2459 ################################
2460 # @brief Checks if there is a specified tag and if the the tag has a content.
2461 sub _check_xml_tag_is_ok {
2462 my ($msg_hash,$tag) = @_;
2463 if (not defined $msg_hash->{$tag}) {
2464 $_ = "message contains no tag '$tag'";
2465 return 0;
2466 }
2467 if (ref @{$msg_hash->{$tag}}[0] eq 'HASH') {
2468 $_ = "message tag '$tag' has no content";
2469 return 0;
2470 }
2471 return 1;
2472 }
2474 ################################
2475 # @brief Writes the log line and returns the error message for GOsa.
2476 sub _giveErrorFeedback {
2477 my ($msg_hash, $err_string, $session_id) = @_;
2478 &main::daemon_log("$session_id ERROR: $err_string", 1);
2479 my $out_hash = &main::create_xml_hash("error", $main::server_address, @{$msg_hash->{source}}[0], $err_string);
2480 if (exists $msg_hash->{forward_to_gosa}) {
2481 &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]);
2482 }
2483 return ( &create_xml_string($out_hash) );
2484 }
2487 ################################
2488 # @brief Perform the call to the Opsi server and measure the time for the call
2489 sub _callOpsi {
2490 my %arg = ('method'=>undef, 'params'=>[], 'id'=>1, @_);
2492 my $callObject = {
2493 method => $arg{method},
2494 params => $arg{params},
2495 id => $arg{id},
2496 };
2498 my $startTime = Time::HiRes::time;
2499 my $opsiResult = $opsi_client->call($opsi_url, $callObject);
2500 my $endTime = Time::HiRes::time;
2501 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2503 &main::daemon_log("0 DEBUG: time to process opsi call '$arg{method}' : $elapsedTime seconds", 1034);
2505 return $opsiResult;
2506 }
2508 sub _getLicensePool_hash {
2509 my %arg = ( 'licensePoolId' => undef, @_ );
2511 if (not defined $arg{licensePoolId} ) {
2512 return ("function requires licensePoolId as parameter", 1);
2513 }
2515 my $res = &_callOpsi( method => 'getLicensePool_hash', params =>[$arg{licensePoolId}], id => 1 );
2516 my ($res_error, $res_error_str) = &check_opsi_res($res);
2517 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2519 return ($res->result, 0);
2520 }
2522 sub _getSoftwareLicenses_listOfHashes {
2524 my $res = &_callOpsi( method => 'getSoftwareLicenses_listOfHashes' );
2525 my ($res_error, $res_error_str) = &check_opsi_res($res);
2526 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2528 return ($res->result, 0);
2529 }
2531 sub _getSoftwareLicenseUsages_listOfHashes {
2532 my %arg = ( 'hostId' => "", 'licensePoolId' => "", @_ );
2534 my $res = &_callOpsi( method=>'getSoftwareLicenseUsages_listOfHashes', params=>[ $arg{hostId}, $arg{licensePoolId} ] );
2535 my ($res_error, $res_error_str) = &check_opsi_res($res);
2536 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2538 return ($res->result, 0);
2539 }
2541 sub _removeSoftwareLicenseFromLicensePool {
2542 my %arg = ( 'softwareLicenseId' => undef, 'licensePoolId' => undef, @_ );
2544 if (not defined $arg{softwareLicenseId} ) {
2545 return ("function requires softwareLicenseId as parameter", 1);
2546 }
2547 if (not defined $arg{licensePoolId} ) {
2548 return ("function requires licensePoolId as parameter", 1);
2549 }
2551 my $res = &_callOpsi( method=>'removeSoftwareLicenseFromLicensePool', params=>[ $arg{softwareLicenseId}, $arg{licensePoolId} ] );
2552 my ($res_error, $res_error_str) = &check_opsi_res($res);
2553 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2555 return ($res->result, 0);
2556 }
2558 sub _deleteSoftwareLicense {
2559 my %arg = ( 'softwareLicenseId' => undef, 'removeFromPools' => "false", @_ );
2561 if (not defined $arg{softwareLicenseId} ) {
2562 return ("function requires softwareLicenseId as parameter", 1);
2563 }
2564 my $removeFromPools = "";
2565 if ((defined $arg{removeFromPools}) && ($arg{removeFromPools} eq "true")) {
2566 $removeFromPools = "removeFromPools";
2567 }
2569 my $res = &_callOpsi( method=>'deleteSoftwareLicense', params=>[ $arg{softwareLicenseId}, $removeFromPools ] );
2570 my ($res_error, $res_error_str) = &check_opsi_res($res);
2571 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2573 return ($res->result, 0);
2574 }
2576 sub _getLicensePoolId {
2577 my %arg = ( 'productId' => undef, @_ );
2579 if (not defined $arg{productId} ) {
2580 return ("function requires productId as parameter", 1);
2581 }
2583 my $res = &_callOpsi( method => 'getLicensePoolId', params => [ $arg{productId} ] );
2584 my ($res_error, $res_error_str) = &check_opsi_res($res);
2585 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2587 return ($res->result, 0);
2588 }
2590 sub _getLicenseContract_hash {
2591 my %arg = ( 'licenseContractId' => undef, @_ );
2593 if (not defined $arg{licenseContractId} ) {
2594 return ("function requires licenseContractId as parameter", 1);
2595 }
2597 my $res = &_callOpsi( method => 'getLicenseContract_hash', params => [ $arg{licenseContractId} ] );
2598 my ($res_error, $res_error_str) = &check_opsi_res($res);
2599 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2601 return ($res->result, 0);
2602 }
2604 sub _createLicenseContract {
2605 my %arg = (
2606 'licenseContractId' => undef,
2607 'partner' => undef,
2608 'conclusionDate' => undef,
2609 'notificationDate' => undef,
2610 'expirationDate' => undef,
2611 'notes' => undef,
2612 @_ );
2614 my $res = &_callOpsi( method => 'createLicenseContract',
2615 params => [ $arg{licenseContractId}, $arg{partner}, $arg{conclusionDate}, $arg{notificationDate}, $arg{expirationDate}, $arg{notes} ],
2616 );
2617 my ($res_error, $res_error_str) = &check_opsi_res($res);
2618 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2620 return ($res->result, 0);
2621 }
2623 sub _createSoftwareLicense {
2624 my %arg = (
2625 'softwareLicenseId' => undef,
2626 'licenseContractId' => undef,
2627 'licenseType' => undef,
2628 'maxInstallations' => undef,
2629 'boundToHost' => undef,
2630 'expirationDate' => undef,
2631 @_ );
2633 my $res = &_callOpsi( method => 'createSoftwareLicense',
2634 params => [ $arg{softwareLicenseId}, $arg{licenseContractId}, $arg{licenseType}, $arg{maxInstallations}, $arg{boundToHost}, $arg{expirationDate} ],
2635 );
2636 my ($res_error, $res_error_str) = &check_opsi_res($res);
2637 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2639 return ($res->result, 0);
2640 }
2642 sub _addSoftwareLicenseToLicensePool {
2643 my %arg = (
2644 'softwareLicenseId' => undef,
2645 'licensePoolId' => undef,
2646 'licenseKey' => undef,
2647 @_ );
2649 if (not defined $arg{softwareLicenseId} ) {
2650 return ("function requires softwareLicenseId as parameter", 1);
2651 }
2652 if (not defined $arg{licensePoolId} ) {
2653 return ("function requires licensePoolId as parameter", 1);
2654 }
2656 my $res = &_callOpsi( method => 'addSoftwareLicenseToLicensePool', params => [ $arg{softwareLicenseId}, $arg{licensePoolId}, $arg{licenseKey} ] );
2657 my ($res_error, $res_error_str) = &check_opsi_res($res);
2658 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2660 return ($res->result, 0);
2661 }
2663 sub _getProductStates_hash {
2664 my %arg = ( 'hostId' => undef, @_ );
2666 if (not defined $arg{hostId} ) {
2667 return ("function requires hostId as parameter", 1);
2668 }
2670 my $res = &_callOpsi( method => 'getProductStates_hash', params => [$arg{hostId}]);
2671 my ($res_error, $res_error_str) = &check_opsi_res($res);
2672 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2674 return ($res->result, 0);
2675 }
2677 1;