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;
8 use strict;
9 use warnings;
11 use Exporter;
12 use UNIVERSAL 'isa';
13 use GOSA::GosaSupportDaemon;
14 use Data::Dumper;
15 use XML::Quote qw(:all);
17 our @ISA = qw(Exporter);
19 my @events = (
20 "get_events",
21 "opsi_install_client",
22 "opsi_get_netboot_products",
23 "opsi_get_local_products",
24 "opsi_get_client_hardware",
25 "opsi_get_client_software",
26 "opsi_get_product_properties",
27 "opsi_get_full_product_host_information",
28 "opsi_set_product_properties",
29 "opsi_list_clients",
30 "opsi_del_client",
31 "opsi_add_client",
32 "opsi_modify_client",
33 "opsi_add_product_to_client",
34 "opsi_del_product_from_client",
35 "opsi_createLicensePool",
36 "opsi_deleteLicensePool",
37 "opsi_createLicense",
38 "opsi_assignSoftwareLicenseToHost",
39 "opsi_unassignSoftwareLicenseFromHost",
40 "opsi_unassignAllSoftwareLicensesFromHost",
41 "opsi_getSoftwareLicense_hash",
42 "opsi_getLicensePool_hash",
43 "opsi_getSoftwareLicenseUsages",
44 "opsi_getSoftwareLicenseUsagesForProductId",
45 "opsi_getLicensePools_listOfHashes",
46 "opsi_getLicenseInformationForProduct",
47 "opsi_getPool",
48 "opsi_getAllSoftwareLicenses",
49 "opsi_removeLicense",
50 "opsi_getReservedLicenses",
51 "opsi_boundHostToLicense",
52 "opsi_unboundHostFromLicense",
53 "opsi_test",
54 );
56 our @EXPORT = @events;
59 BEGIN {}
61 END {}
63 # ----------------------------------------------------------------------------
64 # D E C L A R A T I O N S
65 # ----------------------------------------------------------------------------
67 my $licenseTyp_hash = { 'OEM'=>'', 'VOLUME'=>'', 'RETAIL'=>''};
68 my ($opsi_enabled, $opsi_server, $opsi_admin, $opsi_password, $opsi_url, $opsi_client);
69 my %cfg_defaults = (
70 "Opsi" => {
71 "enabled" => [\$opsi_enabled, "false"],
72 "server" => [\$opsi_server, "localhost"],
73 "admin" => [\$opsi_admin, "opsi-admin"],
74 "password" => [\$opsi_password, "secret"],
75 },
76 );
77 &read_configfile($main::cfg_file, %cfg_defaults);
78 if ($opsi_enabled eq "true") {
79 use JSON::RPC::Client;
80 use XML::Quote qw(:all);
81 use Time::HiRes qw( time );
82 $opsi_url= "https://".$opsi_admin.":".$opsi_password."@".$opsi_server.":4447/rpc";
83 $opsi_client = new JSON::RPC::Client;
85 # Check version dependencies
86 eval { &myXmlHashToString(); };
87 if ($@ ) {
88 die "\nThe version of the Opsi plugin you want to use requires a newer version of GosaSupportDaemon. Please update your GOsa-SI or deactivate the Opsi plugin.\n";
89 }
90 }
92 # ----------------------------------------------------------------------------
93 # external methods handling the comunication with GOsa/GOsa-si
94 # ----------------------------------------------------------------------------
96 ################################
97 # @brief A function returning a list of functions which are exported by importing the module.
98 # @return List of all provided functions
99 sub get_events {
100 return \@events;
101 }
103 ################################
104 # @brief Adds an Opsi product to an Opsi client.
105 # @param msg - STRING - xml message with tags hostId and productId
106 # @param msg_hash - HASHREF - message information parsed into a hash
107 # @param session_id - INTEGER - POE session id of the processing of this message
108 # @return out_msg - STRING - feedback to GOsa in success and error case
109 sub opsi_add_product_to_client {
110 my $startTime = Time::HiRes::time;
111 my ($msg, $msg_hash, $session_id) = @_;
112 my $header = @{$msg_hash->{'header'}}[0];
113 my $source = @{$msg_hash->{'source'}}[0];
114 my $target = @{$msg_hash->{'target'}}[0];
115 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
117 # Build return message
118 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
119 if (defined $forward_to_gosa) {
120 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
121 }
123 # Sanity check of needed parameter
124 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
125 return &_giveErrorFeedback($msg_hash, "no hostId specified or hostId tag invalid", $session_id);
126 }
127 if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
128 return &_giveErrorFeedback($msg_hash, "no productId specified or productId tag invalid", $session_id);
129 }
131 # Get hostId
132 my $hostId = @{$msg_hash->{'hostId'}}[0];
133 &add_content2xml_hash($out_hash, "hostId", $hostId);
135 # Get productID
136 my $productId = @{$msg_hash->{'productId'}}[0];
137 &add_content2xml_hash($out_hash, "productId", $productId);
139 # Do an action request for all these -> "setup".
140 my $callobj = {
141 method => 'setProductActionRequest',
142 params => [ $productId, $hostId, "setup" ],
143 id => 1, };
144 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
146 if (&check_opsi_res($res)) { return ( (caller(0))[3]." : ".$_, 1 ); };
148 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
149 return ( &create_xml_string($out_hash) );
150 }
152 ################################
153 # @brief Deletes an Opsi-product from an Opsi-client.
154 # @param msg - STRING - xml message with tags hostId and productId
155 # @param msg_hash - HASHREF - message information parsed into a hash
156 # @param session_id - INTEGER - POE session id of the processing of this message
157 # @return out_msg - STRING - feedback to GOsa in success and error case
158 sub opsi_del_product_from_client {
159 my $startTime = Time::HiRes::time;
160 my ($msg, $msg_hash, $session_id) = @_;
161 my $header = @{$msg_hash->{'header'}}[0];
162 my $source = @{$msg_hash->{'source'}}[0];
163 my $target = @{$msg_hash->{'target'}}[0];
164 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
165 my ($hostId, $productId);
166 my $error = 0;
167 my ($sres, $sres_err, $sres_err_string);
169 # Build return message
170 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
171 if (defined $forward_to_gosa) {
172 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
173 }
175 # Sanity check of needed parameter
176 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
177 $error++;
178 &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
179 &add_content2xml_hash($out_hash, "error", "hostId");
180 &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1);
182 }
183 if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
184 $error++;
185 &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
186 &add_content2xml_hash($out_hash, "error", "productId");
187 &main::daemon_log("$session_id ERROR: no productId specified or procutId tag invalid: $msg", 1);
188 }
190 # All parameter available
191 if (not $error) {
192 # Get hostId
193 $hostId = @{$msg_hash->{'hostId'}}[0];
194 &add_content2xml_hash($out_hash, "hostId", $hostId);
196 # Get productID
197 $productId = @{$msg_hash->{'productId'}}[0];
198 &add_content2xml_hash($out_hash, "productId", $productId);
200 # Check to get product action list
201 my $callobj = {
202 method => 'getPossibleProductActions_list',
203 params => [ $productId ],
204 id => 1, };
205 $sres = $main::opsi_client->call($main::opsi_url, $callobj);
206 ($sres_err, $sres_err_string) = &check_opsi_res($sres);
207 if ($sres_err){
208 &main::daemon_log("$session_id ERROR: cannot get product action list: ".$sres_err_string, 1);
209 &add_content2xml_hash($out_hash, "error", $sres_err_string);
210 $error++;
211 }
212 }
214 # Check action uninstall of product
215 if (not $error) {
216 my $uninst_possible= 0;
217 foreach my $r (@{$sres->result}) {
218 if ($r eq 'uninstall') {
219 $uninst_possible= 1;
220 }
221 }
222 if (!$uninst_possible){
223 &main::daemon_log("$session_id ERROR: cannot uninstall product '$productId', product do not has the action 'uninstall'", 1);
224 &add_content2xml_hash($out_hash, "error", "cannot uninstall product '$productId', product do not has the action 'uninstall'");
225 $error++;
226 }
227 }
229 # Set product state to "none"
230 # Do an action request for all these -> "setup".
231 if (not $error) {
232 my $callobj = {
233 method => 'setProductActionRequest',
234 params => [ $productId, $hostId, "none" ],
235 id => 1,
236 };
237 $sres = $main::opsi_client->call($main::opsi_url, $callobj);
238 ($sres_err, $sres_err_string) = &check_opsi_res($sres);
239 if ($sres_err){
240 &main::daemon_log("$session_id ERROR: cannot delete product: ".$sres_err_string, 1);
241 &add_content2xml_hash($out_hash, "error", $sres_err_string);
242 }
243 }
245 # Return message
246 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
247 return ( &create_xml_string($out_hash) );
248 }
250 ################################
251 # @brief Adds an Opsi client to Opsi.
252 # @param msg - STRING - xml message with tags hostId and macaddress
253 # @param msg_hash - HASHREF - message information parsed into a hash
254 # @param session_id - INTEGER - POE session id of the processing of this message
255 # @return out_msg - STRING - feedback to GOsa in success and error case
256 sub opsi_add_client {
257 my $startTime = Time::HiRes::time;
258 my ($msg, $msg_hash, $session_id) = @_;
259 my $header = @{$msg_hash->{'header'}}[0];
260 my $source = @{$msg_hash->{'source'}}[0];
261 my $target = @{$msg_hash->{'target'}}[0];
262 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
263 my ($hostId, $mac);
264 my $error = 0;
265 my ($sres, $sres_err, $sres_err_string);
267 # Build return message with twisted target and source
268 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
269 if (defined $forward_to_gosa) {
270 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
271 }
273 # Sanity check of needed parameter
274 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
275 $error++;
276 &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
277 &add_content2xml_hash($out_hash, "error", "hostId");
278 &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1);
279 }
280 if ((not exists $msg_hash->{'macaddress'}) || (@{$msg_hash->{'macaddress'}} != 1) || (@{$msg_hash->{'macaddress'}}[0] eq ref 'HASH')) {
281 $error++;
282 &add_content2xml_hash($out_hash, "error_string", "no macaddress specified or macaddress tag invalid");
283 &add_content2xml_hash($out_hash, "error", "macaddress");
284 &main::daemon_log("$session_id ERROR: no macaddress specified or macaddress tag invalid: $msg", 1);
285 }
287 if (not $error) {
288 # Get hostId
289 $hostId = @{$msg_hash->{'hostId'}}[0];
290 &add_content2xml_hash($out_hash, "hostId", $hostId);
292 # Get macaddress
293 $mac = @{$msg_hash->{'macaddress'}}[0];
294 &add_content2xml_hash($out_hash, "macaddress", $mac);
296 my $name= $hostId;
297 $name=~ s/^([^.]+).*$/$1/;
298 my $domain= $hostId;
299 $domain=~ s/^[^.]+\.(.*)$/$1/;
300 my ($description, $notes, $ip);
302 if (defined @{$msg_hash->{'description'}}[0]){
303 $description = @{$msg_hash->{'description'}}[0];
304 }
305 if (defined @{$msg_hash->{'notes'}}[0]){
306 $notes = @{$msg_hash->{'notes'}}[0];
307 }
308 if (defined @{$msg_hash->{'ip'}}[0]){
309 $ip = @{$msg_hash->{'ip'}}[0];
310 }
312 my $callobj;
313 $callobj = {
314 method => 'createClient',
315 params => [ $name, $domain, $description, $notes, $ip, $mac ],
316 id => 1,
317 };
319 $sres = $main::opsi_client->call($main::opsi_url, $callobj);
320 ($sres_err, $sres_err_string) = &check_opsi_res($sres);
321 if ($sres_err){
322 &main::daemon_log("$session_id ERROR: cannot create client: ".$sres_err_string, 1);
323 &add_content2xml_hash($out_hash, "error", $sres_err_string);
324 } else {
325 &main::daemon_log("$session_id INFO: add opsi client '$hostId' with mac '$mac'", 5);
326 }
327 }
329 # Return message
330 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
331 return ( &create_xml_string($out_hash) );
332 }
334 ################################
335 # @brief Modifies the parameters description, mac or notes for an Opsi client if the corresponding message tags are given.
336 # @param msg - STRING - xml message with tag hostId and optional description, mac or notes
337 # @param msg_hash - HASHREF - message information parsed into a hash
338 # @param session_id - INTEGER - POE session id of the processing of this message
339 # @return out_msg - STRING - feedback to GOsa in success and error case
340 sub opsi_modify_client {
341 my $startTime = Time::HiRes::time;
342 my ($msg, $msg_hash, $session_id) = @_;
343 my $header = @{$msg_hash->{'header'}}[0];
344 my $source = @{$msg_hash->{'source'}}[0];
345 my $target = @{$msg_hash->{'target'}}[0];
346 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
347 my $hostId;
348 my $error = 0;
349 my ($sres, $sres_err, $sres_err_string);
351 # Build return message with twisted target and source
352 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
353 if (defined $forward_to_gosa) {
354 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
355 }
357 # Sanity check of needed parameter
358 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
359 $error++;
360 &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
361 &add_content2xml_hash($out_hash, "error", "hostId");
362 &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1);
363 }
365 if (not $error) {
366 # Get hostId
367 $hostId = @{$msg_hash->{'hostId'}}[0];
368 &add_content2xml_hash($out_hash, "hostId", $hostId);
369 my $name= $hostId;
370 $name=~ s/^([^.]+).*$/$1/;
371 my $domain= $hostId;
372 $domain=~ s/^[^.]+(.*)$/$1/;
374 # Modify description, notes or mac if defined
375 my ($description, $notes, $mac);
376 my $callobj;
377 if ((exists $msg_hash->{'description'}) && (@{$msg_hash->{'description'}} == 1) ){
378 $description = @{$msg_hash->{'description'}}[0];
379 $callobj = {
380 method => 'setHostDescription',
381 params => [ $hostId, $description ],
382 id => 1,
383 };
384 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
385 my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
386 if ($sres_err){
387 &main::daemon_log("ERROR: cannot set description: ".$sres_err_string, 1);
388 &add_content2xml_hash($out_hash, "error", $sres_err_string);
389 }
390 }
391 if ((exists $msg_hash->{'notes'}) && (@{$msg_hash->{'notes'}} == 1)) {
392 $notes = @{$msg_hash->{'notes'}}[0];
393 $callobj = {
394 method => 'setHostNotes',
395 params => [ $hostId, $notes ],
396 id => 1,
397 };
398 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
399 my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
400 if ($sres_err){
401 &main::daemon_log("ERROR: cannot set notes: ".$sres_err_string, 1);
402 &add_content2xml_hash($out_hash, "error", $sres_err_string);
403 }
404 }
405 if ((exists $msg_hash->{'mac'}) && (@{$msg_hash->{'mac'}} == 1)){
406 $mac = @{$msg_hash->{'mac'}}[0];
407 $callobj = {
408 method => 'setMacAddress',
409 params => [ $hostId, $mac ],
410 id => 1,
411 };
412 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
413 my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
414 if ($sres_err){
415 &main::daemon_log("ERROR: cannot set mac address: ".$sres_err_string, 1);
416 &add_content2xml_hash($out_hash, "error", $sres_err_string);
417 }
418 }
419 }
421 # Return message
422 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
423 return ( &create_xml_string($out_hash) );
424 }
426 ################################
427 # @brief Get netboot products for specific host.
428 # @param msg - STRING - xml message with tag hostId
429 # @param msg_hash - HASHREF - message information parsed into a hash
430 # @param session_id - INTEGER - POE session id of the processing of this message
431 # @return out_msg - STRING - feedback to GOsa in success and error case
432 sub opsi_get_netboot_products {
433 my $startTime = Time::HiRes::time;
434 my ($msg, $msg_hash, $session_id) = @_;
435 my $header = @{$msg_hash->{'header'}}[0];
436 my $source = @{$msg_hash->{'source'}}[0];
437 my $target = @{$msg_hash->{'target'}}[0];
438 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
439 my $hostId;
441 # Build return message with twisted target and source
442 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
443 if (defined $forward_to_gosa) {
444 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
445 }
446 &add_content2xml_hash($out_hash, "xxx", "");
448 # Get hostId if defined
449 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1)) {
450 $hostId = @{$msg_hash->{'hostId'}}[0];
451 &add_content2xml_hash($out_hash, "hostId", $hostId);
452 }
454 # Move to XML string
455 my $xml_msg= &create_xml_string($out_hash);
457 my $callobj;
458 # Check if we need to get host or global information
459 if (defined $hostId){
460 $callobj = {
461 method => 'getProductHostInformation_list',
462 params => [ $hostId, undef, 'netboot'],
463 id => 1,
464 };
466 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
467 if (not &check_opsi_res($res)){
468 foreach my $product (@{$res->result}){
469 my $replace= "<item><productId>".xml_quote($product->{'productId'})."<\/productId><name>".xml_quote($product->{'name'})."<\/name><description>".xml_quote($product->{'description'})."<\/description><state>".xml_quote($product->{'installationStatus'})."</state><action>".xml_quote($product->{'actionRequest'})."</action><\/item><xxx><\/xxx>";
470 $xml_msg=~ s/<xxx><\/xxx>/\n$replace/;
471 }
472 }
474 } else {
476 # For hosts, only return the products that are or get installed
477 $callobj = {
478 method => 'getProductInformation_list',
479 params => [ undef, 'netboot' ],
480 id => 1,
481 };
483 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
484 if (not &check_opsi_res($res)){
485 foreach my $product (@{$res->result}) {
486 my $replace= "<item><productId>".xml_quote($product->{'productId'})."<\/productId><name>".xml_quote($product->{'name'})."<\/name><description>".xml_quote($product->{'description'})."<\/description><\/item><xxx><\/xxx>";
487 $xml_msg=~ s/<xxx><\/xxx>/\n$replace/;
488 }
489 }
490 }
492 $xml_msg=~ s/<xxx><\/xxx>//;
494 # Retrun Message
495 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
496 return ( $xml_msg );
497 }
499 ################################
500 # @brief Get product properties for a product and a specific host or gobally for a product.
501 # @param msg - STRING - xml message with tags productId and optional hostId
502 # @param msg_hash - HASHREF - message information parsed into a hash
503 # @param session_id - INTEGER - POE session id of the processing of this message
504 # @return out_msg - STRING - feedback to GOsa in success and error case
505 sub opsi_get_product_properties {
506 my $startTime = Time::HiRes::time;
507 my ($msg, $msg_hash, $session_id) = @_;
508 my $header = @{$msg_hash->{'header'}}[0];
509 my $source = @{$msg_hash->{'source'}}[0];
510 my $target = @{$msg_hash->{'target'}}[0];
511 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
512 my ($hostId, $productId);
513 my $xml_msg;
515 # Build return message with twisted target and source
516 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
517 if (defined $forward_to_gosa) {
518 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
519 }
521 # Sanity check of needed parameter
522 if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
523 &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
524 &add_content2xml_hash($out_hash, "error", "productId");
525 &main::daemon_log("$session_id ERROR: no productId specified or productId tag invalid: $msg", 1);
527 # Return message
528 return ( &create_xml_string($out_hash) );
529 }
531 # Get productid
532 $productId = @{$msg_hash->{'productId'}}[0];
533 &add_content2xml_hash($out_hash, "producId", "$productId");
535 # Get hostId if defined
536 if (defined @{$msg_hash->{'hostId'}}[0]){
537 $hostId = @{$msg_hash->{'hostId'}}[0];
538 &add_content2xml_hash($out_hash, "hostId", $hostId);
539 }
541 # Load actions
542 my $callobj = {
543 method => 'getPossibleProductActions_list',
544 params => [ $productId ],
545 id => 1,
546 };
547 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
548 if (not &check_opsi_res($res)){
549 foreach my $action (@{$res->result}){
550 &add_content2xml_hash($out_hash, "action", $action);
551 }
552 }
554 # Add place holder
555 &add_content2xml_hash($out_hash, "xxx", "");
557 # Move to XML string
558 $xml_msg= &create_xml_string($out_hash);
560 # JSON Query
561 if (defined $hostId){
562 $callobj = {
563 method => 'getProductProperties_hash',
564 params => [ $productId, $hostId ],
565 id => 1,
566 };
567 } else {
568 $callobj = {
569 method => 'getProductProperties_hash',
570 params => [ $productId ],
571 id => 1,
572 };
573 }
574 $res = $main::opsi_client->call($main::opsi_url, $callobj);
576 # JSON Query 2
577 $callobj = {
578 method => 'getProductPropertyDefinitions_listOfHashes',
579 params => [ $productId ],
580 id => 1,
581 };
583 # Assemble options
584 my $res2 = $main::opsi_client->call($main::opsi_url, $callobj);
585 my $values = {};
586 my $descriptions = {};
587 if (not &check_opsi_res($res2)){
588 my $r= $res2->result;
590 foreach my $entr (@$r){
591 # Unroll values
592 my $cnv;
593 if (UNIVERSAL::isa( $entr->{'values'}, "ARRAY" )){
594 foreach my $v (@{$entr->{'values'}}){
595 $cnv.= "<value>$v</value>";
596 }
597 } else {
598 $cnv= $entr->{'values'};
599 }
600 $values->{$entr->{'name'}}= $cnv;
601 $descriptions->{$entr->{'name'}}= "<description>".$entr->{'description'}."</description>";
602 }
603 }
605 if (not &check_opsi_res($res)){
606 my $r= $res->result;
607 foreach my $key (keys %{$r}) {
608 my $item= "\n<item>";
609 my $value= $r->{$key};
610 my $dsc= "";
611 my $vals= "";
612 if (defined $descriptions->{$key}){
613 $dsc= $descriptions->{$key};
614 }
615 if (defined $values->{$key}){
616 $vals= $values->{$key};
617 }
618 $item.= "<$key>$dsc<current>".xml_quote($value)."</current>$vals</$key>";
619 $item.= "</item>";
620 $xml_msg=~ s/<xxx><\/xxx>/$item<xxx><\/xxx>/;
621 }
622 }
624 $xml_msg=~ s/<xxx><\/xxx>//;
626 # Return message
627 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
628 return ( $xml_msg );
629 }
631 ################################
632 # @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.
633 # @param msg - STRING - xml message with tags productId, action, state and optional hostId, action and state
634 # @param msg_hash - HASHREF - message information parsed into a hash
635 # @param session_id - INTEGER - POE session id of the processing of this message
636 # @return out_msg - STRING - feedback to GOsa in success and error case
637 sub opsi_set_product_properties {
638 my $startTime = Time::HiRes::time;
639 my ($msg, $msg_hash, $session_id) = @_;
640 my $header = @{$msg_hash->{'header'}}[0];
641 my $source = @{$msg_hash->{'source'}}[0];
642 my $target = @{$msg_hash->{'target'}}[0];
643 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
644 my ($productId, $hostId);
646 # Build return message with twisted target and source
647 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
648 if (defined $forward_to_gosa) {
649 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
650 }
652 # Sanity check of needed parameter
653 if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
654 &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
655 &add_content2xml_hash($out_hash, "error", "productId");
656 &main::daemon_log("$session_id ERROR: no productId specified or productId tag invalid: $msg", 1);
657 return ( &create_xml_string($out_hash) );
658 }
659 if (not exists $msg_hash->{'item'}) {
660 &add_content2xml_hash($out_hash, "error_string", "message needs one xml-tag 'item' and within the xml-tags 'name' and 'value'");
661 &add_content2xml_hash($out_hash, "error", "item");
662 &main::daemon_log("$session_id ERROR: message needs one xml-tag 'item' and within the xml-tags 'name' and 'value': $msg", 1);
663 return ( &create_xml_string($out_hash) );
664 } else {
665 if ((not exists @{$msg_hash->{'item'}}[0]->{'name'}) || (@{@{$msg_hash->{'item'}}[0]->{'name'}} != 1 )) {
666 &add_content2xml_hash($out_hash, "error_string", "message needs within the xml-tag 'item' one xml-tags 'name'");
667 &add_content2xml_hash($out_hash, "error", "name");
668 &main::daemon_log("$session_id ERROR: message needs within the xml-tag 'item' one xml-tags 'name': $msg", 1);
669 return ( &create_xml_string($out_hash) );
670 }
671 if ((not exists @{$msg_hash->{'item'}}[0]->{'value'}) || (@{@{$msg_hash->{'item'}}[0]->{'value'}} != 1 )) {
672 &add_content2xml_hash($out_hash, "error_string", "message needs within the xml-tag 'item' one xml-tags 'value'");
673 &add_content2xml_hash($out_hash, "error", "value");
674 &main::daemon_log("$session_id ERROR: message needs within the xml-tag 'item' one xml-tags 'value': $msg", 1);
675 return ( &create_xml_string($out_hash) );
676 }
677 }
678 # if no hostId is given, set_product_properties will act on globally
679 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} > 1)) {
680 &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
681 &add_content2xml_hash($out_hash, "error", "hostId");
682 &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1);
683 return ( &create_xml_string($out_hash) );
684 }
687 # Get productId
688 $productId = @{$msg_hash->{'productId'}}[0];
689 &add_content2xml_hash($out_hash, "productId", $productId);
691 # Get hostId if defined
692 if (exists $msg_hash->{'hostId'}){
693 $hostId = @{$msg_hash->{'hostId'}}[0];
694 &add_content2xml_hash($out_hash, "hostId", $hostId);
695 }
697 # Set product states if requested
698 if (defined @{$msg_hash->{'action'}}[0]){
699 &_set_action($productId, @{$msg_hash->{'action'}}[0], $hostId);
700 }
701 if (defined @{$msg_hash->{'state'}}[0]){
702 &_set_state($productId, @{$msg_hash->{'state'}}[0], $hostId);
703 }
705 # Find properties
706 foreach my $item (@{$msg_hash->{'item'}}){
707 # JSON Query
708 my $callobj;
710 if (defined $hostId){
711 $callobj = {
712 method => 'setProductProperty',
713 params => [ $productId, $item->{'name'}[0], $item->{'value'}[0], $hostId ],
714 id => 1,
715 };
716 } else {
717 $callobj = {
718 method => 'setProductProperty',
719 params => [ $productId, $item->{'name'}[0], $item->{'value'}[0] ],
720 id => 1,
721 };
722 }
724 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
725 my ($res_err, $res_err_string) = &check_opsi_res($res);
727 if ($res_err){
728 &main::daemon_log("$session_id ERROR: communication failed while setting '".$item->{'name'}[0]."': ".$res_err_string, 1);
729 &add_content2xml_hash($out_hash, "error", $res_err_string);
730 }
731 }
734 # Return message
735 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
736 return ( &create_xml_string($out_hash) );
737 }
739 ################################
740 # @brief Reports client hardware inventory.
741 # @param msg - STRING - xml message with tag hostId
742 # @param msg_hash - HASHREF - message information parsed into a hash
743 # @param session_id - INTEGER - POE session id of the processing of this message
744 # @return out_msg - STRING - feedback to GOsa in success and error case
745 sub opsi_get_client_hardware {
746 my $startTime = Time::HiRes::time;
747 my ($msg, $msg_hash, $session_id) = @_;
748 my $header = @{$msg_hash->{'header'}}[0];
749 my $source = @{$msg_hash->{'source'}}[0];
750 my $target = @{$msg_hash->{'target'}}[0];
751 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
752 my $hostId;
753 my $error = 0;
754 my $xml_msg;
756 # Sanity check of needed parameter
757 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
758 $hostId = @{$msg_hash->{'hostId'}}[0];
759 } else {
760 return &_giveErrorFeedback($msg_hash, $_, $session_id);
761 }
764 # Build return message with twisted target and source
765 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
766 if (defined $forward_to_gosa) {
767 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
768 }
769 &add_content2xml_hash($out_hash, "hostId", "$hostId");
770 &add_content2xml_hash($out_hash, "xxx", "");
772 # Move to XML string
773 $xml_msg= &create_xml_string($out_hash);
775 my $res = &_callOpsi(method=>'getHardwareInformation_hash', params=>[ $hostId ]);
776 if (not &check_opsi_res($res)){
777 my $result= $res->result;
778 if (ref $result eq "HASH") {
779 foreach my $r (keys %{$result}){
780 my $item= "\n<item><id>".xml_quote($r)."</id>";
781 my $value= $result->{$r};
782 foreach my $sres (@{$value}){
784 foreach my $dres (keys %{$sres}){
785 if (defined $sres->{$dres}){
786 $item.= "<$dres>".xml_quote($sres->{$dres})."</$dres>";
787 }
788 }
790 }
791 $item.= "</item>";
792 $xml_msg=~ s%<xxx></xxx>%$item<xxx></xxx>%;
794 }
795 }
796 }
798 $xml_msg=~ s/<xxx><\/xxx>//;
800 # Return message
801 my $endTime = Time::HiRes::time;
802 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
803 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
804 return ( $xml_msg );
805 }
807 ################################
808 # @brief Reports all Opsi clients.
809 # @param msg - STRING - xml message
810 # @param msg_hash - HASHREF - message information parsed into a hash
811 # @param session_id - INTEGER - POE session id of the processing of this message
812 # @return out_msg - STRING - feedback to GOsa in success and error case
813 sub opsi_list_clients {
814 my $startTime = Time::HiRes::time;
815 my ($msg, $msg_hash, $session_id) = @_;
816 my $header = @{$msg_hash->{'header'}}[0];
817 my $source = @{$msg_hash->{'source'}}[0];
818 my $target = @{$msg_hash->{'target'}}[0];
819 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
821 # Build return message with twisted target and source
822 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
823 if (defined $forward_to_gosa) {
824 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
825 }
826 &add_content2xml_hash($out_hash, "xxx", "");
828 # Move to XML string
829 my $xml_msg= &create_xml_string($out_hash);
831 # JSON Query
832 my $callobj = {
833 method => 'getClientsInformation_listOfHashes',
834 params => [ ],
835 id => 1,
836 };
838 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
839 if (not &check_opsi_res($res)){
840 foreach my $host (@{$res->result}){
841 my $item= "\n<item><name>".$host->{'hostId'}."</name>";
842 $item.= "<mac>".xml_quote($host->{'macAddress'})."</mac>";
843 if (defined($host->{'description'})){
844 $item.= "<description>".xml_quote($host->{'description'})."</description>";
845 }
846 if (defined($host->{'notes'})){
847 $item.= "<notes>".xml_quote($host->{'notes'})."</notes>";
848 }
849 if (defined($host->{'lastSeen'})){
850 $item.= "<lastSeen>".xml_quote($host->{'lastSeen'})."</lastSeen>";
851 }
853 $item.= "</item>";
854 $xml_msg=~ s%<xxx></xxx>%$item<xxx></xxx>%;
855 }
856 }
857 $xml_msg=~ s/<xxx><\/xxx>//;
859 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
860 return ( $xml_msg );
861 }
863 ################################
864 # @brief Reports client software inventory.
865 # @param msg - STRING - xml message with tag hostId
866 # @param msg_hash - HASHREF - message information parsed into a hash
867 # @param session_id - INTEGER - POE session id of the processing of this message
868 # @return out_msg - STRING - feedback to GOsa in success and error case
869 sub opsi_get_client_software {
870 my $startTime = Time::HiRes::time;
871 my ($msg, $msg_hash, $session_id) = @_;
872 my $header = @{$msg_hash->{'header'}}[0];
873 my $source = @{$msg_hash->{'source'}}[0];
874 my $target = @{$msg_hash->{'target'}}[0];
875 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
876 my $error = 0;
877 my $hostId;
878 my $xml_msg;
880 # Build return message with twisted target and source
881 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
882 if (defined $forward_to_gosa) {
883 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
884 }
886 # Sanity check of needed parameter
887 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
888 $error++;
889 &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
890 &add_content2xml_hash($out_hash, "error", "hostId");
891 &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1);
892 }
894 if (not $error) {
896 # Get hostId
897 $hostId = @{$msg_hash->{'hostId'}}[0];
898 &add_content2xml_hash($out_hash, "hostId", "$hostId");
899 &add_content2xml_hash($out_hash, "xxx", "");
900 }
902 $xml_msg= &create_xml_string($out_hash);
904 if (not $error) {
906 # JSON Query
907 my $callobj = {
908 method => 'getSoftwareInformation_hash',
909 params => [ $hostId ],
910 id => 1,
911 };
913 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
914 if (not &check_opsi_res($res)){
915 my $result= $res->result;
916 }
918 $xml_msg=~ s/<xxx><\/xxx>//;
920 }
922 # Return message
923 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
924 return ( $xml_msg );
925 }
927 ################################
928 # @brief Reports product for given hostId or globally.
929 # @param msg - STRING - xml message with optional tag hostId
930 # @param msg_hash - HASHREF - message information parsed into a hash
931 # @param session_id - INTEGER - POE session id of the processing of this message
932 # @return out_msg - STRING - feedback to GOsa in success and error case
933 sub opsi_get_local_products {
934 my $startTime = Time::HiRes::time;
935 my ($msg, $msg_hash, $session_id) = @_;
936 my $header = @{$msg_hash->{'header'}}[0];
937 my $source = @{$msg_hash->{'source'}}[0];
938 my $target = @{$msg_hash->{'target'}}[0];
939 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
940 my $hostId;
942 # Build return message with twisted target and source
943 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
944 if (defined $forward_to_gosa) {
945 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
946 }
947 &add_content2xml_hash($out_hash, "xxx", "");
949 # Get hostId if defined
950 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1)) {
951 $hostId = @{$msg_hash->{'hostId'}}[0];
952 &add_content2xml_hash($out_hash, "hostId", $hostId);
953 }
955 my $callobj;
957 # Move to XML string
958 my $xml_msg= &create_xml_string($out_hash);
960 # Check if we need to get host or global information
961 if (defined $hostId){
962 $callobj = {
963 method => 'getProductHostInformation_list',
964 params => [ $hostId ],
965 id => 1,
966 };
968 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
969 if (not &check_opsi_res($res)){
970 foreach my $product (@{$res->result}){
971 my $replace= "<item><productId>".xml_quote($product->{'productId'})."<\/productId><name>".xml_quote($product->{'name'})."<\/name><description>".xml_quote($product->{'description'})."<\/description><state>".xml_quote($product->{'installationStatus'})."</state><action>".xml_quote($product->{'actionRequest'})."</action><\/item><xxx><\/xxx>";
972 $xml_msg=~ s/<xxx><\/xxx>/\n$replace/;
973 }
974 }
976 } else {
978 # For hosts, only return the products that are or get installed
979 $callobj = {
980 method => 'getProductInformation_list',
981 params => [ undef, 'localboot' ],
982 id => 1,
983 };
985 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
986 if (not &check_opsi_res($res)){
987 foreach my $product (@{$res->result}) {
988 my $replace= "<item><productId>".xml_quote($product->{'productId'})."<\/productId><name>".xml_quote($product->{'name'})."<\/name><description>".xml_quote($product->{'description'})."<\/description><\/item><xxx><\/xxx>";
989 $xml_msg=~ s/<xxx><\/xxx>/\n$replace/;
990 }
991 }
992 }
994 $xml_msg=~ s/<xxx><\/xxx>//;
996 # Retrun Message
997 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
998 return ( $xml_msg );
999 }
1001 ################################
1002 # @brief Deletes a client from Opsi.
1003 # @param msg - STRING - xml message with tag hostId
1004 # @param msg_hash - HASHREF - message information parsed into a hash
1005 # @param session_id - INTEGER - POE session id of the processing of this message
1006 # @return out_msg - STRING - feedback to GOsa in success and error case
1007 sub opsi_del_client {
1008 my $startTime = Time::HiRes::time;
1009 my ($msg, $msg_hash, $session_id) = @_;
1010 my $header = @{$msg_hash->{'header'}}[0];
1011 my $source = @{$msg_hash->{'source'}}[0];
1012 my $target = @{$msg_hash->{'target'}}[0];
1013 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1014 my $hostId;
1015 my $error = 0;
1017 # Build return message with twisted target and source
1018 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1019 if (defined $forward_to_gosa) {
1020 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1021 }
1023 # Sanity check of needed parameter
1024 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
1025 $error++;
1026 &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
1027 &add_content2xml_hash($out_hash, "error", "hostId");
1028 &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1);
1029 }
1031 if (not $error) {
1033 # Get hostId
1034 $hostId = @{$msg_hash->{'hostId'}}[0];
1035 &add_content2xml_hash($out_hash, "hostId", "$hostId");
1037 # JSON Query
1038 my $callobj = {
1039 method => 'deleteClient',
1040 params => [ $hostId ],
1041 id => 1,
1042 };
1043 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1044 }
1046 # Move to XML string
1047 my $xml_msg= &create_xml_string($out_hash);
1049 # Return message
1050 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1051 return ( $xml_msg );
1052 }
1054 ################################
1055 # @brief Set a client in Opsi to install and trigger a wake on lan message (WOL).
1056 # @param msg - STRING - xml message with tags hostId, macaddress
1057 # @param msg_hash - HASHREF - message information parsed into a hash
1058 # @param session_id - INTEGER - POE session id of the processing of this message
1059 # @return out_msg - STRING - feedback to GOsa in success and error case
1060 sub opsi_install_client {
1061 my $startTime = Time::HiRes::time;
1062 my ($msg, $msg_hash, $session_id) = @_;
1063 my $header = @{$msg_hash->{'header'}}[0];
1064 my $source = @{$msg_hash->{'source'}}[0];
1065 my $target = @{$msg_hash->{'target'}}[0];
1066 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1067 my ($hostId, $macaddress);
1068 my $error = 0;
1069 my @out_msg_l;
1071 # Build return message with twisted target and source
1072 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1073 if (defined $forward_to_gosa) {
1074 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1075 }
1077 # Sanity check of needed parameter
1078 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
1079 $error++;
1080 &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
1081 &add_content2xml_hash($out_hash, "error", "hostId");
1082 &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1);
1083 }
1084 if ((not exists $msg_hash->{'macaddress'}) || (@{$msg_hash->{'macaddress'}} != 1) || (@{$msg_hash->{'macaddress'}}[0] eq ref 'HASH') ) {
1085 $error++;
1086 &add_content2xml_hash($out_hash, "error_string", "no macaddress specified or macaddress tag invalid");
1087 &add_content2xml_hash($out_hash, "error", "macaddress");
1088 &main::daemon_log("$session_id ERROR: no macaddress specified or macaddress tag invalid: $msg", 1);
1089 } else {
1090 if ((exists $msg_hash->{'macaddress'}) &&
1091 ($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)) {
1092 $macaddress = $1;
1093 } else {
1094 $error ++;
1095 &add_content2xml_hash($out_hash, "error_string", "given mac address is not correct");
1096 &add_content2xml_hash($out_hash, "error", "macaddress");
1097 &main::daemon_log("$session_id ERROR: given mac address is not correct: $msg", 1);
1098 }
1099 }
1101 if (not $error) {
1103 # Get hostId
1104 $hostId = @{$msg_hash->{'hostId'}}[0];
1105 &add_content2xml_hash($out_hash, "hostId", "$hostId");
1107 # Load all products for this host with status != "not_installed" or actionRequest != "none"
1108 my $callobj = {
1109 method => 'getProductStates_hash',
1110 params => [ $hostId ],
1111 id => 1,
1112 };
1114 my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
1115 if (not &check_opsi_res($hres)){
1116 my $htmp= $hres->result->{$hostId};
1118 # check state != not_installed or action == setup -> load and add
1119 foreach my $product (@{$htmp}){
1120 # Now we've a couple of hashes...
1121 if ($product->{'installationStatus'} ne "not_installed" or
1122 $product->{'actionRequest'} ne "none"){
1124 # Do an action request for all these -> "setup".
1125 $callobj = {
1126 method => 'setProductActionRequest',
1127 params => [ $product->{'productId'}, $hostId, "setup" ],
1128 id => 1,
1129 };
1130 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1131 my ($res_err, $res_err_string) = &check_opsi_res($res);
1132 if ($res_err){
1133 &main::daemon_log("$session_id ERROR: cannot set product action request for '$hostId': ".$product->{'productId'}, 1);
1134 } else {
1135 &main::daemon_log("$session_id INFO: requesting 'setup' for '".$product->{'productId'}."' on $hostId", 1);
1136 }
1137 }
1138 }
1139 }
1140 push(@out_msg_l, &create_xml_string($out_hash));
1143 # Build wakeup message for client
1144 if (not $error) {
1145 my $wakeup_hash = &create_xml_hash("trigger_wake", "GOSA", "KNOWN_SERVER");
1146 &add_content2xml_hash($wakeup_hash, 'macaddress', $macaddress);
1147 my $wakeup_msg = &create_xml_string($wakeup_hash);
1148 push(@out_msg_l, $wakeup_msg);
1150 # invoke trigger wake for this gosa-si-server
1151 &main::server_server_com::trigger_wake($wakeup_msg, $wakeup_hash, $session_id);
1152 }
1153 }
1155 # Return messages
1156 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1157 return @out_msg_l;
1158 }
1160 ################################
1161 # @brief Set action for an Opsi client
1162 # @param product - STRING - Opsi product
1163 # @param action - STRING - action
1164 # @param hostId - STRING - Opsi hostId
1165 sub _set_action {
1166 my $product= shift;
1167 my $action = shift;
1168 my $hostId = shift;
1169 my $callobj;
1171 $callobj = {
1172 method => 'setProductActionRequest',
1173 params => [ $product, $hostId, $action],
1174 id => 1,
1175 };
1177 $main::opsi_client->call($main::opsi_url, $callobj);
1178 }
1180 ################################
1181 # @brief Set state for an Opsi client
1182 # @param product - STRING - Opsi product
1183 # @param action - STRING - state
1184 # @param hostId - STRING - Opsi hostId
1185 sub _set_state {
1186 my $product = shift;
1187 my $state = shift;
1188 my $hostId = shift;
1189 my $callobj;
1191 $callobj = {
1192 method => 'setProductState',
1193 params => [ $product, $hostId, $state ],
1194 id => 1,
1195 };
1197 $main::opsi_client->call($main::opsi_url, $callobj);
1198 }
1200 ################################
1201 # @brief Create a license pool at Opsi server.
1202 # @param licensePoolId The name of the pool (optional).
1203 # @param description The description of the pool (optional).
1204 # @param productIds A list of assigned porducts of the pool (optional).
1205 # @param windowsSoftwareIds A list of windows software IDs associated to the pool (optional).
1206 sub opsi_createLicensePool {
1207 my $startTime = Time::HiRes::time;
1208 my ($msg, $msg_hash, $session_id) = @_;
1209 my $header = @{$msg_hash->{'header'}}[0];
1210 my $source = @{$msg_hash->{'source'}}[0];
1211 my $target = @{$msg_hash->{'target'}}[0];
1212 my $out_hash;
1213 my $licensePoolId = defined $msg_hash->{'licensePoolId'} ? @{$msg_hash->{'licensePoolId'}}[0] : undef;
1214 my $description = defined $msg_hash->{'description'} ? @{$msg_hash->{'description'}}[0] : undef;
1215 my @productIds = defined $msg_hash->{'productIds'} ? $msg_hash->{'productIds'} : undef;
1216 my @windowsSoftwareIds = defined $msg_hash->{'windowsSoftwareIds'} ? $msg_hash->{'windowsSoftwareIds'} : undef;
1218 # Create license Pool
1219 my $callobj = {
1220 method => 'createLicensePool',
1221 params => [ $licensePoolId, $description, @productIds, @windowsSoftwareIds],
1222 id => 1,
1223 };
1224 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1226 # Check Opsi error
1227 my ($res_error, $res_error_str) = &check_opsi_res($res);
1228 if ($res_error){
1229 # Create error message
1230 &main::daemon_log("$session_id ERROR: cannot create license pool at Opsi server: ".$res_error_str, 1);
1231 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1232 return ( &create_xml_string($out_hash) );
1233 }
1235 # Create function result message
1236 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source, $res->result);
1237 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1239 my $endTime = Time::HiRes::time;
1240 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1241 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1242 return ( &create_xml_string($out_hash) );
1243 }
1245 ################################
1246 # @brief Return licensePoolId, description, productIds and windowsSoftwareIds for all found license pools.
1247 sub opsi_getLicensePools_listOfHashes {
1248 my $startTime = Time::HiRes::time;
1249 my ($msg, $msg_hash, $session_id) = @_;
1250 my $header = @{$msg_hash->{'header'}}[0];
1251 my $source = @{$msg_hash->{'source'}}[0];
1252 my $out_hash;
1254 # Fetch infos from Opsi server
1255 my $callobj = {
1256 method => 'getLicensePools_listOfHashes',
1257 params => [ ],
1258 id => 1,
1259 };
1260 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1262 # Check Opsi error
1263 my ($res_error, $res_error_str) = &check_opsi_res($res);
1264 if ($res_error){
1265 # Create error message
1266 &main::daemon_log("$session_id ERROR: cannot get license pool ID list from Opsi server: ".$res_error_str, 1);
1267 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1268 return ( &create_xml_string($out_hash) );
1269 }
1271 # Create function result message
1272 my $res_hash = { 'hit'=> [] };
1273 foreach my $licensePool ( @{$res->result}) {
1274 my $licensePool_hash = { 'licensePoolId' => [$licensePool->{'licensePoolId'}],
1275 'description' => [$licensePool->{'description'}],
1276 'productIds' => $licensePool->{'productIds'},
1277 'windowsSoftwareIds' => $licensePool->{'windowsSoftwareIds'},
1278 };
1279 push( @{$res_hash->{hit}}, $licensePool_hash );
1280 }
1282 # Create function result message
1283 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1284 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1285 $out_hash->{result} = [$res_hash];
1287 my $endTime = Time::HiRes::time;
1288 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1289 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1290 return ( &create_xml_string($out_hash) );
1291 }
1293 ################################
1294 # @brief Return productIds, windowsSoftwareIds and description for a given licensePoolId
1295 # @param licensePoolId The name of the pool.
1296 sub opsi_getLicensePool_hash {
1297 my $startTime = Time::HiRes::time;
1298 my ($msg, $msg_hash, $session_id) = @_;
1299 my $header = @{$msg_hash->{'header'}}[0];
1300 my $source = @{$msg_hash->{'source'}}[0];
1301 my $target = @{$msg_hash->{'target'}}[0];
1302 my $licensePoolId;
1303 my $out_hash;
1305 # Check input sanity
1306 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1307 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1308 } else {
1309 return &_giveErrorFeedback($msg_hash, "", $session_id, $_);
1310 }
1312 # Fetch infos from Opsi server
1313 my $callobj = {
1314 method => 'getLicensePool_hash',
1315 params => [ $licensePoolId ],
1316 id => 1,
1317 };
1318 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1320 # Check Opsi error
1321 my ($res_error, $res_error_str) = &check_opsi_res($res);
1322 if ($res_error){
1323 # Create error message
1324 &main::daemon_log("$session_id ERROR: cannot get license pool from Opsi server: ".$res_error_str, 1);
1325 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source);
1326 &add_content2xml_hash($out_hash, "error", $res_error_str);
1327 return ( &create_xml_string($out_hash) );
1328 }
1330 # Create function result message
1331 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1332 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1333 &add_content2xml_hash($out_hash, "licensePoolId", $res->result->{'licensePoolId'});
1334 &add_content2xml_hash($out_hash, "description", $res->result->{'description'});
1335 map(&add_content2xml_hash($out_hash, "productIds", "$_"), @{ $res->result->{'productIds'} });
1336 map(&add_content2xml_hash($out_hash, "windowsSoftwareIds", "$_"), @{ $res->result->{'windowsSoftwareIds'} });
1338 my $endTime = Time::HiRes::time;
1339 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1340 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1341 return ( &create_xml_string($out_hash) );
1342 }
1344 sub _parse_getSoftwareLicenseUsages {
1345 my $res = shift;
1347 # Parse Opsi result
1348 my $tmp_licensePool_cache = {};
1349 my $res_hash = { 'hit'=> [] };
1350 foreach my $license ( @{$res}) {
1351 my $tmp_licensePool = $license->{'licensePoolId'};
1352 if (not exists $tmp_licensePool_cache->{$tmp_licensePool}) {
1353 # Fetch missing informations from Opsi and cache the results for a possible later usage
1354 my ($res, $err) = &_getLicensePool_hash('licensePoolId'=>$tmp_licensePool);
1355 if (not $err) {
1356 $tmp_licensePool_cache->{$tmp_licensePool} = $res;
1357 }
1358 }
1359 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
1360 'notes' => [$license->{'notes'}],
1361 'licenseKey' => [$license->{'licenseKey'}],
1362 'hostId' => [$license->{'hostId'}],
1363 'licensePoolId' => [$tmp_licensePool],
1364 };
1365 if (exists $tmp_licensePool_cache->{$tmp_licensePool}) {
1366 $license_hash->{$tmp_licensePool} = {'productIds'=>[], 'windowsSoftwareIds'=>[]};
1367 map (push (@{$license_hash->{$tmp_licensePool}->{productIds}}, $_), @{$tmp_licensePool_cache->{$tmp_licensePool}->{productIds}});
1368 map (push (@{$license_hash->{$tmp_licensePool}->{windowsSoftwareIds}}, $_), @{$tmp_licensePool_cache->{$tmp_licensePool}->{windowsSoftwareIds}});
1369 }
1370 push( @{$res_hash->{hit}}, $license_hash );
1371 }
1373 return $res_hash;
1374 }
1376 ################################
1377 # @brief Returns softwareLicenseId, notes, licenseKey, hostId and licensePoolId for optional given licensePoolId and hostId
1378 # @param hostid Something like client_1.intranet.mydomain.de (optional).
1379 # @param licensePoolId The name of the pool (optional).
1380 sub opsi_getSoftwareLicenseUsages {
1381 my $startTime = Time::HiRes::time;
1382 my ($msg, $msg_hash, $session_id) = @_;
1383 my $header = @{$msg_hash->{'header'}}[0];
1384 my $source = @{$msg_hash->{'source'}}[0];
1385 my $target = @{$msg_hash->{'target'}}[0];
1386 my $licensePoolId = defined $msg_hash->{'licensePoolId'} ? @{$msg_hash->{'licensePoolId'}}[0] : undef;
1387 my $hostId = defined $msg_hash->{'hostId'} ? @{$msg_hash->{'hostId'}}[0] : undef;
1388 my $out_hash;
1390 my ($res, $err) = &_getSoftwareLicenseUsages_listOfHashes('licensePoolId'=>$licensePoolId, 'hostId'=>$hostId);
1391 if ($err){
1392 return &_giveErrorFeedback($msg_hash, "cannot fetch software licenses from license pool : ".$res, $session_id);
1393 }
1395 # Parse Opsi result
1396 my $res_hash = &_parse_getSoftwareLicenseUsages($res);
1398 # Create function result message
1399 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1400 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1401 $out_hash->{result} = [$res_hash];
1403 my $endTime = Time::HiRes::time;
1404 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1405 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1406 return ( &create_xml_string($out_hash) );
1407 }
1409 ################################
1410 # @brief Returns softwareLicenseId, notes, licenseKey, hostId and licensePoolId. Function return is identical to opsi_getSoftwareLicenseUsages
1411 # @param productId Something like 'firefox', 'python' or anything else .
1412 sub opsi_getSoftwareLicenseUsagesForProductId {
1413 my $startTime = Time::HiRes::time;
1414 my ($msg, $msg_hash, $session_id) = @_;
1415 my $header = @{$msg_hash->{'header'}}[0];
1416 my $source = @{$msg_hash->{'source'}}[0];
1418 # Check input sanity
1419 my $productId;
1420 if (&_check_xml_tag_is_ok ($msg_hash, 'productId')) {
1421 $productId= @{$msg_hash->{'productId'}}[0];
1422 } else {
1423 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1424 }
1426 # Fetch licensePoolId for productId
1427 my ($res, $err) = &_getLicensePoolId('productId'=>$productId);
1428 if ($err){
1429 my $out_hash = &create_xml_hash("answer_$header", $main::server_address, $source);
1430 $out_hash->{result} = [];
1431 return ( &create_xml_string($out_hash) );
1432 }
1433 my $licensePoolId = $res; # We assume that there is only one pool for each productID!!!
1435 # Fetch softwareLiceceUsages for licensePoolId
1436 ($res, $err) = &_getSoftwareLicenseUsages_listOfHashes('licensePoolId'=>$licensePoolId);
1437 if ($err){
1438 return &_giveErrorFeedback($msg_hash, "cannot fetch software licenses from license pool : ".$res, $session_id);
1439 }
1440 # Parse Opsi result
1441 my $res_hash = &_parse_getSoftwareLicenseUsages($res);
1443 # Create function result message
1444 my $out_hash = &create_xml_hash("answer_$header", $main::server_address, $source);
1445 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1446 $out_hash->{result} = [$res_hash];
1448 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1449 return ( &create_xml_string($out_hash) );
1450 }
1452 ################################
1453 # @brief Returns expirationDate, boundToHost, maxInstallation, licenseTyp, licensePoolIds and licenseKeys for a given softwareLicense ID.
1454 # @param softwareLicenseId Identificator of a license.
1455 sub opsi_getSoftwareLicense_hash {
1456 my $startTime = Time::HiRes::time;
1457 my ($msg, $msg_hash, $session_id) = @_;
1458 my $header = @{$msg_hash->{'header'}}[0];
1459 my $source = @{$msg_hash->{'source'}}[0];
1460 my $target = @{$msg_hash->{'target'}}[0];
1461 my $softwareLicenseId;
1462 my $out_hash;
1464 # Check input sanity
1465 if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
1466 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
1467 } else {
1468 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1469 }
1471 my $callobj = {
1472 method => 'getSoftwareLicense_hash',
1473 params => [ $softwareLicenseId ],
1474 id => 1,
1475 };
1476 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1478 # Check Opsi error
1479 my ($res_error, $res_error_str) = &check_opsi_res($res);
1480 if ($res_error){
1481 # Create error message
1482 &main::daemon_log("$session_id ERROR: cannot fetch information for license '$softwareLicenseId': ".$res_error_str, 1);
1483 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1484 return ( &create_xml_string($out_hash) );
1485 }
1487 # Create function result message
1488 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1489 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1490 &add_content2xml_hash($out_hash, "expirationDate", $res->result->{'expirationDate'});
1491 &add_content2xml_hash($out_hash, "boundToHost", $res->result->{'boundToHost'});
1492 &add_content2xml_hash($out_hash, "maxInstallations", $res->result->{'maxInstallations'});
1493 &add_content2xml_hash($out_hash, "licenseTyp", $res->result->{'licenseTyp'});
1494 foreach my $licensePoolId ( @{$res->result->{'licensePoolIds'}}) {
1495 &add_content2xml_hash($out_hash, "licensePoolId", $licensePoolId);
1496 &add_content2xml_hash($out_hash, $licensePoolId, $res->result->{'licenseKeys'}->{$licensePoolId});
1497 }
1499 my $endTime = Time::HiRes::time;
1500 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1501 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1502 return ( &create_xml_string($out_hash) );
1503 }
1505 ################################
1506 # @brief Delete licnese pool by license pool ID. A pool can only be deleted if there are no software licenses bound to the pool.
1507 # The fixed parameter deleteLicenses=True specifies that all software licenses bound to the pool are being deleted.
1508 # @param licensePoolId The name of the pool.
1509 sub opsi_deleteLicensePool {
1510 my $startTime = Time::HiRes::time;
1511 my ($msg, $msg_hash, $session_id) = @_;
1512 my $header = @{$msg_hash->{'header'}}[0];
1513 my $source = @{$msg_hash->{'source'}}[0];
1514 my $target = @{$msg_hash->{'target'}}[0];
1515 my $licensePoolId;
1516 my $out_hash;
1518 # Check input sanity
1519 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1520 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1521 } else {
1522 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1523 }
1525 # Fetch softwareLicenseIds used in license pool
1526 # This has to be done because function deleteLicensePool deletes the pool and the corresponding software licenses
1527 # but not the license contracts of the software licenses. In our case each software license has exactly one license contract.
1528 my $callobj = {
1529 method => 'getSoftwareLicenses_listOfHashes',
1530 params => [ ],
1531 id => 1,
1532 };
1533 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1535 # Keep list of licenseContractIds in mind to delete it after the deletion of the software licenses
1536 my @lCI_toBeDeleted;
1537 foreach my $softwareLicenseHash ( @{$res->result} ) {
1538 if ((@{$softwareLicenseHash->{'licensePoolIds'}} == 0) || (@{$softwareLicenseHash->{'licensePoolIds'}}[0] ne $licensePoolId)) {
1539 next;
1540 }
1541 push (@lCI_toBeDeleted, $softwareLicenseHash->{'licenseContractId'});
1542 }
1544 # Delete license pool at Opsi server
1545 $callobj = {
1546 method => 'deleteLicensePool',
1547 params => [ $licensePoolId, 'deleteLicenses=True' ],
1548 id => 1,
1549 };
1550 $res = $main::opsi_client->call($main::opsi_url, $callobj);
1551 my ($res_error, $res_error_str) = &check_opsi_res($res);
1552 if ($res_error){
1553 # Create error message
1554 &main::daemon_log("$session_id ERROR: cannot delete license pool at Opsi server: ".$res_error_str, 1);
1555 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1556 return ( &create_xml_string($out_hash) );
1557 }
1559 # Delete each license contract connected with the license pool
1560 foreach my $licenseContractId ( @lCI_toBeDeleted ) {
1561 my $callobj = {
1562 method => 'deleteLicenseContract',
1563 params => [ $licenseContractId ],
1564 id => 1,
1565 };
1566 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1567 my ($res_error, $res_error_str) = &check_opsi_res($res);
1568 if ($res_error){
1569 # Create error message
1570 &main::daemon_log("$session_id ERROR: cannot delete license contract '$licenseContractId' connected with license pool '$licensePoolId' at Opsi server: ".$res_error_str, 1);
1571 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1572 return ( &create_xml_string($out_hash) );
1573 }
1574 }
1576 # Create function result message
1577 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1578 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1580 my $endTime = Time::HiRes::time;
1581 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1582 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1583 return ( &create_xml_string($out_hash) );
1584 }
1586 ################################
1587 # @brief Create a license contract, create a software license and add the software license to the license pool
1588 # @param licensePoolId The name of the pool the license should be assigned.
1589 # @param licenseKey The license key.
1590 # @param partner Name of the license partner (optional).
1591 # @param conclusionDate Date of conclusion of license contract (optional)
1592 # @param notificationDate Date of notification that license is running out soon (optional).
1593 # @param notes This is the place for some notes (optional)
1594 # @param softwareLicenseId Identificator of a license (optional).
1595 # @param licenseTyp Typ of a licnese, either "OEM", "VOLUME" or "RETAIL" (optional).
1596 # @param maxInstallations The number of clients use this license (optional).
1597 # @param boundToHost The name of the client the license is bound to (optional).
1598 # @param expirationDate The date when the license is running down (optional).
1599 sub opsi_createLicense {
1600 my $startTime = Time::HiRes::time;
1601 my ($msg, $msg_hash, $session_id) = @_;
1602 my $header = @{$msg_hash->{'header'}}[0];
1603 my $source = @{$msg_hash->{'source'}}[0];
1604 my $target = @{$msg_hash->{'target'}}[0];
1605 my $partner = defined $msg_hash->{'partner'} ? @{$msg_hash->{'partner'}}[0] : undef;
1606 my $conclusionDate = defined $msg_hash->{'conclusionDate'} ? @{$msg_hash->{'conclusionDate'}}[0] : undef;
1607 my $notificationDate = defined $msg_hash->{'notificationDate'} ? @{$msg_hash->{'notificationDate'}}[0] : undef;
1608 my $notes = defined $msg_hash->{'notes'} ? @{$msg_hash->{'notes'}}[0] : undef;
1609 my $licenseContractId = undef;
1610 my $softwareLicenseId = defined $msg_hash->{'softwareLicenseId'} ? @{$msg_hash->{'softwareLicenseId'}}[0] : undef;
1611 my $licenseType = defined $msg_hash->{'licenseType'} ? @{$msg_hash->{'licenseType'}}[0] : undef;
1612 my $maxInstallations = defined $msg_hash->{'maxInstallations'} ? @{$msg_hash->{'maxInstallations'}}[0] : undef;
1613 my $boundToHost = defined $msg_hash->{'boundToHost'} ? @{$msg_hash->{'boundToHost'}}[0] : undef;
1614 my $expirationDate = defined $msg_hash->{'expirationDate'} ? @{$msg_hash->{'expirationDate'}}[0] : undef;
1615 my $licensePoolId;
1616 my $licenseKey;
1617 my $out_hash;
1619 # Check input sanity
1620 if (&_check_xml_tag_is_ok ($msg_hash, 'licenseKey')) {
1621 $licenseKey = @{$msg_hash->{'licenseKey'}}[0];
1622 } else {
1623 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1624 }
1625 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1626 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1627 } else {
1628 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1629 }
1630 if ((defined $licenseType) && (not exists $licenseTyp_hash->{$licenseType})) {
1631 return &_giveErrorFeedback($msg_hash, "The typ of a license can be either 'OEM', 'VOLUME' or 'RETAIL'.", $session_id);
1632 }
1634 # Automatically define licenseContractId if ID is not given
1635 if (defined $softwareLicenseId) {
1636 $licenseContractId = "c_".$softwareLicenseId;
1637 }
1639 # Create license contract at Opsi server
1640 my $callobj = {
1641 method => 'createLicenseContract',
1642 params => [ $licenseContractId, $partner, $conclusionDate, $notificationDate, undef, $notes ],
1643 id => 1,
1644 };
1645 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1647 # Check Opsi error
1648 my ($res_error, $res_error_str) = &check_opsi_res($res);
1649 if ($res_error){
1650 # Create error message
1651 &main::daemon_log("$session_id ERROR: cannot create license contract at Opsi server: ".$res_error_str, 1);
1652 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1653 return ( &create_xml_string($out_hash) );
1654 }
1656 $licenseContractId = $res->result;
1658 # Create software license at Opsi server
1659 $callobj = {
1660 method => 'createSoftwareLicense',
1661 params => [ $softwareLicenseId, $licenseContractId, $licenseType, $maxInstallations, $boundToHost, $expirationDate ],
1662 id => 1,
1663 };
1664 $res = $main::opsi_client->call($main::opsi_url, $callobj);
1666 # Check Opsi error
1667 ($res_error, $res_error_str) = &check_opsi_res($res);
1668 if ($res_error){
1669 # Create error message
1670 &main::daemon_log("$session_id ERROR: cannot create software license at Opsi server: ".$res_error_str, 1);
1671 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1672 return ( &create_xml_string($out_hash) );
1673 }
1675 $softwareLicenseId = $res->result;
1677 # Add software license to license pool
1678 $callobj = {
1679 method => 'addSoftwareLicenseToLicensePool',
1680 params => [ $softwareLicenseId, $licensePoolId, $licenseKey ],
1681 id => 1,
1682 };
1683 $res = $main::opsi_client->call($main::opsi_url, $callobj);
1685 # Check Opsi error
1686 ($res_error, $res_error_str) = &check_opsi_res($res);
1687 if ($res_error){
1688 # Create error message
1689 &main::daemon_log("$session_id ERROR: cannot add software license to license pool at Opsi server: ".$res_error_str, 1);
1690 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1691 return ( &create_xml_string($out_hash) );
1692 }
1694 # Create function result message
1695 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1696 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1698 my $endTime = Time::HiRes::time;
1699 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1700 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1701 return ( &create_xml_string($out_hash) );
1702 }
1704 ################################
1705 # @brief Assign a software license to a host
1706 # @param hostid Something like client_1.intranet.mydomain.de
1707 # @param licensePoolId The name of the pool.
1708 sub opsi_assignSoftwareLicenseToHost {
1709 my $startTime = Time::HiRes::time;
1710 my ($msg, $msg_hash, $session_id) = @_;
1711 my $header = @{$msg_hash->{'header'}}[0];
1712 my $source = @{$msg_hash->{'source'}}[0];
1713 my $target = @{$msg_hash->{'target'}}[0];
1714 my $hostId;
1715 my $licensePoolId;
1717 # Check input sanity
1718 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1719 $hostId = @{$msg_hash->{'hostId'}}[0];
1720 } else {
1721 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1722 }
1723 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1724 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1725 } else {
1726 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1727 }
1729 # Assign a software license to a host
1730 my $callobj = {
1731 method => 'getAndAssignSoftwareLicenseKey',
1732 params => [ $hostId, $licensePoolId ],
1733 id => 1,
1734 };
1735 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1737 # Check Opsi error
1738 my ($res_error, $res_error_str) = &check_opsi_res($res);
1739 if ($res_error){
1740 # Create error message
1741 &main::daemon_log("$session_id ERROR: cannot assign a software license to a host at Opsi server: ".$res_error_str, 1);
1742 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1743 return ( &create_xml_string($out_hash) );
1744 }
1746 # Create function result message
1747 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1748 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1750 my $endTime = Time::HiRes::time;
1751 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1752 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1753 return ( &create_xml_string($out_hash) );
1754 }
1756 ################################
1757 # @brief Unassign a software license from a host.
1758 # @param hostid Something like client_1.intranet.mydomain.de
1759 # @param licensePoolId The name of the pool.
1760 sub opsi_unassignSoftwareLicenseFromHost {
1761 my $startTime = Time::HiRes::time;
1762 my ($msg, $msg_hash, $session_id) = @_;
1763 my $header = @{$msg_hash->{'header'}}[0];
1764 my $source = @{$msg_hash->{'source'}}[0];
1765 my $target = @{$msg_hash->{'target'}}[0];
1766 my $hostId;
1767 my $licensePoolId;
1769 # Check input sanity
1770 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1771 $hostId = @{$msg_hash->{'hostId'}}[0];
1772 } else {
1773 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1774 }
1775 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1776 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1777 } else {
1778 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1779 }
1781 # Unassign a software license from a host
1782 my $callobj = {
1783 method => 'deleteSoftwareLicenseUsage',
1784 params => [ $hostId, '', $licensePoolId ],
1785 id => 1,
1786 };
1787 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1789 # Check Opsi error
1790 my ($res_error, $res_error_str) = &check_opsi_res($res);
1791 if ($res_error){
1792 # Create error message
1793 &main::daemon_log("$session_id ERROR: cannot unassign a software license from a host at Opsi server: ".$res_error_str, 1);
1794 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1795 return ( &create_xml_string($out_hash) );
1796 }
1798 # Create function result message
1799 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1800 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1802 my $endTime = Time::HiRes::time;
1803 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1804 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1805 return ( &create_xml_string($out_hash) );
1806 }
1808 ################################
1809 # @brief Unassign all software licenses from a host
1810 # @param hostid Something like client_1.intranet.mydomain.de
1811 sub opsi_unassignAllSoftwareLicensesFromHost {
1812 my $startTime = Time::HiRes::time;
1813 my ($msg, $msg_hash, $session_id) = @_;
1814 my $header = @{$msg_hash->{'header'}}[0];
1815 my $source = @{$msg_hash->{'source'}}[0];
1816 my $target = @{$msg_hash->{'target'}}[0];
1817 my $hostId;
1819 # Check input sanity
1820 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1821 $hostId = @{$msg_hash->{'hostId'}}[0];
1822 } else {
1823 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1824 }
1826 # Unassign all software licenses from a host
1827 my $callobj = {
1828 method => 'deleteAllSoftwareLicenseUsages',
1829 params => [ $hostId ],
1830 id => 1,
1831 };
1832 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1834 # Check Opsi error
1835 my ($res_error, $res_error_str) = &check_opsi_res($res);
1836 if ($res_error){
1837 # Create error message
1838 &main::daemon_log("$session_id ERROR: cannot unassign a software license from a host at Opsi server: ".$res_error_str, 1);
1839 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1840 return ( &create_xml_string($out_hash) );
1841 }
1843 # Create function result message
1844 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1845 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1847 my $endTime = Time::HiRes::time;
1848 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1849 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1850 return ( &create_xml_string($out_hash) );
1851 }
1854 ################################
1855 # @brief Returns the assigned licensePoolId and licenses, how often the product is installed and at which host
1856 # and the number of max and remaining installations for a given OPSI product.
1857 # @param productId Identificator of an OPSI product.
1858 sub opsi_getLicenseInformationForProduct {
1859 my $startTime = Time::HiRes::time;
1860 my ($msg, $msg_hash, $session_id) = @_;
1861 my $header = @{$msg_hash->{'header'}}[0];
1862 my $source = @{$msg_hash->{'source'}}[0];
1863 my $productId;
1864 my $out_hash;
1866 # Check input sanity
1867 if (&_check_xml_tag_is_ok ($msg_hash, 'productId')) {
1868 $productId = @{$msg_hash->{'productId'}}[0];
1869 } else {
1870 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1871 }
1873 # Fetch infos from Opsi server
1874 my $callobj = {
1875 method => 'getLicensePoolId',
1876 params => [ $productId ],
1877 id => 1,
1878 };
1879 #my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1880 my $res = $opsi_client->call($opsi_url, $callobj);
1882 # Check Opsi error
1883 my ($res_error, $res_error_str) = &check_opsi_res($res);
1884 if ($res_error){
1885 return &_giveErrorFeedback($msg_hash, "cannot get license pool for product '$productId' : ".$res_error_str, $session_id);
1886 }
1888 my $licensePoolId = $res->result;
1890 # Fetch statistic information for given pool ID
1891 $callobj = {
1892 method => 'getLicenseStatistics_hash',
1893 params => [ ],
1894 id => 1,
1895 };
1896 $res = $opsi_client->call($opsi_url, $callobj);
1898 # Check Opsi error
1899 ($res_error, $res_error_str) = &check_opsi_res($res);
1900 if ($res_error){
1901 # Create error message
1902 &main::daemon_log("$session_id ERROR: cannot get statistic informations for license pools : ".$res_error_str, 1);
1903 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1904 return ( &create_xml_string($out_hash) );
1905 }
1907 # Create function result message
1908 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1909 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1910 &add_content2xml_hash($out_hash, "licensePoolId", $licensePoolId);
1911 &add_content2xml_hash($out_hash, "licenses", $res->result->{$licensePoolId}->{'licenses'});
1912 &add_content2xml_hash($out_hash, "usageCount", $res->result->{$licensePoolId}->{'usageCount'});
1913 &add_content2xml_hash($out_hash, "maxInstallations", $res->result->{$licensePoolId}->{'maxInstallations'});
1914 &add_content2xml_hash($out_hash, "remainingInstallations", $res->result->{$licensePoolId}->{'remainingInstallations'});
1915 map(&add_content2xml_hash($out_hash, "usedBy", "$_"), @{ $res->result->{$licensePoolId}->{'usedBy'}});
1917 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1918 return ( &create_xml_string($out_hash) );
1919 }
1922 ################################
1923 # @brief Returns licensePoolId, description, a list of productIds, al list of windowsSoftwareIds and a list of licenses for a given licensePoolId.
1924 # Each license contains softwareLicenseId, maxInstallations, licenseType, licensePoolIds, licenseKeys, hostIds, expirationDate, boundToHost and licenseContractId.
1925 # The licenseContract contains conclusionDate, expirationDate, notes, notificationDate and partner.
1926 # @param licensePoolId The name of the pool.
1927 sub opsi_getPool {
1928 my $startTime = Time::HiRes::time;
1929 my ($msg, $msg_hash, $session_id) = @_;
1930 my $header = @{$msg_hash->{'header'}}[0];
1931 my $source = @{$msg_hash->{'source'}}[0];
1933 # Check input sanity
1934 my $licensePoolId;
1935 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1936 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1937 } else {
1938 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1939 }
1941 # Create hash for the answer
1942 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1943 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1945 # Call Opsi
1946 my ($res, $err) = &_getLicensePool_hash( 'licensePoolId'=> $licensePoolId );
1947 if ($err){
1948 return &_giveErrorFeedback($msg_hash, "cannot get license pool from Opsi server: ".$res, $session_id);
1949 }
1950 # Add data to outgoing hash
1951 &add_content2xml_hash($out_hash, "licensePoolId", $res->{'licensePoolId'});
1952 &add_content2xml_hash($out_hash, "description", $res->{'description'});
1953 map(&add_content2xml_hash($out_hash, "productIds", "$_"), @{ $res->{'productIds'} });
1954 map(&add_content2xml_hash($out_hash, "windowsSoftwareIds", "$_"), @{ $res->{'windowsSoftwareIds'} });
1957 # Call Opsi two times
1958 my ($usages_res, $usages_err) = &_getSoftwareLicenseUsages_listOfHashes('licensePoolId'=>$licensePoolId);
1959 if ($usages_err){
1960 return &_giveErrorFeedback($msg_hash, "cannot get software license usage information from Opsi server: ".$usages_res, $session_id);
1961 }
1962 my ($licenses_res, $licenses_err) = &_getSoftwareLicenses_listOfHashes();
1963 if ($licenses_err){
1964 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server: ".$licenses_res, $session_id);
1965 }
1967 # Add data to outgoing hash
1968 # Parse through all software licenses and select those associated to the pool
1969 my $res_hash = { 'hit'=> [] };
1970 foreach my $license ( @$licenses_res) {
1971 # Each license hash has a list of licensePoolIds so go through this list and search for matching licensePoolIds
1972 my $found = 0;
1973 my @licensePoolIds_list = @{$license->{licensePoolIds}};
1974 foreach my $lPI ( @licensePoolIds_list) {
1975 if ($lPI eq $licensePoolId) { $found++ }
1976 }
1977 if (not $found ) { next; };
1978 # Found matching licensePoolId
1979 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
1980 'licenseKeys' => {},
1981 'expirationDate' => [$license->{'expirationDate'}],
1982 'boundToHost' => [$license->{'boundToHost'}],
1983 'maxInstallations' => [$license->{'maxInstallations'}],
1984 'licenseType' => [$license->{'licenseType'}],
1985 'licenseContractId' => [$license->{'licenseContractId'}],
1986 'licensePoolIds' => [],
1987 'hostIds' => [],
1988 };
1989 foreach my $licensePoolId (@{ $license->{'licensePoolIds'}}) {
1990 push( @{$license_hash->{'licensePoolIds'}}, $licensePoolId);
1991 $license_hash->{licenseKeys}->{$licensePoolId} = [ $license->{'licenseKeys'}->{$licensePoolId} ];
1992 }
1993 foreach my $usage (@$usages_res) {
1994 # Search for hostIds with matching softwareLicenseId
1995 if ($license->{'softwareLicenseId'} eq $usage->{'softwareLicenseId'}) {
1996 push( @{ $license_hash->{hostIds}}, $usage->{hostId});
1997 }
1998 }
2000 # Each softwareLicenseId has one licenseContractId, fetch contract details for each licenseContractId
2001 my ($lContract_res, $lContract_err) = &_getLicenseContract_hash('licenseContractId'=>$license->{licenseContractId});
2002 if ($lContract_err){
2003 return &_giveErrorFeedback($msg_hash, "cannot get software license contract information from Opsi server: ".$licenses_res, $session_id);
2004 }
2005 $license_hash->{$license->{'licenseContractId'}} = [];
2006 my $licenseContract_hash = { 'conclusionDate' => [$lContract_res->{conclusionDate}],
2007 'notificationDate' => [$lContract_res->{notificationDate}],
2008 'notes' => [$lContract_res->{notes}],
2009 'exirationDate' => [$lContract_res->{expirationDate}],
2010 'partner' => [$lContract_res->{partner}],
2011 };
2012 push( @{$license_hash->{licenseContractData}}, $licenseContract_hash );
2014 push( @{$res_hash->{hit}}, $license_hash );
2015 }
2016 $out_hash->{licenses} = [$res_hash];
2018 my $endTime = Time::HiRes::time;
2019 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2020 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2021 return ( &create_xml_string($out_hash) );
2022 }
2025 ################################
2026 # @brief Removes at first the software license from license pool and than deletes the software license.
2027 # Attention, the software license has to exists otherwise it will lead to an Opsi internal server error.
2028 # @param softwareLicenseId Identificator of a license.
2029 # @param licensePoolId The name of the pool.
2030 sub opsi_removeLicense {
2031 my $startTime = Time::HiRes::time;
2032 my ($msg, $msg_hash, $session_id) = @_;
2033 my $header = @{$msg_hash->{'header'}}[0];
2034 my $source = @{$msg_hash->{'source'}}[0];
2036 # Check input sanity
2037 my $softwareLicenseId;
2038 if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
2039 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
2040 } else {
2041 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2042 }
2043 my $licensePoolId;
2044 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
2045 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
2046 } else {
2047 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2048 }
2050 # Call Opsi
2051 my ($res, $err) = &_removeSoftwareLicenseFromLicensePool( 'licensePoolId' => $licensePoolId, 'softwareLicenseId' => $softwareLicenseId );
2052 if ($err){
2053 return &_giveErrorFeedback($msg_hash, "cannot delete software license from pool: ".$res, $session_id);
2054 }
2056 # Call Opsi
2057 ($res, $err) = &_deleteSoftwareLicense( 'softwareLicenseId'=>$softwareLicenseId );
2058 if ($err){
2059 return &_giveErrorFeedback($msg_hash, "cannot delete software license from Opsi server: ".$res, $session_id);
2060 }
2062 # Create hash for the answer
2063 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2064 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2065 my $endTime = Time::HiRes::time;
2066 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2067 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2068 return ( &create_xml_string($out_hash) );
2069 }
2072 ################################
2073 # @brief Return softwareLicenseId, maxInstallations, licenseType, licensePoolIds, licenseContractId, expirationDate, boundToHost and a list of productIds.
2074 # @param hostId Something like client_1.intranet.mydomain.de
2075 sub opsi_getReservedLicenses {
2076 my $startTime = Time::HiRes::time;
2077 my ($msg, $msg_hash, $session_id) = @_;
2078 my $header = @{$msg_hash->{'header'}}[0];
2079 my $source = @{$msg_hash->{'source'}}[0];
2081 # Check input sanity
2082 my $hostId;
2083 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
2084 $hostId = @{$msg_hash->{'hostId'}}[0];
2085 } else {
2086 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2087 }
2089 # Fetch informations from Opsi server
2090 my ($license_res, $license_err) = &_getSoftwareLicenses_listOfHashes();
2091 if ($license_err){
2092 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server: ".$license_res, $session_id);
2093 }
2095 # Parse result
2096 my $res_hash = { 'hit'=> [] };
2097 foreach my $license ( @$license_res) {
2098 if ($license->{boundToHost} ne $hostId) { next; }
2100 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
2101 'maxInstallations' => [$license->{'maxInstallations'}],
2102 'boundToHost' => [$license->{'boundToHost'}],
2103 'expirationDate' => [$license->{'expirationDate'}],
2104 'licenseContractId' => [$license->{'licenseContractId'}],
2105 'licenseType' => [$license->{'licenseType'}],
2106 'licensePoolIds' => [],
2107 };
2109 foreach my $licensePoolId (@{$license->{'licensePoolIds'}}) {
2110 # Fetch information for license pools containing a software license which is bound to given host
2111 my ($pool_res, $pool_err) = &_getLicensePool_hash( 'licensePoolId'=>$licensePoolId );
2112 if ($pool_err){
2113 return &_giveErrorFeedback($msg_hash, "cannot get license pool from Opsi server: ".$pool_res, $session_id);
2114 }
2116 # Add licensePool information to result hash
2117 push (@{$license_hash->{licensePoolIds}}, $licensePoolId);
2118 $license_hash->{$licensePoolId} = {'productIds'=>[], 'windowsSoftwareIds'=>[]};
2119 map (push (@{$license_hash->{$licensePoolId}->{productIds}}, $_), @{$pool_res->{productIds}});
2120 map (push (@{$license_hash->{$licensePoolId}->{windowsSoftwareIds}}, $_), @{$pool_res->{windowsSoftwareIds}});
2121 }
2122 push( @{$res_hash->{hit}}, $license_hash );
2123 }
2124 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2125 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2126 $out_hash->{licenses} = [$res_hash];
2128 my $endTime = Time::HiRes::time;
2129 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2130 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2131 return ( &create_xml_string($out_hash) );
2132 }
2134 ################################
2135 # @brief Bound the given softwareLicenseId to the given host.
2136 # @param hostId Opsi hostId
2137 # @param softwareLicenseId Identificator of a license (optional).
2138 sub opsi_boundHostToLicense {
2139 my $startTime = Time::HiRes::time;
2140 my ($msg, $msg_hash, $session_id) = @_;
2141 my $header = @{$msg_hash->{'header'}}[0];
2142 my $source = @{$msg_hash->{'source'}}[0];
2144 # Check input sanity
2145 my $hostId;
2146 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
2147 $hostId = @{$msg_hash->{'hostId'}}[0];
2148 } else {
2149 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2150 }
2151 my $softwareLicenseId;
2152 if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
2153 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
2154 } else {
2155 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2156 }
2158 # Fetch informations from Opsi server
2159 my ($license_res, $license_err) = &_getSoftwareLicenses_listOfHashes();
2160 if ($license_err){
2161 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server: ".$license_res, $session_id);
2162 }
2164 # Memorize parameter for given softwareLicenseId
2165 my $licenseContractId;
2166 my $licenseType;
2167 my $maxInstallations;
2168 my $boundToHost;
2169 my $expirationDate = "";
2170 my $found;
2171 foreach my $license (@$license_res) {
2172 if ($license->{softwareLicenseId} ne $softwareLicenseId) { next; }
2173 $licenseContractId = $license->{licenseContractId};
2174 $licenseType = $license->{licenseType};
2175 $maxInstallations = $license->{maxInstallations};
2176 $expirationDate = $license->{expirationDate};
2177 $found++;
2178 }
2180 if (not $found) {
2181 return &_giveErrorFeedback($msg_hash, "no softwarelicenseId found with name '".$softwareLicenseId."'", $session_id);
2182 }
2184 # Set boundToHost option for a given software license
2185 my ($bound_res, $bound_err) = &_createSoftwareLicense('softwareLicenseId'=>$softwareLicenseId,
2186 'licenseContractId' => $licenseContractId,
2187 'licenseType' => $licenseType,
2188 'maxInstallations' => $maxInstallations,
2189 'boundToHost' => $hostId,
2190 'expirationDate' => $expirationDate);
2191 if ($bound_err) {
2192 return &_giveErrorFeedback($msg_hash, "cannot set boundToHost for given softwareLicenseId and hostId: ".$bound_res, $session_id);
2193 }
2195 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2196 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2198 my $endTime = Time::HiRes::time;
2199 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2200 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2201 return ( &create_xml_string($out_hash) );
2202 }
2204 ################################
2205 # @brief Release a software license formerly bound to a host.
2206 # @param softwareLicenseId Identificator of a license.
2207 sub opsi_unboundHostFromLicense {
2208 # This is really mad! Opsi is not able to unbound a lincense from a host. To provide the functionality for GOsa
2209 # 4 rpc calls to Opsi are necessary. First, fetch all data for the given softwareLicenseId, then all details for the associated
2210 # licenseContractId, then delete the softwareLicense and finally recreate the softwareLicense without the boundToHost option. NASTY!
2211 my $startTime = Time::HiRes::time;
2212 my ($msg, $msg_hash, $session_id) = @_;
2213 my $header = @{$msg_hash->{'header'}}[0];
2214 my $source = @{$msg_hash->{'source'}}[0];
2216 # Check input sanity
2217 my $softwareLicenseId;
2218 if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
2219 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
2220 } else {
2221 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2222 }
2224 # Memorize parameter witch are required for this procedure
2225 my $licenseContractId;
2226 my $licenseType;
2227 my $maxInstallations;
2228 my $expirationDate;
2229 my $partner;
2230 my $conclusionDate;
2231 my $notificationDate;
2232 my $notes;
2233 my $licensePoolId;
2234 my $licenseKey;
2236 # Fetch license informations from Opsi server
2237 my ($license_res, $license_err) = &_getSoftwareLicenses_listOfHashes();
2238 if ($license_err){
2239 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server, required to unbound license from host: ".$license_res, $session_id);
2240 }
2241 my $found = 0;
2242 foreach my $license (@$license_res) {
2243 if (($found > 0) || ($license->{softwareLicenseId} ne $softwareLicenseId)) { next; }
2244 $licenseContractId = $license->{licenseContractId};
2245 $licenseType = $license->{licenseType};
2246 $maxInstallations = $license->{maxInstallations};
2247 $expirationDate = $license->{expirationDate};
2248 $licensePoolId = @{$license->{licensePoolIds}}[0];
2249 $licenseKey = $license->{licenseKeys}->{$licensePoolId};
2250 $found++;
2251 }
2253 # Fetch contract informations from Opsi server
2254 my ($contract_res, $contract_err) = &_getLicenseContract_hash('licenseContractId'=>$licenseContractId);
2255 if ($contract_err){
2256 return &_giveErrorFeedback($msg_hash, "cannot get contract license information from Opsi server, required to unbound license from host: ".$license_res, $session_id);
2257 }
2258 $partner = $contract_res->{partner};
2259 $conclusionDate = $contract_res->{conclusionDate};
2260 $notificationDate = $contract_res->{notificationDate};
2261 $expirationDate = $contract_res->{expirationDate};
2262 $notes = $contract_res->{notes};
2264 # Delete software license
2265 my ($res, $err) = &_deleteSoftwareLicense( 'softwareLicenseId' => $softwareLicenseId, 'removeFromPools'=> "true" );
2266 if ($err) {
2267 return &_giveErrorFeedback($msg_hash, "cannot delet license from Opsi server, required to unbound license from host : ".$res, $session_id);
2268 }
2270 # Recreate software license without boundToHost
2271 ($res, $err) = &_createLicenseContract( 'licenseContractId' => $licenseContractId, 'partner' => $partner, 'conclusionDate' => $conclusionDate,
2272 'notificationDate' => $notificationDate, 'expirationDate' => $expirationDate, 'notes' => $notes );
2273 if ($err) {
2274 return &_giveErrorFeedback($msg_hash, "cannot create license contract at Opsi server, required to unbound license from host : ".$res, $session_id);
2275 }
2276 ($res, $err) = &_createSoftwareLicense( 'softwareLicenseId' => $softwareLicenseId, 'licenseContractId' => $licenseContractId, 'licenseType' => $licenseType,
2277 'maxInstallations' => $maxInstallations, 'boundToHost' => "", 'expirationDate' => $expirationDate );
2278 if ($err) {
2279 return &_giveErrorFeedback($msg_hash, "cannot create software license at Opsi server, required to unbound license from host : ".$res, $session_id);
2280 }
2281 ($res, $err) = &_addSoftwareLicenseToLicensePool( 'softwareLicenseId' => $softwareLicenseId, 'licensePoolId' => $licensePoolId, 'licenseKey' => $licenseKey );
2282 if ($err) {
2283 return &_giveErrorFeedback($msg_hash, "cannot add software license to license pool at Opsi server, required to unbound license from host : ".$res, $session_id);
2284 }
2286 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2287 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2289 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
2290 return ( &create_xml_string($out_hash) );
2291 }
2293 ################################
2294 # @brief Returns a list of licenses with softwaerLicenseId, maxInstallations, boundToHost, expirationDate, licenseContractId, licenseType, a list of licensePoolIds with associated licenseKeys
2295 sub opsi_getAllSoftwareLicenses {
2296 my $startTime = Time::HiRes::time;
2297 my ($msg, $msg_hash, $session_id) = @_;
2298 my $header = @{$msg_hash->{'header'}}[0];
2299 my $source = @{$msg_hash->{'source'}}[0];
2301 my ($res, $err) = &_getSoftwareLicenses_listOfHashes();
2302 if ($err) {
2303 return &_giveErrorFeedback($msg_hash, "cannot fetch software licenses from Opsi server : ".$res, $session_id);
2304 }
2306 # Parse result
2307 my $res_hash = { 'hit'=> [] };
2308 foreach my $license ( @$res) {
2309 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
2310 'maxInstallations' => [$license->{'maxInstallations'}],
2311 'boundToHost' => [$license->{'boundToHost'}],
2312 'expirationDate' => [$license->{'expirationDate'}],
2313 'licenseContractId' => [$license->{'licenseContractId'}],
2314 'licenseType' => [$license->{'licenseType'}],
2315 'licensePoolIds' => [],
2316 'licenseKeys'=> {}
2317 };
2318 foreach my $licensePoolId (@{$license->{'licensePoolIds'}}) {
2319 push( @{$license_hash->{'licensePoolIds'}}, $licensePoolId);
2320 $license_hash->{licenseKeys}->{$licensePoolId} = [ $license->{'licenseKeys'}->{$licensePoolId} ];
2321 }
2322 push( @{$res_hash->{hit}}, $license_hash );
2323 }
2325 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2326 $out_hash->{licenses} = [$res_hash];
2327 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2329 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
2330 return ( &create_xml_string($out_hash) );
2331 }
2334 ################################
2335 # @brief Returns a list of values for a given host. Values: priority, onceScript, licenseRequired, packageVersion, productVersion, advice, setupScript, windowsSoftwareIds, installationStatus, pxeConfigTemplate, name, creationTimestamp, alwaysScript, productId, description, properties, actionRequest, uninstallScript, action, updateScript and productClassNames
2336 # @param hostId Opsi hostId
2337 sub opsi_get_full_product_host_information {
2338 my $startTime = Time::HiRes::time;
2339 my ($msg, $msg_hash, $session_id) = @_;
2340 my $header = @{$msg_hash->{'header'}}[0];
2341 my $source = @{$msg_hash->{'source'}}[0];
2342 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
2343 my $hostId;
2345 my ($res, $err) = &_get_full_product_host_information( hostId=>@{$msg_hash->{'hostId'}}[0]);
2346 if ($err) {
2347 return &_giveErrorFeedback($msg_hash, "cannot fetch full_product_host_information from Opsi server : ".$res, $session_id);
2348 }
2350 # Build return message with twisted target and source
2351 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2352 if (defined $forward_to_gosa) {
2353 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
2354 }
2355 &add_content2xml_hash($out_hash, "xxx", "");
2357 # Get hostId if defined
2358 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1)) {
2359 $hostId = @{$msg_hash->{'hostId'}}[0];
2360 &add_content2xml_hash($out_hash, "hostId", $hostId);
2361 }
2363 # Move to XML string
2364 my $xml_msg= &create_xml_string($out_hash);
2366 # Convert result in something usable
2367 my $replace= "";
2368 foreach my $product ( @$res) {
2370 # Open item
2371 $replace.= "<item>";
2373 # Add flat hash information
2374 my @entries= ( "priority", "onceScript", "licenseRequired", "packageVersion", "productVersion", "advice",
2375 "setupScript", "windowsSoftwareIds", "installationStatus", "pxeConfigTemplate", "name", "type",
2376 "creationTimestamp", "alwaysScript", "productId", "description", "actionRequest", "uninstallScript",
2377 "action", "updateScript", "productClassNames");
2378 foreach my $entry (@entries) {
2379 if (defined $product->{$entry}) {
2380 my $value= $product->{$entry};
2382 if(ref($value) eq 'ARRAY'){
2383 my $tmp= "";
2384 foreach my $element (@$value) {
2385 $tmp.= "<element>$element</element>";
2386 }
2387 $replace.= "<$entry>$tmp</$entry>";
2388 } else {
2389 $replace.= "<$entry>$value</$entry>";
2390 }
2391 }
2392 }
2394 # Add property information
2395 if (defined $product->{'properties'}) {
2396 $replace.= "<properties>";
2397 while ((my $key, my $value) = each(%{$product->{'properties'}})){
2398 $replace.= "<$key>";
2400 while ((my $pkey, my $pvalue) = each(%$value)){
2401 if(ref($pvalue) eq 'ARRAY'){
2402 my $tmp= "";
2403 foreach my $element (@$pvalue) {
2404 $tmp.= "<element>$element</element>";
2405 }
2406 $replace.= "<$pkey>$tmp</$pkey>";
2407 } else {
2408 $replace.= "<$pkey>$pvalue</$pkey>";
2409 }
2410 }
2411 $replace.= "</$key>";
2412 }
2413 $replace.= "</properties>";
2414 }
2416 # Close item
2417 $replace.= "</item>";
2418 }
2420 $xml_msg=~ s/<xxx><\/xxx>/\n$replace/;
2422 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
2423 return ( $xml_msg );
2424 }
2427 sub opsi_test {
2428 my ($msg, $msg_hash, $session_id) = @_;
2429 my $header = @{$msg_hash->{'header'}}[0];
2430 my $source = @{$msg_hash->{'source'}}[0];
2431 my $pram1 = @{$msg_hash->{'productId'}}[0];
2434 # Fetch infos from Opsi server
2435 my $callobj = {
2436 method => 'getLicensePoolId',
2437 params => [ $pram1 ],
2438 id => 1,
2439 };
2440 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
2442 return ();
2443 }
2446 # ----------------------------------------------------------------------------
2447 # internal methods handling the comunication with Opsi
2448 # ----------------------------------------------------------------------------
2450 ################################
2451 # @brief Checks if there is a specified tag and if the the tag has a content.
2452 sub _check_xml_tag_is_ok {
2453 my ($msg_hash,$tag) = @_;
2454 if (not defined $msg_hash->{$tag}) {
2455 $_ = "message contains no tag '$tag'";
2456 return 0;
2457 }
2458 if (ref @{$msg_hash->{$tag}}[0] eq 'HASH') {
2459 $_ = "message tag '$tag' has no content";
2460 return 0;
2461 }
2462 return 1;
2463 }
2465 ################################
2466 # @brief Writes the log line and returns the error message for GOsa.
2467 sub _giveErrorFeedback {
2468 my ($msg_hash, $err_string, $session_id) = @_;
2469 &main::daemon_log("$session_id ERROR: $err_string", 1);
2470 my $out_hash = &main::create_xml_hash("error", $main::server_address, @{$msg_hash->{source}}[0], $err_string);
2471 if (exists $msg_hash->{forward_to_gosa}) {
2472 &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]);
2473 }
2474 return ( &create_xml_string($out_hash) );
2475 }
2478 ################################
2479 # @brief Perform the call to the Opsi server and measure the time for the call
2480 sub _callOpsi {
2481 my %arg = ('method'=>undef, 'params'=>[], 'id'=>1, @_);
2483 my $callObject = {
2484 method => $arg{method},
2485 params => $arg{params},
2486 id => $arg{id},
2487 };
2489 my $startTime = Time::HiRes::time;
2490 my $opsiResult = $opsi_client->call($opsi_url, $callObject);
2491 my $endTime = Time::HiRes::time;
2492 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2494 &main::daemon_log("0 DEBUG: time to process opsi call '$arg{method}' : $elapsedTime seconds", 1034);
2496 return $opsiResult;
2497 }
2499 sub _getLicensePool_hash {
2500 my %arg = ( 'licensePoolId' => undef, @_ );
2502 if (not defined $arg{licensePoolId} ) {
2503 return ("function requires licensePoolId as parameter", 1);
2504 }
2506 my $res = &_callOpsi( method => 'getLicensePool_hash', params =>[$arg{licensePoolId}], id => 1 );
2507 my ($res_error, $res_error_str) = &check_opsi_res($res);
2508 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2510 return ($res->result, 0);
2511 }
2513 sub _getSoftwareLicenses_listOfHashes {
2515 my $res = &_callOpsi( method => 'getSoftwareLicenses_listOfHashes' );
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 _getSoftwareLicenseUsages_listOfHashes {
2523 my %arg = ( 'hostId' => "", 'licensePoolId' => "", @_ );
2525 my $res = &_callOpsi( method=>'getSoftwareLicenseUsages_listOfHashes', params=>[ $arg{hostId}, $arg{licensePoolId} ] );
2526 my ($res_error, $res_error_str) = &check_opsi_res($res);
2527 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2529 return ($res->result, 0);
2530 }
2532 sub _removeSoftwareLicenseFromLicensePool {
2533 my %arg = ( 'softwareLicenseId' => undef, 'licensePoolId' => undef, @_ );
2535 if (not defined $arg{softwareLicenseId} ) {
2536 return ("function requires softwareLicenseId as parameter", 1);
2537 }
2538 if (not defined $arg{licensePoolId} ) {
2539 return ("function requires licensePoolId as parameter", 1);
2540 }
2542 my $res = &_callOpsi( method=>'removeSoftwareLicenseFromLicensePool', params=>[ $arg{softwareLicenseId}, $arg{licensePoolId} ] );
2543 my ($res_error, $res_error_str) = &check_opsi_res($res);
2544 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2546 return ($res->result, 0);
2547 }
2549 sub _deleteSoftwareLicense {
2550 my %arg = ( 'softwareLicenseId' => undef, 'removeFromPools' => "false", @_ );
2552 if (not defined $arg{softwareLicenseId} ) {
2553 return ("function requires softwareLicenseId as parameter", 1);
2554 }
2555 my $removeFromPools = "";
2556 if ((defined $arg{removeFromPools}) && ($arg{removeFromPools} eq "true")) {
2557 $removeFromPools = "removeFromPools";
2558 }
2560 my $res = &_callOpsi( method=>'deleteSoftwareLicense', params=>[ $arg{softwareLicenseId}, $removeFromPools ] );
2561 my ($res_error, $res_error_str) = &check_opsi_res($res);
2562 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2564 return ($res->result, 0);
2565 }
2567 sub _getLicensePoolId {
2568 my %arg = ( 'productId' => undef, @_ );
2570 if (not defined $arg{productId} ) {
2571 return ("function requires productId as parameter", 1);
2572 }
2574 my $res = &_callOpsi( method => 'getLicensePoolId', params => [ $arg{productId} ] );
2575 my ($res_error, $res_error_str) = &check_opsi_res($res);
2576 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2578 return ($res->result, 0);
2579 }
2581 sub _getLicenseContract_hash {
2582 my %arg = ( 'licenseContractId' => undef, @_ );
2584 if (not defined $arg{licenseContractId} ) {
2585 return ("function requires licenseContractId as parameter", 1);
2586 }
2588 my $res = &_callOpsi( method => 'getLicenseContract_hash', params => [ $arg{licenseContractId} ] );
2589 my ($res_error, $res_error_str) = &check_opsi_res($res);
2590 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2592 return ($res->result, 0);
2593 }
2595 sub _createLicenseContract {
2596 my %arg = (
2597 'licenseContractId' => undef,
2598 'partner' => undef,
2599 'conclusionDate' => undef,
2600 'notificationDate' => undef,
2601 'expirationDate' => undef,
2602 'notes' => undef,
2603 @_ );
2605 my $res = &_callOpsi( method => 'createLicenseContract',
2606 params => [ $arg{licenseContractId}, $arg{partner}, $arg{conclusionDate}, $arg{notificationDate}, $arg{expirationDate}, $arg{notes} ],
2607 );
2608 my ($res_error, $res_error_str) = &check_opsi_res($res);
2609 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2611 return ($res->result, 0);
2612 }
2614 sub _createSoftwareLicense {
2615 my %arg = (
2616 'softwareLicenseId' => undef,
2617 'licenseContractId' => undef,
2618 'licenseType' => undef,
2619 'maxInstallations' => undef,
2620 'boundToHost' => undef,
2621 'expirationDate' => undef,
2622 @_ );
2624 my $res = &_callOpsi( method => 'createSoftwareLicense',
2625 params => [ $arg{softwareLicenseId}, $arg{licenseContractId}, $arg{licenseType}, $arg{maxInstallations}, $arg{boundToHost}, $arg{expirationDate} ],
2626 );
2627 my ($res_error, $res_error_str) = &check_opsi_res($res);
2628 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2630 return ($res->result, 0);
2631 }
2633 sub _addSoftwareLicenseToLicensePool {
2634 my %arg = (
2635 'softwareLicenseId' => undef,
2636 'licensePoolId' => undef,
2637 'licenseKey' => undef,
2638 @_ );
2640 if (not defined $arg{softwareLicenseId} ) {
2641 return ("function requires softwareLicenseId as parameter", 1);
2642 }
2643 if (not defined $arg{licensePoolId} ) {
2644 return ("function requires licensePoolId as parameter", 1);
2645 }
2647 my $res = &_callOpsi( method => 'addSoftwareLicenseToLicensePool', params => [ $arg{softwareLicenseId}, $arg{licensePoolId}, $arg{licenseKey} ] );
2648 my ($res_error, $res_error_str) = &check_opsi_res($res);
2649 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2651 return ($res->result, 0);
2652 }
2654 sub _getProductStates_hash {
2655 my %arg = ( 'hostId' => undef, @_ );
2657 if (not defined $arg{hostId} ) {
2658 return ("function requires hostId as parameter", 1);
2659 }
2661 my $res = &_callOpsi( method => 'getProductStates_hash', params => [$arg{hostId}]);
2662 my ($res_error, $res_error_str) = &check_opsi_res($res);
2663 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2665 return ($res->result, 0);
2666 }
2668 sub _get_full_product_host_information {
2669 my %arg = ( 'hostId' => undef, @_ );
2671 my $res = &_callOpsi( method => 'getFullProductHostInformation_list', params => [$arg{hostId}]);
2672 my ($res_error, $res_error_str) = &check_opsi_res($res);
2673 if ($res_error){ return ((caller(0))[3]." : ".$res_error_str, 1); }
2675 return ($res->result, 0);
2676 }
2678 1;