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 @ISA = qw(Exporter);
18 my @events = (
19 "get_events",
20 "opsi_install_client",
21 "opsi_get_netboot_products",
22 "opsi_get_local_products",
23 "opsi_get_client_hardware",
24 "opsi_get_client_software",
25 "opsi_get_product_properties",
26 "opsi_get_full_product_host_information",
27 "opsi_set_product_properties",
28 "opsi_list_clients",
29 "opsi_del_client",
30 "opsi_add_client",
31 "opsi_modify_client",
32 "opsi_add_product_to_client",
33 "opsi_del_product_from_client",
34 "opsi_createLicensePool",
35 "opsi_deleteLicensePool",
36 "opsi_createLicense",
37 "opsi_assignSoftwareLicenseToHost",
38 "opsi_unassignSoftwareLicenseFromHost",
39 "opsi_unassignAllSoftwareLicensesFromHost",
40 "opsi_getSoftwareLicense_hash",
41 "opsi_getLicensePool_hash",
42 "opsi_getSoftwareLicenseUsages",
43 "opsi_getSoftwareLicenseUsagesForProductId",
44 "opsi_getLicensePools_listOfHashes",
45 "opsi_getLicenseInformationForProduct",
46 "opsi_getPool",
47 "opsi_getAllSoftwareLicenses",
48 "opsi_removeLicense",
49 "opsi_getReservedLicenses",
50 "opsi_boundHostToLicense",
51 "opsi_unboundHostFromLicense",
52 "opsi_test",
53 );
54 @EXPORT = @events;
57 BEGIN {}
59 END {}
61 # ----------------------------------------------------------------------------
62 # D E C L A R A T I O N S
63 # ----------------------------------------------------------------------------
65 my $licenseTyp_hash = { 'OEM'=>'', 'VOLUME'=>'', 'RETAIL'=>''};
66 my ($opsi_enabled, $opsi_server, $opsi_admin, $opsi_password, $opsi_url, $opsi_client);
67 my %cfg_defaults = (
68 "Opsi" => {
69 "enabled" => [\$opsi_enabled, "false"],
70 "server" => [\$opsi_server, "localhost"],
71 "admin" => [\$opsi_admin, "opsi-admin"],
72 "password" => [\$opsi_password, "secret"],
73 },
74 );
75 &read_configfile($main::cfg_file, %cfg_defaults);
76 if ($opsi_enabled eq "true") {
77 use JSON::RPC::Client;
78 use XML::Quote qw(:all);
79 use Time::HiRes qw( time );
80 $opsi_url= "https://".$opsi_admin.":".$opsi_password."@".$opsi_server.":4447/rpc";
81 $opsi_client = new JSON::RPC::Client;
83 # Check version dependencies
84 eval { &myXmlHashToString(); };
85 if ($@ ) {
86 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";
87 }
88 }
90 # ----------------------------------------------------------------------------
91 # external methods handling the comunication with GOsa/GOsa-si
92 # ----------------------------------------------------------------------------
94 ################################
95 # @brief A function returning a list of functions which are exported by importing the module.
96 # @return List of all provided functions
97 sub get_events {
98 return \@events;
99 }
101 ################################
102 # @brief Adds an Opsi product to an Opsi client.
103 # @param msg - STRING - xml message with tags hostId and productId
104 # @param msg_hash - HASHREF - message information parsed into a hash
105 # @param session_id - INTEGER - POE session id of the processing of this message
106 # @return out_msg - STRING - feedback to GOsa in success and error case
107 sub opsi_add_product_to_client {
108 my $startTime = Time::HiRes::time;
109 my ($msg, $msg_hash, $session_id) = @_;
110 my $header = @{$msg_hash->{'header'}}[0];
111 my $source = @{$msg_hash->{'source'}}[0];
112 my $target = @{$msg_hash->{'target'}}[0];
113 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
115 # Build return message
116 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
117 if (defined $forward_to_gosa) {
118 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
119 }
121 # Sanity check of needed parameter
122 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
123 return &_giveErrorFeedback($msg_hash, "no hostId specified or hostId tag invalid", $session_id);
124 }
125 if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
126 return &_giveErrorFeedback($msg_hash, "no productId specified or productId tag invalid", $session_id);
127 }
129 # Get hostId
130 my $hostId = @{$msg_hash->{'hostId'}}[0];
131 &add_content2xml_hash($out_hash, "hostId", $hostId);
133 # Get productID
134 my $productId = @{$msg_hash->{'productId'}}[0];
135 &add_content2xml_hash($out_hash, "productId", $productId);
137 # Do an action request for all these -> "setup".
138 my $callobj = {
139 method => 'setProductActionRequest',
140 params => [ $productId, $hostId, "setup" ],
141 id => 1, };
142 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
144 if (&check_opsi_res($res)) { return ( (caller(0))[3]." : ".$_, 1 ); };
146 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
147 return ( &create_xml_string($out_hash) );
148 }
150 ################################
151 # @brief Deletes an Opsi-product from an Opsi-client.
152 # @param msg - STRING - xml message with tags hostId and productId
153 # @param msg_hash - HASHREF - message information parsed into a hash
154 # @param session_id - INTEGER - POE session id of the processing of this message
155 # @return out_msg - STRING - feedback to GOsa in success and error case
156 sub opsi_del_product_from_client {
157 my $startTime = Time::HiRes::time;
158 my ($msg, $msg_hash, $session_id) = @_;
159 my $header = @{$msg_hash->{'header'}}[0];
160 my $source = @{$msg_hash->{'source'}}[0];
161 my $target = @{$msg_hash->{'target'}}[0];
162 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
163 my ($hostId, $productId);
164 my $error = 0;
165 my ($sres, $sres_err, $sres_err_string);
167 # Build return message
168 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
169 if (defined $forward_to_gosa) {
170 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
171 }
173 # Sanity check of needed parameter
174 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
175 $error++;
176 &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
177 &add_content2xml_hash($out_hash, "error", "hostId");
178 &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1);
180 }
181 if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
182 $error++;
183 &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
184 &add_content2xml_hash($out_hash, "error", "productId");
185 &main::daemon_log("$session_id ERROR: no productId specified or procutId tag invalid: $msg", 1);
186 }
188 # All parameter available
189 if (not $error) {
190 # Get hostId
191 $hostId = @{$msg_hash->{'hostId'}}[0];
192 &add_content2xml_hash($out_hash, "hostId", $hostId);
194 # Get productID
195 $productId = @{$msg_hash->{'productId'}}[0];
196 &add_content2xml_hash($out_hash, "productId", $productId);
198 # Check to get product action list
199 my $callobj = {
200 method => 'getPossibleProductActions_list',
201 params => [ $productId ],
202 id => 1, };
203 $sres = $main::opsi_client->call($main::opsi_url, $callobj);
204 ($sres_err, $sres_err_string) = &check_opsi_res($sres);
205 if ($sres_err){
206 &main::daemon_log("$session_id ERROR: cannot get product action list: ".$sres_err_string, 1);
207 &add_content2xml_hash($out_hash, "error", $sres_err_string);
208 $error++;
209 }
210 }
212 # Check action uninstall of product
213 if (not $error) {
214 my $uninst_possible= 0;
215 foreach my $r (@{$sres->result}) {
216 if ($r eq 'uninstall') {
217 $uninst_possible= 1;
218 }
219 }
220 if (!$uninst_possible){
221 &main::daemon_log("$session_id ERROR: cannot uninstall product '$productId', product do not has the action 'uninstall'", 1);
222 &add_content2xml_hash($out_hash, "error", "cannot uninstall product '$productId', product do not has the action 'uninstall'");
223 $error++;
224 }
225 }
227 # Set product state to "none"
228 # Do an action request for all these -> "setup".
229 if (not $error) {
230 my $callobj = {
231 method => 'setProductActionRequest',
232 params => [ $productId, $hostId, "none" ],
233 id => 1,
234 };
235 $sres = $main::opsi_client->call($main::opsi_url, $callobj);
236 ($sres_err, $sres_err_string) = &check_opsi_res($sres);
237 if ($sres_err){
238 &main::daemon_log("$session_id ERROR: cannot delete product: ".$sres_err_string, 1);
239 &add_content2xml_hash($out_hash, "error", $sres_err_string);
240 }
241 }
243 # Return message
244 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
245 return ( &create_xml_string($out_hash) );
246 }
248 ################################
249 # @brief Adds an Opsi client to Opsi.
250 # @param msg - STRING - xml message with tags hostId and macaddress
251 # @param msg_hash - HASHREF - message information parsed into a hash
252 # @param session_id - INTEGER - POE session id of the processing of this message
253 # @return out_msg - STRING - feedback to GOsa in success and error case
254 sub opsi_add_client {
255 my $startTime = Time::HiRes::time;
256 my ($msg, $msg_hash, $session_id) = @_;
257 my $header = @{$msg_hash->{'header'}}[0];
258 my $source = @{$msg_hash->{'source'}}[0];
259 my $target = @{$msg_hash->{'target'}}[0];
260 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
261 my ($hostId, $mac);
262 my $error = 0;
263 my ($sres, $sres_err, $sres_err_string);
265 # Build return message with twisted target and source
266 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
267 if (defined $forward_to_gosa) {
268 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
269 }
271 # Sanity check of needed parameter
272 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
273 $error++;
274 &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
275 &add_content2xml_hash($out_hash, "error", "hostId");
276 &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1);
277 }
278 if ((not exists $msg_hash->{'macaddress'}) || (@{$msg_hash->{'macaddress'}} != 1) || (@{$msg_hash->{'macaddress'}}[0] eq ref 'HASH')) {
279 $error++;
280 &add_content2xml_hash($out_hash, "error_string", "no macaddress specified or macaddress tag invalid");
281 &add_content2xml_hash($out_hash, "error", "macaddress");
282 &main::daemon_log("$session_id ERROR: no macaddress specified or macaddress tag invalid: $msg", 1);
283 }
285 if (not $error) {
286 # Get hostId
287 $hostId = @{$msg_hash->{'hostId'}}[0];
288 &add_content2xml_hash($out_hash, "hostId", $hostId);
290 # Get macaddress
291 $mac = @{$msg_hash->{'macaddress'}}[0];
292 &add_content2xml_hash($out_hash, "macaddress", $mac);
294 my $name= $hostId;
295 $name=~ s/^([^.]+).*$/$1/;
296 my $domain= $hostId;
297 $domain=~ s/^[^.]+\.(.*)$/$1/;
298 my ($description, $notes, $ip);
300 if (defined @{$msg_hash->{'description'}}[0]){
301 $description = @{$msg_hash->{'description'}}[0];
302 }
303 if (defined @{$msg_hash->{'notes'}}[0]){
304 $notes = @{$msg_hash->{'notes'}}[0];
305 }
306 if (defined @{$msg_hash->{'ip'}}[0]){
307 $ip = @{$msg_hash->{'ip'}}[0];
308 }
310 my $callobj;
311 $callobj = {
312 method => 'createClient',
313 params => [ $name, $domain, $description, $notes, $ip, $mac ],
314 id => 1,
315 };
317 $sres = $main::opsi_client->call($main::opsi_url, $callobj);
318 ($sres_err, $sres_err_string) = &check_opsi_res($sres);
319 if ($sres_err){
320 &main::daemon_log("$session_id ERROR: cannot create client: ".$sres_err_string, 1);
321 &add_content2xml_hash($out_hash, "error", $sres_err_string);
322 } else {
323 &main::daemon_log("$session_id INFO: add opsi client '$hostId' with mac '$mac'", 5);
324 }
325 }
327 # Return message
328 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
329 return ( &create_xml_string($out_hash) );
330 }
332 ################################
333 # @brief Modifies the parameters description, mac or notes for an Opsi client if the corresponding message tags are given.
334 # @param msg - STRING - xml message with tag hostId and optional description, mac or notes
335 # @param msg_hash - HASHREF - message information parsed into a hash
336 # @param session_id - INTEGER - POE session id of the processing of this message
337 # @return out_msg - STRING - feedback to GOsa in success and error case
338 sub opsi_modify_client {
339 my $startTime = Time::HiRes::time;
340 my ($msg, $msg_hash, $session_id) = @_;
341 my $header = @{$msg_hash->{'header'}}[0];
342 my $source = @{$msg_hash->{'source'}}[0];
343 my $target = @{$msg_hash->{'target'}}[0];
344 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
345 my $hostId;
346 my $error = 0;
347 my ($sres, $sres_err, $sres_err_string);
349 # Build return message with twisted target and source
350 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
351 if (defined $forward_to_gosa) {
352 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
353 }
355 # Sanity check of needed parameter
356 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
357 $error++;
358 &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
359 &add_content2xml_hash($out_hash, "error", "hostId");
360 &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1);
361 }
363 if (not $error) {
364 # Get hostId
365 $hostId = @{$msg_hash->{'hostId'}}[0];
366 &add_content2xml_hash($out_hash, "hostId", $hostId);
367 my $name= $hostId;
368 $name=~ s/^([^.]+).*$/$1/;
369 my $domain= $hostId;
370 $domain=~ s/^[^.]+(.*)$/$1/;
372 # Modify description, notes or mac if defined
373 my ($description, $notes, $mac);
374 my $callobj;
375 if ((exists $msg_hash->{'description'}) && (@{$msg_hash->{'description'}} == 1) ){
376 $description = @{$msg_hash->{'description'}}[0];
377 $callobj = {
378 method => 'setHostDescription',
379 params => [ $hostId, $description ],
380 id => 1,
381 };
382 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
383 my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
384 if ($sres_err){
385 &main::daemon_log("ERROR: cannot set description: ".$sres_err_string, 1);
386 &add_content2xml_hash($out_hash, "error", $sres_err_string);
387 }
388 }
389 if ((exists $msg_hash->{'notes'}) && (@{$msg_hash->{'notes'}} == 1)) {
390 $notes = @{$msg_hash->{'notes'}}[0];
391 $callobj = {
392 method => 'setHostNotes',
393 params => [ $hostId, $notes ],
394 id => 1,
395 };
396 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
397 my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
398 if ($sres_err){
399 &main::daemon_log("ERROR: cannot set notes: ".$sres_err_string, 1);
400 &add_content2xml_hash($out_hash, "error", $sres_err_string);
401 }
402 }
403 if ((exists $msg_hash->{'mac'}) && (@{$msg_hash->{'mac'}} == 1)){
404 $mac = @{$msg_hash->{'mac'}}[0];
405 $callobj = {
406 method => 'setMacAddress',
407 params => [ $hostId, $mac ],
408 id => 1,
409 };
410 my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
411 my ($sres_err, $sres_err_string) = &check_opsi_res($sres);
412 if ($sres_err){
413 &main::daemon_log("ERROR: cannot set mac address: ".$sres_err_string, 1);
414 &add_content2xml_hash($out_hash, "error", $sres_err_string);
415 }
416 }
417 }
419 # Return message
420 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
421 return ( &create_xml_string($out_hash) );
422 }
424 ################################
425 # @brief Get netboot products for specific host.
426 # @param msg - STRING - xml message with tag hostId
427 # @param msg_hash - HASHREF - message information parsed into a hash
428 # @param session_id - INTEGER - POE session id of the processing of this message
429 # @return out_msg - STRING - feedback to GOsa in success and error case
430 sub opsi_get_netboot_products {
431 my $startTime = Time::HiRes::time;
432 my ($msg, $msg_hash, $session_id) = @_;
433 my $header = @{$msg_hash->{'header'}}[0];
434 my $source = @{$msg_hash->{'source'}}[0];
435 my $target = @{$msg_hash->{'target'}}[0];
436 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
437 my $hostId;
439 # Build return message with twisted target and source
440 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
441 if (defined $forward_to_gosa) {
442 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
443 }
444 &add_content2xml_hash($out_hash, "xxx", "");
446 # Get hostId if defined
447 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1)) {
448 $hostId = @{$msg_hash->{'hostId'}}[0];
449 &add_content2xml_hash($out_hash, "hostId", $hostId);
450 }
452 # Move to XML string
453 my $xml_msg= &create_xml_string($out_hash);
455 my $callobj;
456 # Check if we need to get host or global information
457 if (defined $hostId){
458 $callobj = {
459 method => 'getProductHostInformation_list',
460 params => [ $hostId, undef, 'netboot'],
461 id => 1,
462 };
464 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
465 if (not &check_opsi_res($res)){
466 foreach my $product (@{$res->result}){
467 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>";
468 $xml_msg=~ s/<xxx><\/xxx>/\n$replace/;
469 }
470 }
472 } else {
474 # For hosts, only return the products that are or get installed
475 $callobj = {
476 method => 'getProductInformation_list',
477 params => [ undef, 'netboot' ],
478 id => 1,
479 };
481 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
482 if (not &check_opsi_res($res)){
483 foreach my $product (@{$res->result}) {
484 my $replace= "<item><productId>".xml_quote($product->{'productId'})."<\/productId><name>".xml_quote($product->{'name'})."<\/name><description>".xml_quote($product->{'description'})."<\/description><\/item><xxx><\/xxx>";
485 $xml_msg=~ s/<xxx><\/xxx>/\n$replace/;
486 }
487 }
488 }
490 $xml_msg=~ s/<xxx><\/xxx>//;
492 # Retrun Message
493 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
494 return ( $xml_msg );
495 }
497 ################################
498 # @brief Get product properties for a product and a specific host or gobally for a product.
499 # @param msg - STRING - xml message with tags productId and optional hostId
500 # @param msg_hash - HASHREF - message information parsed into a hash
501 # @param session_id - INTEGER - POE session id of the processing of this message
502 # @return out_msg - STRING - feedback to GOsa in success and error case
503 sub opsi_get_product_properties {
504 my $startTime = Time::HiRes::time;
505 my ($msg, $msg_hash, $session_id) = @_;
506 my $header = @{$msg_hash->{'header'}}[0];
507 my $source = @{$msg_hash->{'source'}}[0];
508 my $target = @{$msg_hash->{'target'}}[0];
509 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
510 my ($hostId, $productId);
511 my $xml_msg;
513 # Build return message with twisted target and source
514 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
515 if (defined $forward_to_gosa) {
516 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
517 }
519 # Sanity check of needed parameter
520 if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
521 &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
522 &add_content2xml_hash($out_hash, "error", "productId");
523 &main::daemon_log("$session_id ERROR: no productId specified or productId tag invalid: $msg", 1);
525 # Return message
526 return ( &create_xml_string($out_hash) );
527 }
529 # Get productid
530 $productId = @{$msg_hash->{'productId'}}[0];
531 &add_content2xml_hash($out_hash, "producId", "$productId");
533 # Get hostId if defined
534 if (defined @{$msg_hash->{'hostId'}}[0]){
535 $hostId = @{$msg_hash->{'hostId'}}[0];
536 &add_content2xml_hash($out_hash, "hostId", $hostId);
537 }
539 # Load actions
540 my $callobj = {
541 method => 'getPossibleProductActions_list',
542 params => [ $productId ],
543 id => 1,
544 };
545 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
546 if (not &check_opsi_res($res)){
547 foreach my $action (@{$res->result}){
548 &add_content2xml_hash($out_hash, "action", $action);
549 }
550 }
552 # Add place holder
553 &add_content2xml_hash($out_hash, "xxx", "");
555 # Move to XML string
556 $xml_msg= &create_xml_string($out_hash);
558 # JSON Query
559 if (defined $hostId){
560 $callobj = {
561 method => 'getProductProperties_hash',
562 params => [ $productId, $hostId ],
563 id => 1,
564 };
565 } else {
566 $callobj = {
567 method => 'getProductProperties_hash',
568 params => [ $productId ],
569 id => 1,
570 };
571 }
572 $res = $main::opsi_client->call($main::opsi_url, $callobj);
574 # JSON Query 2
575 $callobj = {
576 method => 'getProductPropertyDefinitions_listOfHashes',
577 params => [ $productId ],
578 id => 1,
579 };
581 # Assemble options
582 my $res2 = $main::opsi_client->call($main::opsi_url, $callobj);
583 my $values = {};
584 my $descriptions = {};
585 if (not &check_opsi_res($res2)){
586 my $r= $res2->result;
588 foreach my $entr (@$r){
589 # Unroll values
590 my $cnv;
591 if (UNIVERSAL::isa( $entr->{'values'}, "ARRAY" )){
592 foreach my $v (@{$entr->{'values'}}){
593 $cnv.= "<value>$v</value>";
594 }
595 } else {
596 $cnv= $entr->{'values'};
597 }
598 $values->{$entr->{'name'}}= $cnv;
599 $descriptions->{$entr->{'name'}}= "<description>".$entr->{'description'}."</description>";
600 }
601 }
603 if (not &check_opsi_res($res)){
604 my $r= $res->result;
605 foreach my $key (keys %{$r}) {
606 my $item= "\n<item>";
607 my $value= $r->{$key};
608 my $dsc= "";
609 my $vals= "";
610 if (defined $descriptions->{$key}){
611 $dsc= $descriptions->{$key};
612 }
613 if (defined $values->{$key}){
614 $vals= $values->{$key};
615 }
616 $item.= "<$key>$dsc<current>".xml_quote($value)."</current>$vals</$key>";
617 $item.= "</item>";
618 $xml_msg=~ s/<xxx><\/xxx>/$item<xxx><\/xxx>/;
619 }
620 }
622 $xml_msg=~ s/<xxx><\/xxx>//;
624 # Return message
625 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
626 return ( $xml_msg );
627 }
629 ################################
630 # @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.
631 # @param msg - STRING - xml message with tags productId, action, state and optional hostId, action and state
632 # @param msg_hash - HASHREF - message information parsed into a hash
633 # @param session_id - INTEGER - POE session id of the processing of this message
634 # @return out_msg - STRING - feedback to GOsa in success and error case
635 sub opsi_set_product_properties {
636 my $startTime = Time::HiRes::time;
637 my ($msg, $msg_hash, $session_id) = @_;
638 my $header = @{$msg_hash->{'header'}}[0];
639 my $source = @{$msg_hash->{'source'}}[0];
640 my $target = @{$msg_hash->{'target'}}[0];
641 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
642 my ($productId, $hostId);
644 # Build return message with twisted target and source
645 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
646 if (defined $forward_to_gosa) {
647 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
648 }
650 # Sanity check of needed parameter
651 if ((not exists $msg_hash->{'productId'}) || (@{$msg_hash->{'productId'}} != 1) || (@{$msg_hash->{'productId'}}[0] eq ref 'HASH')) {
652 &add_content2xml_hash($out_hash, "error_string", "no productId specified or productId tag invalid");
653 &add_content2xml_hash($out_hash, "error", "productId");
654 &main::daemon_log("$session_id ERROR: no productId specified or productId tag invalid: $msg", 1);
655 return ( &create_xml_string($out_hash) );
656 }
657 if (not exists $msg_hash->{'item'}) {
658 &add_content2xml_hash($out_hash, "error_string", "message needs one xml-tag 'item' and within the xml-tags 'name' and 'value'");
659 &add_content2xml_hash($out_hash, "error", "item");
660 &main::daemon_log("$session_id ERROR: message needs one xml-tag 'item' and within the xml-tags 'name' and 'value': $msg", 1);
661 return ( &create_xml_string($out_hash) );
662 } else {
663 if ((not exists @{$msg_hash->{'item'}}[0]->{'name'}) || (@{@{$msg_hash->{'item'}}[0]->{'name'}} != 1 )) {
664 &add_content2xml_hash($out_hash, "error_string", "message needs within the xml-tag 'item' one xml-tags 'name'");
665 &add_content2xml_hash($out_hash, "error", "name");
666 &main::daemon_log("$session_id ERROR: message needs within the xml-tag 'item' one xml-tags 'name': $msg", 1);
667 return ( &create_xml_string($out_hash) );
668 }
669 if ((not exists @{$msg_hash->{'item'}}[0]->{'value'}) || (@{@{$msg_hash->{'item'}}[0]->{'value'}} != 1 )) {
670 &add_content2xml_hash($out_hash, "error_string", "message needs within the xml-tag 'item' one xml-tags 'value'");
671 &add_content2xml_hash($out_hash, "error", "value");
672 &main::daemon_log("$session_id ERROR: message needs within the xml-tag 'item' one xml-tags 'value': $msg", 1);
673 return ( &create_xml_string($out_hash) );
674 }
675 }
676 # if no hostId is given, set_product_properties will act on globally
677 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} > 1)) {
678 &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
679 &add_content2xml_hash($out_hash, "error", "hostId");
680 &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1);
681 return ( &create_xml_string($out_hash) );
682 }
685 # Get productId
686 $productId = @{$msg_hash->{'productId'}}[0];
687 &add_content2xml_hash($out_hash, "productId", $productId);
689 # Get hostId if defined
690 if (exists $msg_hash->{'hostId'}){
691 $hostId = @{$msg_hash->{'hostId'}}[0];
692 &add_content2xml_hash($out_hash, "hostId", $hostId);
693 }
695 # Set product states if requested
696 if (defined @{$msg_hash->{'action'}}[0]){
697 &_set_action($productId, @{$msg_hash->{'action'}}[0], $hostId);
698 }
699 if (defined @{$msg_hash->{'state'}}[0]){
700 &_set_state($productId, @{$msg_hash->{'state'}}[0], $hostId);
701 }
703 # Find properties
704 foreach my $item (@{$msg_hash->{'item'}}){
705 # JSON Query
706 my $callobj;
708 if (defined $hostId){
709 $callobj = {
710 method => 'setProductProperty',
711 params => [ $productId, $item->{'name'}[0], $item->{'value'}[0], $hostId ],
712 id => 1,
713 };
714 } else {
715 $callobj = {
716 method => 'setProductProperty',
717 params => [ $productId, $item->{'name'}[0], $item->{'value'}[0] ],
718 id => 1,
719 };
720 }
722 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
723 my ($res_err, $res_err_string) = &check_opsi_res($res);
725 if ($res_err){
726 &main::daemon_log("$session_id ERROR: communication failed while setting '".$item->{'name'}[0]."': ".$res_err_string, 1);
727 &add_content2xml_hash($out_hash, "error", $res_err_string);
728 }
729 }
732 # Return message
733 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
734 return ( &create_xml_string($out_hash) );
735 }
737 ################################
738 # @brief Reports client hardware inventory.
739 # @param msg - STRING - xml message with tag hostId
740 # @param msg_hash - HASHREF - message information parsed into a hash
741 # @param session_id - INTEGER - POE session id of the processing of this message
742 # @return out_msg - STRING - feedback to GOsa in success and error case
743 sub opsi_get_client_hardware {
744 my $startTime = Time::HiRes::time;
745 my ($msg, $msg_hash, $session_id) = @_;
746 my $header = @{$msg_hash->{'header'}}[0];
747 my $source = @{$msg_hash->{'source'}}[0];
748 my $target = @{$msg_hash->{'target'}}[0];
749 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
750 my $hostId;
751 my $error = 0;
752 my $xml_msg;
754 # Sanity check of needed parameter
755 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
756 $hostId = @{$msg_hash->{'hostId'}}[0];
757 } else {
758 return &_giveErrorFeedback($msg_hash, $_, $session_id);
759 }
762 # Build return message with twisted target and source
763 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
764 if (defined $forward_to_gosa) {
765 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
766 }
767 &add_content2xml_hash($out_hash, "hostId", "$hostId");
768 &add_content2xml_hash($out_hash, "xxx", "");
770 # Move to XML string
771 $xml_msg= &create_xml_string($out_hash);
773 my $res = &_callOpsi(method=>'getHardwareInformation_hash', params=>[ $hostId ]);
774 if (not &check_opsi_res($res)){
775 my $result= $res->result;
776 if (ref $result eq "HASH") {
777 foreach my $r (keys %{$result}){
778 my $item= "\n<item><id>".xml_quote($r)."</id>";
779 my $value= $result->{$r};
780 foreach my $sres (@{$value}){
782 foreach my $dres (keys %{$sres}){
783 if (defined $sres->{$dres}){
784 $item.= "<$dres>".xml_quote($sres->{$dres})."</$dres>";
785 }
786 }
788 }
789 $item.= "</item>";
790 $xml_msg=~ s%<xxx></xxx>%$item<xxx></xxx>%;
792 }
793 }
794 }
796 $xml_msg=~ s/<xxx><\/xxx>//;
798 # Return message
799 my $endTime = Time::HiRes::time;
800 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
801 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
802 return ( $xml_msg );
803 }
805 ################################
806 # @brief Reports all Opsi clients.
807 # @param msg - STRING - xml message
808 # @param msg_hash - HASHREF - message information parsed into a hash
809 # @param session_id - INTEGER - POE session id of the processing of this message
810 # @return out_msg - STRING - feedback to GOsa in success and error case
811 sub opsi_list_clients {
812 my $startTime = Time::HiRes::time;
813 my ($msg, $msg_hash, $session_id) = @_;
814 my $header = @{$msg_hash->{'header'}}[0];
815 my $source = @{$msg_hash->{'source'}}[0];
816 my $target = @{$msg_hash->{'target'}}[0];
817 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
819 # Build return message with twisted target and source
820 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
821 if (defined $forward_to_gosa) {
822 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
823 }
824 &add_content2xml_hash($out_hash, "xxx", "");
826 # Move to XML string
827 my $xml_msg= &create_xml_string($out_hash);
829 # JSON Query
830 my $callobj = {
831 method => 'getClientsInformation_listOfHashes',
832 params => [ ],
833 id => 1,
834 };
836 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
837 if (not &check_opsi_res($res)){
838 foreach my $host (@{$res->result}){
839 my $item= "\n<item><name>".$host->{'hostId'}."</name>";
840 $item.= "<mac>".xml_quote($host->{'macAddress'})."</mac>";
841 if (defined($host->{'description'})){
842 $item.= "<description>".xml_quote($host->{'description'})."</description>";
843 }
844 if (defined($host->{'notes'})){
845 $item.= "<notes>".xml_quote($host->{'notes'})."</notes>";
846 }
847 if (defined($host->{'lastSeen'})){
848 $item.= "<lastSeen>".xml_quote($host->{'lastSeen'})."</lastSeen>";
849 }
851 $item.= "</item>";
852 $xml_msg=~ s%<xxx></xxx>%$item<xxx></xxx>%;
853 }
854 }
855 $xml_msg=~ s/<xxx><\/xxx>//;
857 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
858 return ( $xml_msg );
859 }
861 ################################
862 # @brief Reports client software inventory.
863 # @param msg - STRING - xml message with tag hostId
864 # @param msg_hash - HASHREF - message information parsed into a hash
865 # @param session_id - INTEGER - POE session id of the processing of this message
866 # @return out_msg - STRING - feedback to GOsa in success and error case
867 sub opsi_get_client_software {
868 my $startTime = Time::HiRes::time;
869 my ($msg, $msg_hash, $session_id) = @_;
870 my $header = @{$msg_hash->{'header'}}[0];
871 my $source = @{$msg_hash->{'source'}}[0];
872 my $target = @{$msg_hash->{'target'}}[0];
873 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
874 my $error = 0;
875 my $hostId;
876 my $xml_msg;
878 # Build return message with twisted target and source
879 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
880 if (defined $forward_to_gosa) {
881 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
882 }
884 # Sanity check of needed parameter
885 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
886 $error++;
887 &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
888 &add_content2xml_hash($out_hash, "error", "hostId");
889 &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1);
890 }
892 if (not $error) {
894 # Get hostId
895 $hostId = @{$msg_hash->{'hostId'}}[0];
896 &add_content2xml_hash($out_hash, "hostId", "$hostId");
897 &add_content2xml_hash($out_hash, "xxx", "");
898 }
900 $xml_msg= &create_xml_string($out_hash);
902 if (not $error) {
904 # JSON Query
905 my $callobj = {
906 method => 'getSoftwareInformation_hash',
907 params => [ $hostId ],
908 id => 1,
909 };
911 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
912 if (not &check_opsi_res($res)){
913 my $result= $res->result;
914 }
916 $xml_msg=~ s/<xxx><\/xxx>//;
918 }
920 # Return message
921 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
922 return ( $xml_msg );
923 }
925 ################################
926 # @brief Reports product for given hostId or globally.
927 # @param msg - STRING - xml message with optional tag hostId
928 # @param msg_hash - HASHREF - message information parsed into a hash
929 # @param session_id - INTEGER - POE session id of the processing of this message
930 # @return out_msg - STRING - feedback to GOsa in success and error case
931 sub opsi_get_local_products {
932 my $startTime = Time::HiRes::time;
933 my ($msg, $msg_hash, $session_id) = @_;
934 my $header = @{$msg_hash->{'header'}}[0];
935 my $source = @{$msg_hash->{'source'}}[0];
936 my $target = @{$msg_hash->{'target'}}[0];
937 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
938 my $hostId;
940 # Build return message with twisted target and source
941 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
942 if (defined $forward_to_gosa) {
943 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
944 }
945 &add_content2xml_hash($out_hash, "xxx", "");
947 # Get hostId if defined
948 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1)) {
949 $hostId = @{$msg_hash->{'hostId'}}[0];
950 &add_content2xml_hash($out_hash, "hostId", $hostId);
951 }
953 my $callobj;
955 # Move to XML string
956 my $xml_msg= &create_xml_string($out_hash);
958 # Check if we need to get host or global information
959 if (defined $hostId){
960 $callobj = {
961 method => 'getProductHostInformation_list',
962 params => [ $hostId ],
963 id => 1,
964 };
966 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
967 if (not &check_opsi_res($res)){
968 foreach my $product (@{$res->result}){
969 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>";
970 $xml_msg=~ s/<xxx><\/xxx>/\n$replace/;
971 }
972 }
974 } else {
976 # For hosts, only return the products that are or get installed
977 $callobj = {
978 method => 'getProductInformation_list',
979 params => [ undef, 'localboot' ],
980 id => 1,
981 };
983 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
984 if (not &check_opsi_res($res)){
985 foreach my $product (@{$res->result}) {
986 my $replace= "<item><productId>".xml_quote($product->{'productId'})."<\/productId><name>".xml_quote($product->{'name'})."<\/name><description>".xml_quote($product->{'description'})."<\/description><\/item><xxx><\/xxx>";
987 $xml_msg=~ s/<xxx><\/xxx>/\n$replace/;
988 }
989 }
990 }
992 $xml_msg=~ s/<xxx><\/xxx>//;
994 # Retrun Message
995 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
996 return ( $xml_msg );
997 }
999 ################################
1000 # @brief Deletes a client from Opsi.
1001 # @param msg - STRING - xml message with tag hostId
1002 # @param msg_hash - HASHREF - message information parsed into a hash
1003 # @param session_id - INTEGER - POE session id of the processing of this message
1004 # @return out_msg - STRING - feedback to GOsa in success and error case
1005 sub opsi_del_client {
1006 my $startTime = Time::HiRes::time;
1007 my ($msg, $msg_hash, $session_id) = @_;
1008 my $header = @{$msg_hash->{'header'}}[0];
1009 my $source = @{$msg_hash->{'source'}}[0];
1010 my $target = @{$msg_hash->{'target'}}[0];
1011 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1012 my $hostId;
1013 my $error = 0;
1015 # Build return message with twisted target and source
1016 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1017 if (defined $forward_to_gosa) {
1018 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1019 }
1021 # Sanity check of needed parameter
1022 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
1023 $error++;
1024 &add_content2xml_hash($out_hash, "error_string", "hostId contains no or more than one values");
1025 &add_content2xml_hash($out_hash, "error", "hostId");
1026 &main::daemon_log("$session_id ERROR: hostId contains no or more than one values: $msg", 1);
1027 }
1029 if (not $error) {
1031 # Get hostId
1032 $hostId = @{$msg_hash->{'hostId'}}[0];
1033 &add_content2xml_hash($out_hash, "hostId", "$hostId");
1035 # JSON Query
1036 my $callobj = {
1037 method => 'deleteClient',
1038 params => [ $hostId ],
1039 id => 1,
1040 };
1041 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1042 }
1044 # Move to XML string
1045 my $xml_msg= &create_xml_string($out_hash);
1047 # Return message
1048 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1049 return ( $xml_msg );
1050 }
1052 ################################
1053 # @brief Set a client in Opsi to install and trigger a wake on lan message (WOL).
1054 # @param msg - STRING - xml message with tags hostId, macaddress
1055 # @param msg_hash - HASHREF - message information parsed into a hash
1056 # @param session_id - INTEGER - POE session id of the processing of this message
1057 # @return out_msg - STRING - feedback to GOsa in success and error case
1058 sub opsi_install_client {
1059 my $startTime = Time::HiRes::time;
1060 my ($msg, $msg_hash, $session_id) = @_;
1061 my $header = @{$msg_hash->{'header'}}[0];
1062 my $source = @{$msg_hash->{'source'}}[0];
1063 my $target = @{$msg_hash->{'target'}}[0];
1064 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
1065 my ($hostId, $macaddress);
1066 my $error = 0;
1067 my @out_msg_l;
1069 # Build return message with twisted target and source
1070 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1071 if (defined $forward_to_gosa) {
1072 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
1073 }
1075 # Sanity check of needed parameter
1076 if ((not exists $msg_hash->{'hostId'}) || (@{$msg_hash->{'hostId'}} != 1) || (@{$msg_hash->{'hostId'}}[0] eq ref 'HASH')) {
1077 $error++;
1078 &add_content2xml_hash($out_hash, "error_string", "no hostId specified or hostId tag invalid");
1079 &add_content2xml_hash($out_hash, "error", "hostId");
1080 &main::daemon_log("$session_id ERROR: no hostId specified or hostId tag invalid: $msg", 1);
1081 }
1082 if ((not exists $msg_hash->{'macaddress'}) || (@{$msg_hash->{'macaddress'}} != 1) || (@{$msg_hash->{'macaddress'}}[0] eq ref 'HASH') ) {
1083 $error++;
1084 &add_content2xml_hash($out_hash, "error_string", "no macaddress specified or macaddress tag invalid");
1085 &add_content2xml_hash($out_hash, "error", "macaddress");
1086 &main::daemon_log("$session_id ERROR: no macaddress specified or macaddress tag invalid: $msg", 1);
1087 } else {
1088 if ((exists $msg_hash->{'macaddress'}) &&
1089 ($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)) {
1090 $macaddress = $1;
1091 } else {
1092 $error ++;
1093 &add_content2xml_hash($out_hash, "error_string", "given mac address is not correct");
1094 &add_content2xml_hash($out_hash, "error", "macaddress");
1095 &main::daemon_log("$session_id ERROR: given mac address is not correct: $msg", 1);
1096 }
1097 }
1099 if (not $error) {
1101 # Get hostId
1102 $hostId = @{$msg_hash->{'hostId'}}[0];
1103 &add_content2xml_hash($out_hash, "hostId", "$hostId");
1105 # Load all products for this host with status != "not_installed" or actionRequest != "none"
1106 my $callobj = {
1107 method => 'getProductStates_hash',
1108 params => [ $hostId ],
1109 id => 1,
1110 };
1112 my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
1113 if (not &check_opsi_res($hres)){
1114 my $htmp= $hres->result->{$hostId};
1116 # check state != not_installed or action == setup -> load and add
1117 foreach my $product (@{$htmp}){
1118 # Now we've a couple of hashes...
1119 if ($product->{'installationStatus'} ne "not_installed" or
1120 $product->{'actionRequest'} ne "none"){
1122 # Do an action request for all these -> "setup".
1123 $callobj = {
1124 method => 'setProductActionRequest',
1125 params => [ $product->{'productId'}, $hostId, "setup" ],
1126 id => 1,
1127 };
1128 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1129 my ($res_err, $res_err_string) = &check_opsi_res($res);
1130 if ($res_err){
1131 &main::daemon_log("$session_id ERROR: cannot set product action request for '$hostId': ".$product->{'productId'}, 1);
1132 } else {
1133 &main::daemon_log("$session_id INFO: requesting 'setup' for '".$product->{'productId'}."' on $hostId", 1);
1134 }
1135 }
1136 }
1137 }
1138 push(@out_msg_l, &create_xml_string($out_hash));
1141 # Build wakeup message for client
1142 if (not $error) {
1143 my $wakeup_hash = &create_xml_hash("trigger_wake", "GOSA", "KNOWN_SERVER");
1144 &add_content2xml_hash($wakeup_hash, 'macaddress', $macaddress);
1145 my $wakeup_msg = &create_xml_string($wakeup_hash);
1146 push(@out_msg_l, $wakeup_msg);
1148 # invoke trigger wake for this gosa-si-server
1149 &main::server_server_com::trigger_wake($wakeup_msg, $wakeup_hash, $session_id);
1150 }
1151 }
1153 # Return messages
1154 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1155 return @out_msg_l;
1156 }
1158 ################################
1159 # @brief Set action for an Opsi client
1160 # @param product - STRING - Opsi product
1161 # @param action - STRING - action
1162 # @param hostId - STRING - Opsi hostId
1163 sub _set_action {
1164 my $product= shift;
1165 my $action = shift;
1166 my $hostId = shift;
1167 my $callobj;
1169 $callobj = {
1170 method => 'setProductActionRequest',
1171 params => [ $product, $hostId, $action],
1172 id => 1,
1173 };
1175 $main::opsi_client->call($main::opsi_url, $callobj);
1176 }
1178 ################################
1179 # @brief Set state for an Opsi client
1180 # @param product - STRING - Opsi product
1181 # @param action - STRING - state
1182 # @param hostId - STRING - Opsi hostId
1183 sub _set_state {
1184 my $product = shift;
1185 my $state = shift;
1186 my $hostId = shift;
1187 my $callobj;
1189 $callobj = {
1190 method => 'setProductState',
1191 params => [ $product, $hostId, $state ],
1192 id => 1,
1193 };
1195 $main::opsi_client->call($main::opsi_url, $callobj);
1196 }
1198 ################################
1199 # @brief Create a license pool at Opsi server.
1200 # @param licensePoolId The name of the pool (optional).
1201 # @param description The description of the pool (optional).
1202 # @param productIds A list of assigned porducts of the pool (optional).
1203 # @param windowsSoftwareIds A list of windows software IDs associated to the pool (optional).
1204 sub opsi_createLicensePool {
1205 my $startTime = Time::HiRes::time;
1206 my ($msg, $msg_hash, $session_id) = @_;
1207 my $header = @{$msg_hash->{'header'}}[0];
1208 my $source = @{$msg_hash->{'source'}}[0];
1209 my $target = @{$msg_hash->{'target'}}[0];
1210 my $out_hash;
1211 my $licensePoolId = defined $msg_hash->{'licensePoolId'} ? @{$msg_hash->{'licensePoolId'}}[0] : undef;
1212 my $description = defined $msg_hash->{'description'} ? @{$msg_hash->{'description'}}[0] : undef;
1213 my @productIds = defined $msg_hash->{'productIds'} ? $msg_hash->{'productIds'} : undef;
1214 my @windowsSoftwareIds = defined $msg_hash->{'windowsSoftwareIds'} ? $msg_hash->{'windowsSoftwareIds'} : undef;
1216 # Create license Pool
1217 my $callobj = {
1218 method => 'createLicensePool',
1219 params => [ $licensePoolId, $description, @productIds, @windowsSoftwareIds],
1220 id => 1,
1221 };
1222 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1224 # Check Opsi error
1225 my ($res_error, $res_error_str) = &check_opsi_res($res);
1226 if ($res_error){
1227 # Create error message
1228 &main::daemon_log("$session_id ERROR: cannot create license pool at Opsi server: ".$res_error_str, 1);
1229 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1230 return ( &create_xml_string($out_hash) );
1231 }
1233 # Create function result message
1234 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source, $res->result);
1235 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1237 my $endTime = Time::HiRes::time;
1238 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1239 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1240 return ( &create_xml_string($out_hash) );
1241 }
1243 ################################
1244 # @brief Return licensePoolId, description, productIds and windowsSoftwareIds for all found license pools.
1245 sub opsi_getLicensePools_listOfHashes {
1246 my $startTime = Time::HiRes::time;
1247 my ($msg, $msg_hash, $session_id) = @_;
1248 my $header = @{$msg_hash->{'header'}}[0];
1249 my $source = @{$msg_hash->{'source'}}[0];
1250 my $out_hash;
1252 # Fetch infos from Opsi server
1253 my $callobj = {
1254 method => 'getLicensePools_listOfHashes',
1255 params => [ ],
1256 id => 1,
1257 };
1258 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1260 # Check Opsi error
1261 my ($res_error, $res_error_str) = &check_opsi_res($res);
1262 if ($res_error){
1263 # Create error message
1264 &main::daemon_log("$session_id ERROR: cannot get license pool ID list from Opsi server: ".$res_error_str, 1);
1265 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1266 return ( &create_xml_string($out_hash) );
1267 }
1269 # Create function result message
1270 my $res_hash = { 'hit'=> [] };
1271 foreach my $licensePool ( @{$res->result}) {
1272 my $licensePool_hash = { 'licensePoolId' => [$licensePool->{'licensePoolId'}],
1273 'description' => [$licensePool->{'description'}],
1274 'productIds' => $licensePool->{'productIds'},
1275 'windowsSoftwareIds' => $licensePool->{'windowsSoftwareIds'},
1276 };
1277 push( @{$res_hash->{hit}}, $licensePool_hash );
1278 }
1280 # Create function result message
1281 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1282 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1283 $out_hash->{result} = [$res_hash];
1285 my $endTime = Time::HiRes::time;
1286 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1287 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1288 return ( &create_xml_string($out_hash) );
1289 }
1291 ################################
1292 # @brief Return productIds, windowsSoftwareIds and description for a given licensePoolId
1293 # @param licensePoolId The name of the pool.
1294 sub opsi_getLicensePool_hash {
1295 my $startTime = Time::HiRes::time;
1296 my ($msg, $msg_hash, $session_id) = @_;
1297 my $header = @{$msg_hash->{'header'}}[0];
1298 my $source = @{$msg_hash->{'source'}}[0];
1299 my $target = @{$msg_hash->{'target'}}[0];
1300 my $licensePoolId;
1301 my $out_hash;
1303 # Check input sanity
1304 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1305 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1306 } else {
1307 return &_giveErrorFeedback($msg_hash, "", $session_id, $_);
1308 }
1310 # Fetch infos from Opsi server
1311 my $callobj = {
1312 method => 'getLicensePool_hash',
1313 params => [ $licensePoolId ],
1314 id => 1,
1315 };
1316 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1318 # Check Opsi error
1319 my ($res_error, $res_error_str) = &check_opsi_res($res);
1320 if ($res_error){
1321 # Create error message
1322 &main::daemon_log("$session_id ERROR: cannot get license pool from Opsi server: ".$res_error_str, 1);
1323 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source);
1324 &add_content2xml_hash($out_hash, "error", $res_error_str);
1325 return ( &create_xml_string($out_hash) );
1326 }
1328 # Create function result message
1329 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1330 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1331 &add_content2xml_hash($out_hash, "licensePoolId", $res->result->{'licensePoolId'});
1332 &add_content2xml_hash($out_hash, "description", $res->result->{'description'});
1333 map(&add_content2xml_hash($out_hash, "productIds", "$_"), @{ $res->result->{'productIds'} });
1334 map(&add_content2xml_hash($out_hash, "windowsSoftwareIds", "$_"), @{ $res->result->{'windowsSoftwareIds'} });
1336 my $endTime = Time::HiRes::time;
1337 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1338 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1339 return ( &create_xml_string($out_hash) );
1340 }
1342 sub _parse_getSoftwareLicenseUsages {
1343 my $res = shift;
1345 # Parse Opsi result
1346 my $tmp_licensePool_cache = {};
1347 my $res_hash = { 'hit'=> [] };
1348 foreach my $license ( @{$res}) {
1349 my $tmp_licensePool = $license->{'licensePoolId'};
1350 if (not exists $tmp_licensePool_cache->{$tmp_licensePool}) {
1351 # Fetch missing informations from Opsi and cache the results for a possible later usage
1352 my ($res, $err) = &_getLicensePool_hash('licensePoolId'=>$tmp_licensePool);
1353 if (not $err) {
1354 $tmp_licensePool_cache->{$tmp_licensePool} = $res;
1355 }
1356 }
1357 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
1358 'notes' => [$license->{'notes'}],
1359 'licenseKey' => [$license->{'licenseKey'}],
1360 'hostId' => [$license->{'hostId'}],
1361 'licensePoolId' => [$tmp_licensePool],
1362 };
1363 if (exists $tmp_licensePool_cache->{$tmp_licensePool}) {
1364 $license_hash->{$tmp_licensePool} = {'productIds'=>[], 'windowsSoftwareIds'=>[]};
1365 map (push (@{$license_hash->{$tmp_licensePool}->{productIds}}, $_), @{$tmp_licensePool_cache->{$tmp_licensePool}->{productIds}});
1366 map (push (@{$license_hash->{$tmp_licensePool}->{windowsSoftwareIds}}, $_), @{$tmp_licensePool_cache->{$tmp_licensePool}->{windowsSoftwareIds}});
1367 }
1368 push( @{$res_hash->{hit}}, $license_hash );
1369 }
1371 return $res_hash;
1372 }
1374 ################################
1375 # @brief Returns softwareLicenseId, notes, licenseKey, hostId and licensePoolId for optional given licensePoolId and hostId
1376 # @param hostid Something like client_1.intranet.mydomain.de (optional).
1377 # @param licensePoolId The name of the pool (optional).
1378 sub opsi_getSoftwareLicenseUsages {
1379 my $startTime = Time::HiRes::time;
1380 my ($msg, $msg_hash, $session_id) = @_;
1381 my $header = @{$msg_hash->{'header'}}[0];
1382 my $source = @{$msg_hash->{'source'}}[0];
1383 my $target = @{$msg_hash->{'target'}}[0];
1384 my $licensePoolId = defined $msg_hash->{'licensePoolId'} ? @{$msg_hash->{'licensePoolId'}}[0] : undef;
1385 my $hostId = defined $msg_hash->{'hostId'} ? @{$msg_hash->{'hostId'}}[0] : undef;
1386 my $out_hash;
1388 my ($res, $err) = &_getSoftwareLicenseUsages_listOfHashes('licensePoolId'=>$licensePoolId, 'hostId'=>$hostId);
1389 if ($err){
1390 return &_giveErrorFeedback($msg_hash, "cannot fetch software licenses from license pool : ".$res, $session_id);
1391 }
1393 # Parse Opsi result
1394 my $res_hash = &_parse_getSoftwareLicenseUsages($res);
1396 # Create function result message
1397 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1398 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1399 $out_hash->{result} = [$res_hash];
1401 my $endTime = Time::HiRes::time;
1402 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1403 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1404 return ( &create_xml_string($out_hash) );
1405 }
1407 ################################
1408 # @brief Returns softwareLicenseId, notes, licenseKey, hostId and licensePoolId. Function return is identical to opsi_getSoftwareLicenseUsages
1409 # @param productId Something like 'firefox', 'python' or anything else .
1410 sub opsi_getSoftwareLicenseUsagesForProductId {
1411 my $startTime = Time::HiRes::time;
1412 my ($msg, $msg_hash, $session_id) = @_;
1413 my $header = @{$msg_hash->{'header'}}[0];
1414 my $source = @{$msg_hash->{'source'}}[0];
1416 # Check input sanity
1417 my $productId;
1418 if (&_check_xml_tag_is_ok ($msg_hash, 'productId')) {
1419 $productId= @{$msg_hash->{'productId'}}[0];
1420 } else {
1421 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1422 }
1424 # Fetch licensePoolId for productId
1425 my ($res, $err) = &_getLicensePoolId('productId'=>$productId);
1426 if ($err){
1427 my $out_hash = &create_xml_hash("answer_$header", $main::server_address, $source);
1428 $out_hash->{result} = [];
1429 return ( &create_xml_string($out_hash) );
1430 }
1431 my $licensePoolId = $res; # We assume that there is only one pool for each productID!!!
1433 # Fetch softwareLiceceUsages for licensePoolId
1434 ($res, $err) = &_getSoftwareLicenseUsages_listOfHashes('licensePoolId'=>$licensePoolId);
1435 if ($err){
1436 return &_giveErrorFeedback($msg_hash, "cannot fetch software licenses from license pool : ".$res, $session_id);
1437 }
1438 # Parse Opsi result
1439 my $res_hash = &_parse_getSoftwareLicenseUsages($res);
1441 # Create function result message
1442 my $out_hash = &create_xml_hash("answer_$header", $main::server_address, $source);
1443 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1444 $out_hash->{result} = [$res_hash];
1446 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1447 return ( &create_xml_string($out_hash) );
1448 }
1450 ################################
1451 # @brief Returns expirationDate, boundToHost, maxInstallation, licenseTyp, licensePoolIds and licenseKeys for a given softwareLicense ID.
1452 # @param softwareLicenseId Identificator of a license.
1453 sub opsi_getSoftwareLicense_hash {
1454 my $startTime = Time::HiRes::time;
1455 my ($msg, $msg_hash, $session_id) = @_;
1456 my $header = @{$msg_hash->{'header'}}[0];
1457 my $source = @{$msg_hash->{'source'}}[0];
1458 my $target = @{$msg_hash->{'target'}}[0];
1459 my $softwareLicenseId;
1460 my $out_hash;
1462 # Check input sanity
1463 if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
1464 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
1465 } else {
1466 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1467 }
1469 my $callobj = {
1470 method => 'getSoftwareLicense_hash',
1471 params => [ $softwareLicenseId ],
1472 id => 1,
1473 };
1474 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1476 # Check Opsi error
1477 my ($res_error, $res_error_str) = &check_opsi_res($res);
1478 if ($res_error){
1479 # Create error message
1480 &main::daemon_log("$session_id ERROR: cannot fetch information for license '$softwareLicenseId': ".$res_error_str, 1);
1481 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1482 return ( &create_xml_string($out_hash) );
1483 }
1485 # Create function result message
1486 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1487 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1488 &add_content2xml_hash($out_hash, "expirationDate", $res->result->{'expirationDate'});
1489 &add_content2xml_hash($out_hash, "boundToHost", $res->result->{'boundToHost'});
1490 &add_content2xml_hash($out_hash, "maxInstallations", $res->result->{'maxInstallations'});
1491 &add_content2xml_hash($out_hash, "licenseTyp", $res->result->{'licenseTyp'});
1492 foreach my $licensePoolId ( @{$res->result->{'licensePoolIds'}}) {
1493 &add_content2xml_hash($out_hash, "licensePoolId", $licensePoolId);
1494 &add_content2xml_hash($out_hash, $licensePoolId, $res->result->{'licenseKeys'}->{$licensePoolId});
1495 }
1497 my $endTime = Time::HiRes::time;
1498 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1499 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1500 return ( &create_xml_string($out_hash) );
1501 }
1503 ################################
1504 # @brief Delete licnese pool by license pool ID. A pool can only be deleted if there are no software licenses bound to the pool.
1505 # The fixed parameter deleteLicenses=True specifies that all software licenses bound to the pool are being deleted.
1506 # @param licensePoolId The name of the pool.
1507 sub opsi_deleteLicensePool {
1508 my $startTime = Time::HiRes::time;
1509 my ($msg, $msg_hash, $session_id) = @_;
1510 my $header = @{$msg_hash->{'header'}}[0];
1511 my $source = @{$msg_hash->{'source'}}[0];
1512 my $target = @{$msg_hash->{'target'}}[0];
1513 my $licensePoolId;
1514 my $out_hash;
1516 # Check input sanity
1517 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1518 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1519 } else {
1520 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1521 }
1523 # Fetch softwareLicenseIds used in license pool
1524 # This has to be done because function deleteLicensePool deletes the pool and the corresponding software licenses
1525 # but not the license contracts of the software licenses. In our case each software license has exactly one license contract.
1526 my $callobj = {
1527 method => 'getSoftwareLicenses_listOfHashes',
1528 params => [ ],
1529 id => 1,
1530 };
1531 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1533 # Keep list of licenseContractIds in mind to delete it after the deletion of the software licenses
1534 my @lCI_toBeDeleted;
1535 foreach my $softwareLicenseHash ( @{$res->result} ) {
1536 if ((@{$softwareLicenseHash->{'licensePoolIds'}} == 0) || (@{$softwareLicenseHash->{'licensePoolIds'}}[0] ne $licensePoolId)) {
1537 next;
1538 }
1539 push (@lCI_toBeDeleted, $softwareLicenseHash->{'licenseContractId'});
1540 }
1542 # Delete license pool at Opsi server
1543 $callobj = {
1544 method => 'deleteLicensePool',
1545 params => [ $licensePoolId, 'deleteLicenses=True' ],
1546 id => 1,
1547 };
1548 $res = $main::opsi_client->call($main::opsi_url, $callobj);
1549 my ($res_error, $res_error_str) = &check_opsi_res($res);
1550 if ($res_error){
1551 # Create error message
1552 &main::daemon_log("$session_id ERROR: cannot delete license pool at Opsi server: ".$res_error_str, 1);
1553 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1554 return ( &create_xml_string($out_hash) );
1555 }
1557 # Delete each license contract connected with the license pool
1558 foreach my $licenseContractId ( @lCI_toBeDeleted ) {
1559 my $callobj = {
1560 method => 'deleteLicenseContract',
1561 params => [ $licenseContractId ],
1562 id => 1,
1563 };
1564 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1565 my ($res_error, $res_error_str) = &check_opsi_res($res);
1566 if ($res_error){
1567 # Create error message
1568 &main::daemon_log("$session_id ERROR: cannot delete license contract '$licenseContractId' connected with license pool '$licensePoolId' at Opsi server: ".$res_error_str, 1);
1569 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1570 return ( &create_xml_string($out_hash) );
1571 }
1572 }
1574 # Create function result message
1575 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1576 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1578 my $endTime = Time::HiRes::time;
1579 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1580 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1581 return ( &create_xml_string($out_hash) );
1582 }
1584 ################################
1585 # @brief Create a license contract, create a software license and add the software license to the license pool
1586 # @param licensePoolId The name of the pool the license should be assigned.
1587 # @param licenseKey The license key.
1588 # @param partner Name of the license partner (optional).
1589 # @param conclusionDate Date of conclusion of license contract (optional)
1590 # @param notificationDate Date of notification that license is running out soon (optional).
1591 # @param notes This is the place for some notes (optional)
1592 # @param softwareLicenseId Identificator of a license (optional).
1593 # @param licenseTyp Typ of a licnese, either "OEM", "VOLUME" or "RETAIL" (optional).
1594 # @param maxInstallations The number of clients use this license (optional).
1595 # @param boundToHost The name of the client the license is bound to (optional).
1596 # @param expirationDate The date when the license is running down (optional).
1597 sub opsi_createLicense {
1598 my $startTime = Time::HiRes::time;
1599 my ($msg, $msg_hash, $session_id) = @_;
1600 my $header = @{$msg_hash->{'header'}}[0];
1601 my $source = @{$msg_hash->{'source'}}[0];
1602 my $target = @{$msg_hash->{'target'}}[0];
1603 my $partner = defined $msg_hash->{'partner'} ? @{$msg_hash->{'partner'}}[0] : undef;
1604 my $conclusionDate = defined $msg_hash->{'conclusionDate'} ? @{$msg_hash->{'conclusionDate'}}[0] : undef;
1605 my $notificationDate = defined $msg_hash->{'notificationDate'} ? @{$msg_hash->{'notificationDate'}}[0] : undef;
1606 my $notes = defined $msg_hash->{'notes'} ? @{$msg_hash->{'notes'}}[0] : undef;
1607 my $licenseContractId = undef;
1608 my $softwareLicenseId = defined $msg_hash->{'softwareLicenseId'} ? @{$msg_hash->{'softwareLicenseId'}}[0] : undef;
1609 my $licenseType = defined $msg_hash->{'licenseType'} ? @{$msg_hash->{'licenseType'}}[0] : undef;
1610 my $maxInstallations = defined $msg_hash->{'maxInstallations'} ? @{$msg_hash->{'maxInstallations'}}[0] : undef;
1611 my $boundToHost = defined $msg_hash->{'boundToHost'} ? @{$msg_hash->{'boundToHost'}}[0] : undef;
1612 my $expirationDate = defined $msg_hash->{'expirationDate'} ? @{$msg_hash->{'expirationDate'}}[0] : undef;
1613 my $licensePoolId;
1614 my $licenseKey;
1615 my $out_hash;
1617 # Check input sanity
1618 if (&_check_xml_tag_is_ok ($msg_hash, 'licenseKey')) {
1619 $licenseKey = @{$msg_hash->{'licenseKey'}}[0];
1620 } else {
1621 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1622 }
1623 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1624 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1625 } else {
1626 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1627 }
1628 if ((defined $licenseType) && (not exists $licenseTyp_hash->{$licenseType})) {
1629 return &_giveErrorFeedback($msg_hash, "The typ of a license can be either 'OEM', 'VOLUME' or 'RETAIL'.", $session_id);
1630 }
1632 # Automatically define licenseContractId if ID is not given
1633 if (defined $softwareLicenseId) {
1634 $licenseContractId = "c_".$softwareLicenseId;
1635 }
1637 # Create license contract at Opsi server
1638 my $callobj = {
1639 method => 'createLicenseContract',
1640 params => [ $licenseContractId, $partner, $conclusionDate, $notificationDate, undef, $notes ],
1641 id => 1,
1642 };
1643 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1645 # Check Opsi error
1646 my ($res_error, $res_error_str) = &check_opsi_res($res);
1647 if ($res_error){
1648 # Create error message
1649 &main::daemon_log("$session_id ERROR: cannot create license contract at Opsi server: ".$res_error_str, 1);
1650 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1651 return ( &create_xml_string($out_hash) );
1652 }
1654 $licenseContractId = $res->result;
1656 # Create software license at Opsi server
1657 $callobj = {
1658 method => 'createSoftwareLicense',
1659 params => [ $softwareLicenseId, $licenseContractId, $licenseType, $maxInstallations, $boundToHost, $expirationDate ],
1660 id => 1,
1661 };
1662 $res = $main::opsi_client->call($main::opsi_url, $callobj);
1664 # Check Opsi error
1665 ($res_error, $res_error_str) = &check_opsi_res($res);
1666 if ($res_error){
1667 # Create error message
1668 &main::daemon_log("$session_id ERROR: cannot create software license at Opsi server: ".$res_error_str, 1);
1669 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1670 return ( &create_xml_string($out_hash) );
1671 }
1673 $softwareLicenseId = $res->result;
1675 # Add software license to license pool
1676 $callobj = {
1677 method => 'addSoftwareLicenseToLicensePool',
1678 params => [ $softwareLicenseId, $licensePoolId, $licenseKey ],
1679 id => 1,
1680 };
1681 $res = $main::opsi_client->call($main::opsi_url, $callobj);
1683 # Check Opsi error
1684 ($res_error, $res_error_str) = &check_opsi_res($res);
1685 if ($res_error){
1686 # Create error message
1687 &main::daemon_log("$session_id ERROR: cannot add software license to license pool at Opsi server: ".$res_error_str, 1);
1688 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1689 return ( &create_xml_string($out_hash) );
1690 }
1692 # Create function result message
1693 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1694 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1696 my $endTime = Time::HiRes::time;
1697 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1698 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1699 return ( &create_xml_string($out_hash) );
1700 }
1702 ################################
1703 # @brief Assign a software license to a host
1704 # @param hostid Something like client_1.intranet.mydomain.de
1705 # @param licensePoolId The name of the pool.
1706 sub opsi_assignSoftwareLicenseToHost {
1707 my $startTime = Time::HiRes::time;
1708 my ($msg, $msg_hash, $session_id) = @_;
1709 my $header = @{$msg_hash->{'header'}}[0];
1710 my $source = @{$msg_hash->{'source'}}[0];
1711 my $target = @{$msg_hash->{'target'}}[0];
1712 my $hostId;
1713 my $licensePoolId;
1715 # Check input sanity
1716 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1717 $hostId = @{$msg_hash->{'hostId'}}[0];
1718 } else {
1719 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1720 }
1721 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1722 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1723 } else {
1724 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1725 }
1727 # Assign a software license to a host
1728 my $callobj = {
1729 method => 'getAndAssignSoftwareLicenseKey',
1730 params => [ $hostId, $licensePoolId ],
1731 id => 1,
1732 };
1733 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1735 # Check Opsi error
1736 my ($res_error, $res_error_str) = &check_opsi_res($res);
1737 if ($res_error){
1738 # Create error message
1739 &main::daemon_log("$session_id ERROR: cannot assign a software license to a host at Opsi server: ".$res_error_str, 1);
1740 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1741 return ( &create_xml_string($out_hash) );
1742 }
1744 # Create function result message
1745 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1746 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1748 my $endTime = Time::HiRes::time;
1749 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1750 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1751 return ( &create_xml_string($out_hash) );
1752 }
1754 ################################
1755 # @brief Unassign a software license from a host.
1756 # @param hostid Something like client_1.intranet.mydomain.de
1757 # @param licensePoolId The name of the pool.
1758 sub opsi_unassignSoftwareLicenseFromHost {
1759 my $startTime = Time::HiRes::time;
1760 my ($msg, $msg_hash, $session_id) = @_;
1761 my $header = @{$msg_hash->{'header'}}[0];
1762 my $source = @{$msg_hash->{'source'}}[0];
1763 my $target = @{$msg_hash->{'target'}}[0];
1764 my $hostId;
1765 my $licensePoolId;
1767 # Check input sanity
1768 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1769 $hostId = @{$msg_hash->{'hostId'}}[0];
1770 } else {
1771 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1772 }
1773 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1774 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1775 } else {
1776 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1777 }
1779 # Unassign a software license from a host
1780 my $callobj = {
1781 method => 'deleteSoftwareLicenseUsage',
1782 params => [ $hostId, '', $licensePoolId ],
1783 id => 1,
1784 };
1785 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1787 # Check Opsi error
1788 my ($res_error, $res_error_str) = &check_opsi_res($res);
1789 if ($res_error){
1790 # Create error message
1791 &main::daemon_log("$session_id ERROR: cannot unassign a software license from a host at Opsi server: ".$res_error_str, 1);
1792 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1793 return ( &create_xml_string($out_hash) );
1794 }
1796 # Create function result message
1797 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1798 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1800 my $endTime = Time::HiRes::time;
1801 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1802 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1803 return ( &create_xml_string($out_hash) );
1804 }
1806 ################################
1807 # @brief Unassign all software licenses from a host
1808 # @param hostid Something like client_1.intranet.mydomain.de
1809 sub opsi_unassignAllSoftwareLicensesFromHost {
1810 my $startTime = Time::HiRes::time;
1811 my ($msg, $msg_hash, $session_id) = @_;
1812 my $header = @{$msg_hash->{'header'}}[0];
1813 my $source = @{$msg_hash->{'source'}}[0];
1814 my $target = @{$msg_hash->{'target'}}[0];
1815 my $hostId;
1817 # Check input sanity
1818 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1819 $hostId = @{$msg_hash->{'hostId'}}[0];
1820 } else {
1821 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1822 }
1824 # Unassign all software licenses from a host
1825 my $callobj = {
1826 method => 'deleteAllSoftwareLicenseUsages',
1827 params => [ $hostId ],
1828 id => 1,
1829 };
1830 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1832 # Check Opsi error
1833 my ($res_error, $res_error_str) = &check_opsi_res($res);
1834 if ($res_error){
1835 # Create error message
1836 &main::daemon_log("$session_id ERROR: cannot unassign a software license from a host at Opsi server: ".$res_error_str, 1);
1837 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1838 return ( &create_xml_string($out_hash) );
1839 }
1841 # Create function result message
1842 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1843 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1845 my $endTime = Time::HiRes::time;
1846 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1847 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1848 return ( &create_xml_string($out_hash) );
1849 }
1852 ################################
1853 # @brief Returns the assigned licensePoolId and licenses, how often the product is installed and at which host
1854 # and the number of max and remaining installations for a given OPSI product.
1855 # @param productId Identificator of an OPSI product.
1856 sub opsi_getLicenseInformationForProduct {
1857 my $startTime = Time::HiRes::time;
1858 my ($msg, $msg_hash, $session_id) = @_;
1859 my $header = @{$msg_hash->{'header'}}[0];
1860 my $source = @{$msg_hash->{'source'}}[0];
1861 my $productId;
1862 my $out_hash;
1864 # Check input sanity
1865 if (&_check_xml_tag_is_ok ($msg_hash, 'productId')) {
1866 $productId = @{$msg_hash->{'productId'}}[0];
1867 } else {
1868 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1869 }
1871 # Fetch infos from Opsi server
1872 my $callobj = {
1873 method => 'getLicensePoolId',
1874 params => [ $productId ],
1875 id => 1,
1876 };
1877 #my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1878 my $res = $opsi_client->call($opsi_url, $callobj);
1880 # Check Opsi error
1881 my ($res_error, $res_error_str) = &check_opsi_res($res);
1882 if ($res_error){
1883 return &_giveErrorFeedback($msg_hash, "cannot get license pool for product '$productId' : ".$res_error_str, $session_id);
1884 }
1886 my $licensePoolId = $res->result;
1888 # Fetch statistic information for given pool ID
1889 $callobj = {
1890 method => 'getLicenseStatistics_hash',
1891 params => [ ],
1892 id => 1,
1893 };
1894 $res = $opsi_client->call($opsi_url, $callobj);
1896 # Check Opsi error
1897 ($res_error, $res_error_str) = &check_opsi_res($res);
1898 if ($res_error){
1899 # Create error message
1900 &main::daemon_log("$session_id ERROR: cannot get statistic informations for license pools : ".$res_error_str, 1);
1901 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1902 return ( &create_xml_string($out_hash) );
1903 }
1905 # Create function result message
1906 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1907 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1908 &add_content2xml_hash($out_hash, "licensePoolId", $licensePoolId);
1909 &add_content2xml_hash($out_hash, "licenses", $res->result->{$licensePoolId}->{'licenses'});
1910 &add_content2xml_hash($out_hash, "usageCount", $res->result->{$licensePoolId}->{'usageCount'});
1911 &add_content2xml_hash($out_hash, "maxInstallations", $res->result->{$licensePoolId}->{'maxInstallations'});
1912 &add_content2xml_hash($out_hash, "remainingInstallations", $res->result->{$licensePoolId}->{'remainingInstallations'});
1913 map(&add_content2xml_hash($out_hash, "usedBy", "$_"), @{ $res->result->{$licensePoolId}->{'usedBy'}});
1915 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1916 return ( &create_xml_string($out_hash) );
1917 }
1920 ################################
1921 # @brief Returns licensePoolId, description, a list of productIds, al list of windowsSoftwareIds and a list of licenses for a given licensePoolId.
1922 # Each license contains softwareLicenseId, maxInstallations, licenseType, licensePoolIds, licenseKeys, hostIds, expirationDate, boundToHost and licenseContractId.
1923 # The licenseContract contains conclusionDate, expirationDate, notes, notificationDate and partner.
1924 # @param licensePoolId The name of the pool.
1925 sub opsi_getPool {
1926 my $startTime = Time::HiRes::time;
1927 my ($msg, $msg_hash, $session_id) = @_;
1928 my $header = @{$msg_hash->{'header'}}[0];
1929 my $source = @{$msg_hash->{'source'}}[0];
1931 # Check input sanity
1932 my $licensePoolId;
1933 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1934 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1935 } else {
1936 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1937 }
1939 # Create hash for the answer
1940 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1941 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1943 # Call Opsi
1944 my ($res, $err) = &_getLicensePool_hash( 'licensePoolId'=> $licensePoolId );
1945 if ($err){
1946 return &_giveErrorFeedback($msg_hash, "cannot get license pool from Opsi server: ".$res, $session_id);
1947 }
1948 # Add data to outgoing hash
1949 &add_content2xml_hash($out_hash, "licensePoolId", $res->{'licensePoolId'});
1950 &add_content2xml_hash($out_hash, "description", $res->{'description'});
1951 map(&add_content2xml_hash($out_hash, "productIds", "$_"), @{ $res->{'productIds'} });
1952 map(&add_content2xml_hash($out_hash, "windowsSoftwareIds", "$_"), @{ $res->{'windowsSoftwareIds'} });
1955 # Call Opsi two times
1956 my ($usages_res, $usages_err) = &_getSoftwareLicenseUsages_listOfHashes('licensePoolId'=>$licensePoolId);
1957 if ($usages_err){
1958 return &_giveErrorFeedback($msg_hash, "cannot get software license usage information from Opsi server: ".$usages_res, $session_id);
1959 }
1960 my ($licenses_res, $licenses_err) = &_getSoftwareLicenses_listOfHashes();
1961 if ($licenses_err){
1962 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server: ".$licenses_res, $session_id);
1963 }
1965 # Add data to outgoing hash
1966 # Parse through all software licenses and select those associated to the pool
1967 my $res_hash = { 'hit'=> [] };
1968 foreach my $license ( @$licenses_res) {
1969 # Each license hash has a list of licensePoolIds so go through this list and search for matching licensePoolIds
1970 my $found = 0;
1971 my @licensePoolIds_list = @{$license->{licensePoolIds}};
1972 foreach my $lPI ( @licensePoolIds_list) {
1973 if ($lPI eq $licensePoolId) { $found++ }
1974 }
1975 if (not $found ) { next; };
1976 # Found matching licensePoolId
1977 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
1978 'licenseKeys' => {},
1979 'expirationDate' => [$license->{'expirationDate'}],
1980 'boundToHost' => [$license->{'boundToHost'}],
1981 'maxInstallations' => [$license->{'maxInstallations'}],
1982 'licenseType' => [$license->{'licenseType'}],
1983 'licenseContractId' => [$license->{'licenseContractId'}],
1984 'licensePoolIds' => [],
1985 'hostIds' => [],
1986 };
1987 foreach my $licensePoolId (@{ $license->{'licensePoolIds'}}) {
1988 push( @{$license_hash->{'licensePoolIds'}}, $licensePoolId);
1989 $license_hash->{licenseKeys}->{$licensePoolId} = [ $license->{'licenseKeys'}->{$licensePoolId} ];
1990 }
1991 foreach my $usage (@$usages_res) {
1992 # Search for hostIds with matching softwareLicenseId
1993 if ($license->{'softwareLicenseId'} eq $usage->{'softwareLicenseId'}) {
1994 push( @{ $license_hash->{hostIds}}, $usage->{hostId});
1995 }
1996 }
1998 # Each softwareLicenseId has one licenseContractId, fetch contract details for each licenseContractId
1999 my ($lContract_res, $lContract_err) = &_getLicenseContract_hash('licenseContractId'=>$license->{licenseContractId});
2000 if ($lContract_err){
2001 return &_giveErrorFeedback($msg_hash, "cannot get software license contract information from Opsi server: ".$licenses_res, $session_id);
2002 }
2003 $license_hash->{$license->{'licenseContractId'}} = [];
2004 my $licenseContract_hash = { 'conclusionDate' => [$lContract_res->{conclusionDate}],
2005 'notificationDate' => [$lContract_res->{notificationDate}],
2006 'notes' => [$lContract_res->{notes}],
2007 'exirationDate' => [$lContract_res->{expirationDate}],
2008 'partner' => [$lContract_res->{partner}],
2009 };
2010 push( @{$license_hash->{licenseContractData}}, $licenseContract_hash );
2012 push( @{$res_hash->{hit}}, $license_hash );
2013 }
2014 $out_hash->{licenses} = [$res_hash];
2016 my $endTime = Time::HiRes::time;
2017 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2018 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2019 return ( &create_xml_string($out_hash) );
2020 }
2023 ################################
2024 # @brief Removes at first the software license from license pool and than deletes the software license.
2025 # Attention, the software license has to exists otherwise it will lead to an Opsi internal server error.
2026 # @param softwareLicenseId Identificator of a license.
2027 # @param licensePoolId The name of the pool.
2028 sub opsi_removeLicense {
2029 my $startTime = Time::HiRes::time;
2030 my ($msg, $msg_hash, $session_id) = @_;
2031 my $header = @{$msg_hash->{'header'}}[0];
2032 my $source = @{$msg_hash->{'source'}}[0];
2034 # Check input sanity
2035 my $softwareLicenseId;
2036 if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
2037 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
2038 } else {
2039 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2040 }
2041 my $licensePoolId;
2042 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
2043 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
2044 } else {
2045 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2046 }
2048 # Call Opsi
2049 my ($res, $err) = &_removeSoftwareLicenseFromLicensePool( 'licensePoolId' => $licensePoolId, 'softwareLicenseId' => $softwareLicenseId );
2050 if ($err){
2051 return &_giveErrorFeedback($msg_hash, "cannot delete software license from pool: ".$res, $session_id);
2052 }
2054 # Call Opsi
2055 ($res, $err) = &_deleteSoftwareLicense( 'softwareLicenseId'=>$softwareLicenseId );
2056 if ($err){
2057 return &_giveErrorFeedback($msg_hash, "cannot delete software license from Opsi server: ".$res, $session_id);
2058 }
2060 # Create hash for the answer
2061 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2062 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2063 my $endTime = Time::HiRes::time;
2064 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2065 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2066 return ( &create_xml_string($out_hash) );
2067 }
2070 ################################
2071 # @brief Return softwareLicenseId, maxInstallations, licenseType, licensePoolIds, licenseContractId, expirationDate, boundToHost and a list of productIds.
2072 # @param hostId Something like client_1.intranet.mydomain.de
2073 sub opsi_getReservedLicenses {
2074 my $startTime = Time::HiRes::time;
2075 my ($msg, $msg_hash, $session_id) = @_;
2076 my $header = @{$msg_hash->{'header'}}[0];
2077 my $source = @{$msg_hash->{'source'}}[0];
2079 # Check input sanity
2080 my $hostId;
2081 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
2082 $hostId = @{$msg_hash->{'hostId'}}[0];
2083 } else {
2084 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2085 }
2087 # Fetch informations from Opsi server
2088 my ($license_res, $license_err) = &_getSoftwareLicenses_listOfHashes();
2089 if ($license_err){
2090 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server: ".$license_res, $session_id);
2091 }
2093 # Parse result
2094 my $res_hash = { 'hit'=> [] };
2095 foreach my $license ( @$license_res) {
2096 if ($license->{boundToHost} ne $hostId) { next; }
2098 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
2099 'maxInstallations' => [$license->{'maxInstallations'}],
2100 'boundToHost' => [$license->{'boundToHost'}],
2101 'expirationDate' => [$license->{'expirationDate'}],
2102 'licenseContractId' => [$license->{'licenseContractId'}],
2103 'licenseType' => [$license->{'licenseType'}],
2104 'licensePoolIds' => [],
2105 };
2107 foreach my $licensePoolId (@{$license->{'licensePoolIds'}}) {
2108 # Fetch information for license pools containing a software license which is bound to given host
2109 my ($pool_res, $pool_err) = &_getLicensePool_hash( 'licensePoolId'=>$licensePoolId );
2110 if ($pool_err){
2111 return &_giveErrorFeedback($msg_hash, "cannot get license pool from Opsi server: ".$pool_res, $session_id);
2112 }
2114 # Add licensePool information to result hash
2115 push (@{$license_hash->{licensePoolIds}}, $licensePoolId);
2116 $license_hash->{$licensePoolId} = {'productIds'=>[], 'windowsSoftwareIds'=>[]};
2117 map (push (@{$license_hash->{$licensePoolId}->{productIds}}, $_), @{$pool_res->{productIds}});
2118 map (push (@{$license_hash->{$licensePoolId}->{windowsSoftwareIds}}, $_), @{$pool_res->{windowsSoftwareIds}});
2119 }
2120 push( @{$res_hash->{hit}}, $license_hash );
2121 }
2122 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2123 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2124 $out_hash->{licenses} = [$res_hash];
2126 my $endTime = Time::HiRes::time;
2127 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2128 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2129 return ( &create_xml_string($out_hash) );
2130 }
2132 ################################
2133 # @brief Bound the given softwareLicenseId to the given host.
2134 # @param hostId Opsi hostId
2135 # @param softwareLicenseId Identificator of a license (optional).
2136 sub opsi_boundHostToLicense {
2137 my $startTime = Time::HiRes::time;
2138 my ($msg, $msg_hash, $session_id) = @_;
2139 my $header = @{$msg_hash->{'header'}}[0];
2140 my $source = @{$msg_hash->{'source'}}[0];
2142 # Check input sanity
2143 my $hostId;
2144 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
2145 $hostId = @{$msg_hash->{'hostId'}}[0];
2146 } else {
2147 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2148 }
2149 my $softwareLicenseId;
2150 if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
2151 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
2152 } else {
2153 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2154 }
2156 # Fetch informations from Opsi server
2157 my ($license_res, $license_err) = &_getSoftwareLicenses_listOfHashes();
2158 if ($license_err){
2159 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server: ".$license_res, $session_id);
2160 }
2162 # Memorize parameter for given softwareLicenseId
2163 my $licenseContractId;
2164 my $licenseType;
2165 my $maxInstallations;
2166 my $boundToHost;
2167 my $expirationDate = "";
2168 my $found;
2169 foreach my $license (@$license_res) {
2170 if ($license->{softwareLicenseId} ne $softwareLicenseId) { next; }
2171 $licenseContractId = $license->{licenseContractId};
2172 $licenseType = $license->{licenseType};
2173 $maxInstallations = $license->{maxInstallations};
2174 $expirationDate = $license->{expirationDate};
2175 $found++;
2176 }
2178 if (not $found) {
2179 return &_giveErrorFeedback($msg_hash, "no softwarelicenseId found with name '".$softwareLicenseId."'", $session_id);
2180 }
2182 # Set boundToHost option for a given software license
2183 my ($bound_res, $bound_err) = &_createSoftwareLicense('softwareLicenseId'=>$softwareLicenseId,
2184 'licenseContractId' => $licenseContractId,
2185 'licenseType' => $licenseType,
2186 'maxInstallations' => $maxInstallations,
2187 'boundToHost' => $hostId,
2188 'expirationDate' => $expirationDate);
2189 if ($bound_err) {
2190 return &_giveErrorFeedback($msg_hash, "cannot set boundToHost for given softwareLicenseId and hostId: ".$bound_res, $session_id);
2191 }
2193 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2194 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2196 my $endTime = Time::HiRes::time;
2197 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2198 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2199 return ( &create_xml_string($out_hash) );
2200 }
2202 ################################
2203 # @brief Release a software license formerly bound to a host.
2204 # @param softwareLicenseId Identificator of a license.
2205 sub opsi_unboundHostFromLicense {
2206 # This is really mad! Opsi is not able to unbound a lincense from a host. To provide the functionality for GOsa
2207 # 4 rpc calls to Opsi are necessary. First, fetch all data for the given softwareLicenseId, then all details for the associated
2208 # licenseContractId, then delete the softwareLicense and finally recreate the softwareLicense without the boundToHost option. NASTY!
2209 my $startTime = Time::HiRes::time;
2210 my ($msg, $msg_hash, $session_id) = @_;
2211 my $header = @{$msg_hash->{'header'}}[0];
2212 my $source = @{$msg_hash->{'source'}}[0];
2214 # Check input sanity
2215 my $softwareLicenseId;
2216 if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
2217 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
2218 } else {
2219 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2220 }
2222 # Memorize parameter witch are required for this procedure
2223 my $licenseContractId;
2224 my $licenseType;
2225 my $maxInstallations;
2226 my $expirationDate;
2227 my $partner;
2228 my $conclusionDate;
2229 my $notificationDate;
2230 my $notes;
2231 my $licensePoolId;
2232 my $licenseKey;
2234 # Fetch license informations from Opsi server
2235 my ($license_res, $license_err) = &_getSoftwareLicenses_listOfHashes();
2236 if ($license_err){
2237 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server, required to unbound license from host: ".$license_res, $session_id);
2238 }
2239 my $found = 0;
2240 foreach my $license (@$license_res) {
2241 if (($found > 0) || ($license->{softwareLicenseId} ne $softwareLicenseId)) { next; }
2242 $licenseContractId = $license->{licenseContractId};
2243 $licenseType = $license->{licenseType};
2244 $maxInstallations = $license->{maxInstallations};
2245 $expirationDate = $license->{expirationDate};
2246 $licensePoolId = @{$license->{licensePoolIds}}[0];
2247 $licenseKey = $license->{licenseKeys}->{$licensePoolId};
2248 $found++;
2249 }
2251 # Fetch contract informations from Opsi server
2252 my ($contract_res, $contract_err) = &_getLicenseContract_hash('licenseContractId'=>$licenseContractId);
2253 if ($contract_err){
2254 return &_giveErrorFeedback($msg_hash, "cannot get contract license information from Opsi server, required to unbound license from host: ".$license_res, $session_id);
2255 }
2256 $partner = $contract_res->{partner};
2257 $conclusionDate = $contract_res->{conclusionDate};
2258 $notificationDate = $contract_res->{notificationDate};
2259 $expirationDate = $contract_res->{expirationDate};
2260 $notes = $contract_res->{notes};
2262 # Delete software license
2263 my ($res, $err) = &_deleteSoftwareLicense( 'softwareLicenseId' => $softwareLicenseId, 'removeFromPools'=> "true" );
2264 if ($err) {
2265 return &_giveErrorFeedback($msg_hash, "cannot delet license from Opsi server, required to unbound license from host : ".$res, $session_id);
2266 }
2268 # Recreate software license without boundToHost
2269 ($res, $err) = &_createLicenseContract( 'licenseContractId' => $licenseContractId, 'partner' => $partner, 'conclusionDate' => $conclusionDate,
2270 'notificationDate' => $notificationDate, 'expirationDate' => $expirationDate, 'notes' => $notes );
2271 if ($err) {
2272 return &_giveErrorFeedback($msg_hash, "cannot create license contract at Opsi server, required to unbound license from host : ".$res, $session_id);
2273 }
2274 ($res, $err) = &_createSoftwareLicense( 'softwareLicenseId' => $softwareLicenseId, 'licenseContractId' => $licenseContractId, 'licenseType' => $licenseType,
2275 'maxInstallations' => $maxInstallations, 'boundToHost' => "", 'expirationDate' => $expirationDate );
2276 if ($err) {
2277 return &_giveErrorFeedback($msg_hash, "cannot create software license at Opsi server, required to unbound license from host : ".$res, $session_id);
2278 }
2279 ($res, $err) = &_addSoftwareLicenseToLicensePool( 'softwareLicenseId' => $softwareLicenseId, 'licensePoolId' => $licensePoolId, 'licenseKey' => $licenseKey );
2280 if ($err) {
2281 return &_giveErrorFeedback($msg_hash, "cannot add software license to license pool at Opsi server, required to unbound license from host : ".$res, $session_id);
2282 }
2284 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2285 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2287 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
2288 return ( &create_xml_string($out_hash) );
2289 }
2291 ################################
2292 # @brief Returns a list of licenses with softwaerLicenseId, maxInstallations, boundToHost, expirationDate, licenseContractId, licenseType, a list of licensePoolIds with associated licenseKeys
2293 sub opsi_getAllSoftwareLicenses {
2294 my $startTime = Time::HiRes::time;
2295 my ($msg, $msg_hash, $session_id) = @_;
2296 my $header = @{$msg_hash->{'header'}}[0];
2297 my $source = @{$msg_hash->{'source'}}[0];
2299 my ($res, $err) = &_getSoftwareLicenses_listOfHashes();
2300 if ($err) {
2301 return &_giveErrorFeedback($msg_hash, "cannot fetch software licenses from Opsi server : ".$res, $session_id);
2302 }
2304 # Parse result
2305 my $res_hash = { 'hit'=> [] };
2306 foreach my $license ( @$res) {
2307 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
2308 'maxInstallations' => [$license->{'maxInstallations'}],
2309 'boundToHost' => [$license->{'boundToHost'}],
2310 'expirationDate' => [$license->{'expirationDate'}],
2311 'licenseContractId' => [$license->{'licenseContractId'}],
2312 'licenseType' => [$license->{'licenseType'}],
2313 'licensePoolIds' => [],
2314 'licenseKeys'=> {}
2315 };
2316 foreach my $licensePoolId (@{$license->{'licensePoolIds'}}) {
2317 push( @{$license_hash->{'licensePoolIds'}}, $licensePoolId);
2318 $license_hash->{licenseKeys}->{$licensePoolId} = [ $license->{'licenseKeys'}->{$licensePoolId} ];
2319 }
2320 push( @{$res_hash->{hit}}, $license_hash );
2321 }
2323 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2324 $out_hash->{licenses} = [$res_hash];
2325 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2327 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
2328 return ( &create_xml_string($out_hash) );
2329 }
2332 ################################
2333 # @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
2334 # @param hostId Opsi hostId
2335 sub opsi_get_full_product_host_information {
2336 my $startTime = Time::HiRes::time;
2337 my ($msg, $msg_hash, $session_id) = @_;
2338 my $header = @{$msg_hash->{'header'}}[0];
2339 my $source = @{$msg_hash->{'source'}}[0];
2340 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
2341 my $hostId;
2343 my ($res, $err) = &_get_full_product_host_information( hostId=>@{$msg_hash->{'hostId'}}[0]);
2344 if ($err) {
2345 return &_giveErrorFeedback($msg_hash, "cannot fetch full_product_host_information from Opsi server : ".$res, $session_id);
2346 }
2348 # Build return message with twisted target and source
2349 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2350 if (defined $forward_to_gosa) {
2351 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
2352 }
2353 &add_content2xml_hash($out_hash, "xxx", "");
2355 # Get hostId if defined
2356 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1)) {
2357 $hostId = @{$msg_hash->{'hostId'}}[0];
2358 &add_content2xml_hash($out_hash, "hostId", $hostId);
2359 }
2361 # Move to XML string
2362 my $xml_msg= &create_xml_string($out_hash);
2364 # Convert result in something usable
2365 my $replace= "";
2366 foreach my $product ( @$res) {
2368 # Open item
2369 $replace.= "<item>";
2371 # Add flat hash information
2372 my @entries= ( "priority", "onceScript", "licenseRequired", "packageVersion", "productVersion", "advice",
2373 "setupScript", "windowsSoftwareIds", "installationStatus", "pxeConfigTemplate", "name", "type",
2374 "creationTimestamp", "alwaysScript", "productId", "description", "actionRequest", "uninstallScript",
2375 "action", "updateScript", "productClassNames");
2376 foreach my $entry (@entries) {
2377 if (defined $product->{$entry}) {
2378 my $value= $product->{$entry};
2380 if(ref($value) eq 'ARRAY'){
2381 my $tmp= "";
2382 foreach my $element (@$value) {
2383 $tmp.= "<element>$element</element>";
2384 }
2385 $replace.= "<$entry>$tmp</$entry>";
2386 } else {
2387 $replace.= "<$entry>$value</$entry>";
2388 }
2389 }
2390 }
2392 # Add property information
2393 if (defined $product->{'properties'}) {
2394 $replace.= "<properties>";
2395 while ((my $key, my $value) = each(%{$product->{'properties'}})){
2396 $replace.= "<$key>";
2398 while ((my $pkey, my $pvalue) = each(%$value)){
2399 if(ref($pvalue) eq 'ARRAY'){
2400 my $tmp= "";
2401 foreach my $element (@$pvalue) {
2402 $tmp.= "<element>$element</element>";
2403 }
2404 $replace.= "<$pkey>$tmp</$pkey>";
2405 } else {
2406 $replace.= "<$pkey>$pvalue</$pkey>";
2407 }
2408 }
2409 $replace.= "</$key>";
2410 }
2411 $replace.= "</properties>";
2412 }
2414 # Close item
2415 $replace.= "</item>";
2416 }
2418 $xml_msg=~ s/<xxx><\/xxx>/\n$replace/;
2420 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
2421 return ( $xml_msg );
2422 }
2425 sub opsi_test {
2426 my ($msg, $msg_hash, $session_id) = @_;
2427 my $header = @{$msg_hash->{'header'}}[0];
2428 my $source = @{$msg_hash->{'source'}}[0];
2429 my $pram1 = @{$msg_hash->{'productId'}}[0];
2432 # Fetch infos from Opsi server
2433 my $callobj = {
2434 method => 'getLicensePoolId',
2435 params => [ $pram1 ],
2436 id => 1,
2437 };
2438 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
2440 return ();
2441 }
2444 # ----------------------------------------------------------------------------
2445 # internal methods handling the comunication with Opsi
2446 # ----------------------------------------------------------------------------
2448 ################################
2449 # @brief Checks if there is a specified tag and if the the tag has a content.
2450 sub _check_xml_tag_is_ok {
2451 my ($msg_hash,$tag) = @_;
2452 if (not defined $msg_hash->{$tag}) {
2453 $_ = "message contains no tag '$tag'";
2454 return 0;
2455 }
2456 if (ref @{$msg_hash->{$tag}}[0] eq 'HASH') {
2457 $_ = "message tag '$tag' has no content";
2458 return 0;
2459 }
2460 return 1;
2461 }
2463 ################################
2464 # @brief Writes the log line and returns the error message for GOsa.
2465 sub _giveErrorFeedback {
2466 my ($msg_hash, $err_string, $session_id) = @_;
2467 &main::daemon_log("$session_id ERROR: $err_string", 1);
2468 my $out_hash = &main::create_xml_hash("error", $main::server_address, @{$msg_hash->{source}}[0], $err_string);
2469 if (exists $msg_hash->{forward_to_gosa}) {
2470 &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]);
2471 }
2472 return ( &create_xml_string($out_hash) );
2473 }
2476 ################################
2477 # @brief Perform the call to the Opsi server and measure the time for the call
2478 sub _callOpsi {
2479 my %arg = ('method'=>undef, 'params'=>[], 'id'=>1, @_);
2481 my $callObject = {
2482 method => $arg{method},
2483 params => $arg{params},
2484 id => $arg{id},
2485 };
2487 my $startTime = Time::HiRes::time;
2488 my $opsiResult = $opsi_client->call($opsi_url, $callObject);
2489 my $endTime = Time::HiRes::time;
2490 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2492 &main::daemon_log("0 DEBUG: time to process opsi call '$arg{method}' : $elapsedTime seconds", 1034);
2494 return $opsiResult;
2495 }
2497 sub _getLicensePool_hash {
2498 my %arg = ( 'licensePoolId' => undef, @_ );
2500 if (not defined $arg{licensePoolId} ) {
2501 return ("function requires licensePoolId as parameter", 1);
2502 }
2504 my $res = &_callOpsi( method => 'getLicensePool_hash', params =>[$arg{licensePoolId}], id => 1 );
2505 my ($res_error, $res_error_str) = &check_opsi_res($res);
2506 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2508 return ($res->result, 0);
2509 }
2511 sub _getSoftwareLicenses_listOfHashes {
2513 my $res = &_callOpsi( method => 'getSoftwareLicenses_listOfHashes' );
2514 my ($res_error, $res_error_str) = &check_opsi_res($res);
2515 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2517 return ($res->result, 0);
2518 }
2520 sub _getSoftwareLicenseUsages_listOfHashes {
2521 my %arg = ( 'hostId' => "", 'licensePoolId' => "", @_ );
2523 my $res = &_callOpsi( method=>'getSoftwareLicenseUsages_listOfHashes', params=>[ $arg{hostId}, $arg{licensePoolId} ] );
2524 my ($res_error, $res_error_str) = &check_opsi_res($res);
2525 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2527 return ($res->result, 0);
2528 }
2530 sub _removeSoftwareLicenseFromLicensePool {
2531 my %arg = ( 'softwareLicenseId' => undef, 'licensePoolId' => undef, @_ );
2533 if (not defined $arg{softwareLicenseId} ) {
2534 return ("function requires softwareLicenseId as parameter", 1);
2535 }
2536 if (not defined $arg{licensePoolId} ) {
2537 return ("function requires licensePoolId as parameter", 1);
2538 }
2540 my $res = &_callOpsi( method=>'removeSoftwareLicenseFromLicensePool', params=>[ $arg{softwareLicenseId}, $arg{licensePoolId} ] );
2541 my ($res_error, $res_error_str) = &check_opsi_res($res);
2542 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2544 return ($res->result, 0);
2545 }
2547 sub _deleteSoftwareLicense {
2548 my %arg = ( 'softwareLicenseId' => undef, 'removeFromPools' => "false", @_ );
2550 if (not defined $arg{softwareLicenseId} ) {
2551 return ("function requires softwareLicenseId as parameter", 1);
2552 }
2553 my $removeFromPools = "";
2554 if ((defined $arg{removeFromPools}) && ($arg{removeFromPools} eq "true")) {
2555 $removeFromPools = "removeFromPools";
2556 }
2558 my $res = &_callOpsi( method=>'deleteSoftwareLicense', params=>[ $arg{softwareLicenseId}, $removeFromPools ] );
2559 my ($res_error, $res_error_str) = &check_opsi_res($res);
2560 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2562 return ($res->result, 0);
2563 }
2565 sub _getLicensePoolId {
2566 my %arg = ( 'productId' => undef, @_ );
2568 if (not defined $arg{productId} ) {
2569 return ("function requires productId as parameter", 1);
2570 }
2572 my $res = &_callOpsi( method => 'getLicensePoolId', params => [ $arg{productId} ] );
2573 my ($res_error, $res_error_str) = &check_opsi_res($res);
2574 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2576 return ($res->result, 0);
2577 }
2579 sub _getLicenseContract_hash {
2580 my %arg = ( 'licenseContractId' => undef, @_ );
2582 if (not defined $arg{licenseContractId} ) {
2583 return ("function requires licenseContractId as parameter", 1);
2584 }
2586 my $res = &_callOpsi( method => 'getLicenseContract_hash', params => [ $arg{licenseContractId} ] );
2587 my ($res_error, $res_error_str) = &check_opsi_res($res);
2588 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2590 return ($res->result, 0);
2591 }
2593 sub _createLicenseContract {
2594 my %arg = (
2595 'licenseContractId' => undef,
2596 'partner' => undef,
2597 'conclusionDate' => undef,
2598 'notificationDate' => undef,
2599 'expirationDate' => undef,
2600 'notes' => undef,
2601 @_ );
2603 my $res = &_callOpsi( method => 'createLicenseContract',
2604 params => [ $arg{licenseContractId}, $arg{partner}, $arg{conclusionDate}, $arg{notificationDate}, $arg{expirationDate}, $arg{notes} ],
2605 );
2606 my ($res_error, $res_error_str) = &check_opsi_res($res);
2607 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2609 return ($res->result, 0);
2610 }
2612 sub _createSoftwareLicense {
2613 my %arg = (
2614 'softwareLicenseId' => undef,
2615 'licenseContractId' => undef,
2616 'licenseType' => undef,
2617 'maxInstallations' => undef,
2618 'boundToHost' => undef,
2619 'expirationDate' => undef,
2620 @_ );
2622 my $res = &_callOpsi( method => 'createSoftwareLicense',
2623 params => [ $arg{softwareLicenseId}, $arg{licenseContractId}, $arg{licenseType}, $arg{maxInstallations}, $arg{boundToHost}, $arg{expirationDate} ],
2624 );
2625 my ($res_error, $res_error_str) = &check_opsi_res($res);
2626 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2628 return ($res->result, 0);
2629 }
2631 sub _addSoftwareLicenseToLicensePool {
2632 my %arg = (
2633 'softwareLicenseId' => undef,
2634 'licensePoolId' => undef,
2635 'licenseKey' => undef,
2636 @_ );
2638 if (not defined $arg{softwareLicenseId} ) {
2639 return ("function requires softwareLicenseId as parameter", 1);
2640 }
2641 if (not defined $arg{licensePoolId} ) {
2642 return ("function requires licensePoolId as parameter", 1);
2643 }
2645 my $res = &_callOpsi( method => 'addSoftwareLicenseToLicensePool', params => [ $arg{softwareLicenseId}, $arg{licensePoolId}, $arg{licenseKey} ] );
2646 my ($res_error, $res_error_str) = &check_opsi_res($res);
2647 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2649 return ($res->result, 0);
2650 }
2652 sub _getProductStates_hash {
2653 my %arg = ( 'hostId' => undef, @_ );
2655 if (not defined $arg{hostId} ) {
2656 return ("function requires hostId as parameter", 1);
2657 }
2659 my $res = &_callOpsi( method => 'getProductStates_hash', params => [$arg{hostId}]);
2660 my ($res_error, $res_error_str) = &check_opsi_res($res);
2661 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2663 return ($res->result, 0);
2664 }
2666 sub _get_full_product_host_information {
2667 my %arg = ( 'hostId' => undef, @_ );
2669 my $res = &_callOpsi( method => 'getFullProductHostInformation_list', params => [$arg{hostId}]);
2670 my ($res_error, $res_error_str) = &check_opsi_res($res);
2671 if ($res_error){ return ((caller(0))[3]." : ".$res_error_str, 1); }
2673 return ($res->result, 0);
2674 }
2676 1;