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