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<default>".xml_quote($value)."</default>$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 return &_giveErrorFeedback($msg_hash, "cannot fetch licensePoolId for given productId : ".$res, $session_id);
1426 }
1427 my $licensePoolId = $res; # We assume that there is only one pool for each productID!!!
1429 # Fetch softwareLiceceUsages for licensePoolId
1430 ($res, $err) = &_getSoftwareLicenseUsages_listOfHashes('licensePoolId'=>$licensePoolId);
1431 if ($err){
1432 return &_giveErrorFeedback($msg_hash, "cannot fetch software licenses from license pool : ".$res, $session_id);
1433 }
1434 # Parse Opsi result
1435 my $res_hash = &_parse_getSoftwareLicenseUsages($res);
1437 # Create function result message
1438 my $out_hash = &create_xml_hash("answer_$header", $main::server_address, $source);
1439 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1440 $out_hash->{result} = [$res_hash];
1442 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1443 return ( &create_xml_string($out_hash) );
1444 }
1446 ################################
1447 # @brief Returns expirationDate, boundToHost, maxInstallation, licenseTyp, licensePoolIds and licenseKeys for a given softwareLicense ID.
1448 # @param softwareLicenseId Identificator of a license.
1449 sub opsi_getSoftwareLicense_hash {
1450 my $startTime = Time::HiRes::time;
1451 my ($msg, $msg_hash, $session_id) = @_;
1452 my $header = @{$msg_hash->{'header'}}[0];
1453 my $source = @{$msg_hash->{'source'}}[0];
1454 my $target = @{$msg_hash->{'target'}}[0];
1455 my $softwareLicenseId;
1456 my $out_hash;
1458 # Check input sanity
1459 if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
1460 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
1461 } else {
1462 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1463 }
1465 my $callobj = {
1466 method => 'getSoftwareLicense_hash',
1467 params => [ $softwareLicenseId ],
1468 id => 1,
1469 };
1470 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1472 # Check Opsi error
1473 my ($res_error, $res_error_str) = &check_opsi_res($res);
1474 if ($res_error){
1475 # Create error message
1476 &main::daemon_log("$session_id ERROR: cannot fetch information for license '$softwareLicenseId': ".$res_error_str, 1);
1477 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1478 return ( &create_xml_string($out_hash) );
1479 }
1481 # Create function result message
1482 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1483 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1484 &add_content2xml_hash($out_hash, "expirationDate", $res->result->{'expirationDate'});
1485 &add_content2xml_hash($out_hash, "boundToHost", $res->result->{'boundToHost'});
1486 &add_content2xml_hash($out_hash, "maxInstallations", $res->result->{'maxInstallations'});
1487 &add_content2xml_hash($out_hash, "licenseTyp", $res->result->{'licenseTyp'});
1488 foreach my $licensePoolId ( @{$res->result->{'licensePoolIds'}}) {
1489 &add_content2xml_hash($out_hash, "licensePoolId", $licensePoolId);
1490 &add_content2xml_hash($out_hash, $licensePoolId, $res->result->{'licenseKeys'}->{$licensePoolId});
1491 }
1493 my $endTime = Time::HiRes::time;
1494 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1495 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1496 return ( &create_xml_string($out_hash) );
1497 }
1499 ################################
1500 # @brief Delete licnese pool by license pool ID. A pool can only be deleted if there are no software licenses bound to the pool.
1501 # The fixed parameter deleteLicenses=True specifies that all software licenses bound to the pool are being deleted.
1502 # @param licensePoolId The name of the pool.
1503 sub opsi_deleteLicensePool {
1504 my $startTime = Time::HiRes::time;
1505 my ($msg, $msg_hash, $session_id) = @_;
1506 my $header = @{$msg_hash->{'header'}}[0];
1507 my $source = @{$msg_hash->{'source'}}[0];
1508 my $target = @{$msg_hash->{'target'}}[0];
1509 my $licensePoolId;
1510 my $out_hash;
1512 # Check input sanity
1513 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1514 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1515 } else {
1516 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1517 }
1519 # Fetch softwareLicenseIds used in license pool
1520 # This has to be done because function deleteLicensePool deletes the pool and the corresponding software licenses
1521 # but not the license contracts of the software licenses. In our case each software license has exactly one license contract.
1522 my $callobj = {
1523 method => 'getSoftwareLicenses_listOfHashes',
1524 params => [ ],
1525 id => 1,
1526 };
1527 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1529 # Keep list of licenseContractIds in mind to delete it after the deletion of the software licenses
1530 my @lCI_toBeDeleted;
1531 foreach my $softwareLicenseHash ( @{$res->result} ) {
1532 if ((@{$softwareLicenseHash->{'licensePoolIds'}} == 0) || (@{$softwareLicenseHash->{'licensePoolIds'}}[0] ne $licensePoolId)) {
1533 next;
1534 }
1535 push (@lCI_toBeDeleted, $softwareLicenseHash->{'licenseContractId'});
1536 }
1538 # Delete license pool at Opsi server
1539 $callobj = {
1540 method => 'deleteLicensePool',
1541 params => [ $licensePoolId, 'deleteLicenses=True' ],
1542 id => 1,
1543 };
1544 $res = $main::opsi_client->call($main::opsi_url, $callobj);
1545 my ($res_error, $res_error_str) = &check_opsi_res($res);
1546 if ($res_error){
1547 # Create error message
1548 &main::daemon_log("$session_id ERROR: cannot delete license pool at Opsi server: ".$res_error_str, 1);
1549 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1550 return ( &create_xml_string($out_hash) );
1551 }
1553 # Delete each license contract connected with the license pool
1554 foreach my $licenseContractId ( @lCI_toBeDeleted ) {
1555 my $callobj = {
1556 method => 'deleteLicenseContract',
1557 params => [ $licenseContractId ],
1558 id => 1,
1559 };
1560 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1561 my ($res_error, $res_error_str) = &check_opsi_res($res);
1562 if ($res_error){
1563 # Create error message
1564 &main::daemon_log("$session_id ERROR: cannot delete license contract '$licenseContractId' connected with license pool '$licensePoolId' at Opsi server: ".$res_error_str, 1);
1565 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1566 return ( &create_xml_string($out_hash) );
1567 }
1568 }
1570 # Create function result message
1571 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1572 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1574 my $endTime = Time::HiRes::time;
1575 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1576 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1577 return ( &create_xml_string($out_hash) );
1578 }
1580 ################################
1581 # @brief Create a license contract, create a software license and add the software license to the license pool
1582 # @param licensePoolId The name of the pool the license should be assigned.
1583 # @param licenseKey The license key.
1584 # @param partner Name of the license partner (optional).
1585 # @param conclusionDate Date of conclusion of license contract (optional)
1586 # @param notificationDate Date of notification that license is running out soon (optional).
1587 # @param notes This is the place for some notes (optional)
1588 # @param softwareLicenseId Identificator of a license (optional).
1589 # @param licenseTyp Typ of a licnese, either "OEM", "VOLUME" or "RETAIL" (optional).
1590 # @param maxInstallations The number of clients use this license (optional).
1591 # @param boundToHost The name of the client the license is bound to (optional).
1592 # @param expirationDate The date when the license is running down (optional).
1593 sub opsi_createLicense {
1594 my $startTime = Time::HiRes::time;
1595 my ($msg, $msg_hash, $session_id) = @_;
1596 my $header = @{$msg_hash->{'header'}}[0];
1597 my $source = @{$msg_hash->{'source'}}[0];
1598 my $target = @{$msg_hash->{'target'}}[0];
1599 my $partner = defined $msg_hash->{'partner'} ? @{$msg_hash->{'partner'}}[0] : undef;
1600 my $conclusionDate = defined $msg_hash->{'conclusionDate'} ? @{$msg_hash->{'conclusionDate'}}[0] : undef;
1601 my $notificationDate = defined $msg_hash->{'notificationDate'} ? @{$msg_hash->{'notificationDate'}}[0] : undef;
1602 my $notes = defined $msg_hash->{'notes'} ? @{$msg_hash->{'notes'}}[0] : undef;
1603 my $licenseContractId = undef;
1604 my $softwareLicenseId = defined $msg_hash->{'softwareLicenseId'} ? @{$msg_hash->{'softwareLicenseId'}}[0] : undef;
1605 my $licenseType = defined $msg_hash->{'licenseType'} ? @{$msg_hash->{'licenseType'}}[0] : undef;
1606 my $maxInstallations = defined $msg_hash->{'maxInstallations'} ? @{$msg_hash->{'maxInstallations'}}[0] : undef;
1607 my $boundToHost = defined $msg_hash->{'boundToHost'} ? @{$msg_hash->{'boundToHost'}}[0] : undef;
1608 my $expirationDate = defined $msg_hash->{'expirationDate'} ? @{$msg_hash->{'expirationDate'}}[0] : undef;
1609 my $licensePoolId;
1610 my $licenseKey;
1611 my $out_hash;
1613 # Check input sanity
1614 if (&_check_xml_tag_is_ok ($msg_hash, 'licenseKey')) {
1615 $licenseKey = @{$msg_hash->{'licenseKey'}}[0];
1616 } else {
1617 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1618 }
1619 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1620 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1621 } else {
1622 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1623 }
1624 if ((defined $licenseType) && (not exists $licenseTyp_hash->{$licenseType})) {
1625 return &_giveErrorFeedback($msg_hash, "The typ of a license can be either 'OEM', 'VOLUME' or 'RETAIL'.", $session_id);
1626 }
1628 # Automatically define licenseContractId if ID is not given
1629 if (defined $softwareLicenseId) {
1630 $licenseContractId = "c_".$softwareLicenseId;
1631 }
1633 # Create license contract at Opsi server
1634 my $callobj = {
1635 method => 'createLicenseContract',
1636 params => [ $licenseContractId, $partner, $conclusionDate, $notificationDate, undef, $notes ],
1637 id => 1,
1638 };
1639 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1641 # Check Opsi error
1642 my ($res_error, $res_error_str) = &check_opsi_res($res);
1643 if ($res_error){
1644 # Create error message
1645 &main::daemon_log("$session_id ERROR: cannot create license contract at Opsi server: ".$res_error_str, 1);
1646 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1647 return ( &create_xml_string($out_hash) );
1648 }
1650 $licenseContractId = $res->result;
1652 # Create software license at Opsi server
1653 $callobj = {
1654 method => 'createSoftwareLicense',
1655 params => [ $softwareLicenseId, $licenseContractId, $licenseType, $maxInstallations, $boundToHost, $expirationDate ],
1656 id => 1,
1657 };
1658 $res = $main::opsi_client->call($main::opsi_url, $callobj);
1660 # Check Opsi error
1661 ($res_error, $res_error_str) = &check_opsi_res($res);
1662 if ($res_error){
1663 # Create error message
1664 &main::daemon_log("$session_id ERROR: cannot create software license at Opsi server: ".$res_error_str, 1);
1665 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1666 return ( &create_xml_string($out_hash) );
1667 }
1669 $softwareLicenseId = $res->result;
1671 # Add software license to license pool
1672 $callobj = {
1673 method => 'addSoftwareLicenseToLicensePool',
1674 params => [ $softwareLicenseId, $licensePoolId, $licenseKey ],
1675 id => 1,
1676 };
1677 $res = $main::opsi_client->call($main::opsi_url, $callobj);
1679 # Check Opsi error
1680 ($res_error, $res_error_str) = &check_opsi_res($res);
1681 if ($res_error){
1682 # Create error message
1683 &main::daemon_log("$session_id ERROR: cannot add software license to license pool at Opsi server: ".$res_error_str, 1);
1684 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1685 return ( &create_xml_string($out_hash) );
1686 }
1688 # Create function result message
1689 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1690 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1692 my $endTime = Time::HiRes::time;
1693 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1694 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1695 return ( &create_xml_string($out_hash) );
1696 }
1698 ################################
1699 # @brief Assign a software license to a host
1700 # @param hostid Something like client_1.intranet.mydomain.de
1701 # @param licensePoolId The name of the pool.
1702 sub opsi_assignSoftwareLicenseToHost {
1703 my $startTime = Time::HiRes::time;
1704 my ($msg, $msg_hash, $session_id) = @_;
1705 my $header = @{$msg_hash->{'header'}}[0];
1706 my $source = @{$msg_hash->{'source'}}[0];
1707 my $target = @{$msg_hash->{'target'}}[0];
1708 my $hostId;
1709 my $licensePoolId;
1711 # Check input sanity
1712 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1713 $hostId = @{$msg_hash->{'hostId'}}[0];
1714 } else {
1715 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1716 }
1717 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1718 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1719 } else {
1720 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1721 }
1723 # Assign a software license to a host
1724 my $callobj = {
1725 method => 'getAndAssignSoftwareLicenseKey',
1726 params => [ $hostId, $licensePoolId ],
1727 id => 1,
1728 };
1729 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1731 # Check Opsi error
1732 my ($res_error, $res_error_str) = &check_opsi_res($res);
1733 if ($res_error){
1734 # Create error message
1735 &main::daemon_log("$session_id ERROR: cannot assign a software license to a host at Opsi server: ".$res_error_str, 1);
1736 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1737 return ( &create_xml_string($out_hash) );
1738 }
1740 # Create function result message
1741 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1742 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1744 my $endTime = Time::HiRes::time;
1745 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1746 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1747 return ( &create_xml_string($out_hash) );
1748 }
1750 ################################
1751 # @brief Unassign a software license from a host.
1752 # @param hostid Something like client_1.intranet.mydomain.de
1753 # @param licensePoolId The name of the pool.
1754 sub opsi_unassignSoftwareLicenseFromHost {
1755 my $startTime = Time::HiRes::time;
1756 my ($msg, $msg_hash, $session_id) = @_;
1757 my $header = @{$msg_hash->{'header'}}[0];
1758 my $source = @{$msg_hash->{'source'}}[0];
1759 my $target = @{$msg_hash->{'target'}}[0];
1760 my $hostId;
1761 my $licensePoolId;
1763 # Check input sanity
1764 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1765 $hostId = @{$msg_hash->{'hostId'}}[0];
1766 } else {
1767 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1768 }
1769 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1770 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1771 } else {
1772 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1773 }
1775 # Unassign a software license from a host
1776 my $callobj = {
1777 method => 'deleteSoftwareLicenseUsage',
1778 params => [ $hostId, '', $licensePoolId ],
1779 id => 1,
1780 };
1781 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1783 # Check Opsi error
1784 my ($res_error, $res_error_str) = &check_opsi_res($res);
1785 if ($res_error){
1786 # Create error message
1787 &main::daemon_log("$session_id ERROR: cannot unassign a software license from a host at Opsi server: ".$res_error_str, 1);
1788 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1789 return ( &create_xml_string($out_hash) );
1790 }
1792 # Create function result message
1793 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1794 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1796 my $endTime = Time::HiRes::time;
1797 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1798 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1799 return ( &create_xml_string($out_hash) );
1800 }
1802 ################################
1803 # @brief Unassign all software licenses from a host
1804 # @param hostid Something like client_1.intranet.mydomain.de
1805 sub opsi_unassignAllSoftwareLicensesFromHost {
1806 my $startTime = Time::HiRes::time;
1807 my ($msg, $msg_hash, $session_id) = @_;
1808 my $header = @{$msg_hash->{'header'}}[0];
1809 my $source = @{$msg_hash->{'source'}}[0];
1810 my $target = @{$msg_hash->{'target'}}[0];
1811 my $hostId;
1813 # Check input sanity
1814 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
1815 $hostId = @{$msg_hash->{'hostId'}}[0];
1816 } else {
1817 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1818 }
1820 # Unassign all software licenses from a host
1821 my $callobj = {
1822 method => 'deleteAllSoftwareLicenseUsages',
1823 params => [ $hostId ],
1824 id => 1,
1825 };
1826 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1828 # Check Opsi error
1829 my ($res_error, $res_error_str) = &check_opsi_res($res);
1830 if ($res_error){
1831 # Create error message
1832 &main::daemon_log("$session_id ERROR: cannot unassign a software license from a host at Opsi server: ".$res_error_str, 1);
1833 my $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1834 return ( &create_xml_string($out_hash) );
1835 }
1837 # Create function result message
1838 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1839 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1841 my $endTime = Time::HiRes::time;
1842 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
1843 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
1844 return ( &create_xml_string($out_hash) );
1845 }
1848 ################################
1849 # @brief Returns the assigned licensePoolId and licenses, how often the product is installed and at which host
1850 # and the number of max and remaining installations for a given OPSI product.
1851 # @param productId Identificator of an OPSI product.
1852 sub opsi_getLicenseInformationForProduct {
1853 my $startTime = Time::HiRes::time;
1854 my ($msg, $msg_hash, $session_id) = @_;
1855 my $header = @{$msg_hash->{'header'}}[0];
1856 my $source = @{$msg_hash->{'source'}}[0];
1857 my $productId;
1858 my $out_hash;
1860 # Check input sanity
1861 if (&_check_xml_tag_is_ok ($msg_hash, 'productId')) {
1862 $productId = @{$msg_hash->{'productId'}}[0];
1863 } else {
1864 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1865 }
1867 # Fetch infos from Opsi server
1868 my $callobj = {
1869 method => 'getLicensePoolId',
1870 params => [ $productId ],
1871 id => 1,
1872 };
1873 #my $res = $main::opsi_client->call($main::opsi_url, $callobj);
1874 my $res = $opsi_client->call($opsi_url, $callobj);
1876 # Check Opsi error
1877 my ($res_error, $res_error_str) = &check_opsi_res($res);
1878 if ($res_error){
1879 return &_giveErrorFeedback($msg_hash, "cannot get license pool for product '$productId' : ".$res_error_str, $session_id);
1880 }
1882 my $licensePoolId = $res->result;
1884 # Fetch statistic information for given pool ID
1885 $callobj = {
1886 method => 'getLicenseStatistics_hash',
1887 params => [ ],
1888 id => 1,
1889 };
1890 $res = $opsi_client->call($opsi_url, $callobj);
1892 # Check Opsi error
1893 ($res_error, $res_error_str) = &check_opsi_res($res);
1894 if ($res_error){
1895 # Create error message
1896 &main::daemon_log("$session_id ERROR: cannot get statistic informations for license pools : ".$res_error_str, 1);
1897 $out_hash = &main::create_xml_hash("error_$header", $main::server_address, $source, $res_error_str);
1898 return ( &create_xml_string($out_hash) );
1899 }
1901 # Create function result message
1902 $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1903 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1904 &add_content2xml_hash($out_hash, "licensePoolId", $licensePoolId);
1905 &add_content2xml_hash($out_hash, "licenses", $res->result->{$licensePoolId}->{'licenses'});
1906 &add_content2xml_hash($out_hash, "usageCount", $res->result->{$licensePoolId}->{'usageCount'});
1907 &add_content2xml_hash($out_hash, "maxInstallations", $res->result->{$licensePoolId}->{'maxInstallations'});
1908 &add_content2xml_hash($out_hash, "remainingInstallations", $res->result->{$licensePoolId}->{'remainingInstallations'});
1909 map(&add_content2xml_hash($out_hash, "usedBy", "$_"), @{ $res->result->{$licensePoolId}->{'usedBy'}});
1911 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
1912 return ( &create_xml_string($out_hash) );
1913 }
1916 ################################
1917 # @brief Returns licensePoolId, description, a list of productIds, al list of windowsSoftwareIds and a list of licenses for a given licensePoolId.
1918 # Each license contains softwareLicenseId, maxInstallations, licenseType, licensePoolIds, licenseKeys, hostIds, expirationDate, boundToHost and licenseContractId.
1919 # The licenseContract contains conclusionDate, expirationDate, notes, notificationDate and partner.
1920 # @param licensePoolId The name of the pool.
1921 sub opsi_getPool {
1922 my $startTime = Time::HiRes::time;
1923 my ($msg, $msg_hash, $session_id) = @_;
1924 my $header = @{$msg_hash->{'header'}}[0];
1925 my $source = @{$msg_hash->{'source'}}[0];
1927 # Check input sanity
1928 my $licensePoolId;
1929 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
1930 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
1931 } else {
1932 return &_giveErrorFeedback($msg_hash, $_, $session_id);
1933 }
1935 # Create hash for the answer
1936 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
1937 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
1939 # Call Opsi
1940 my ($res, $err) = &_getLicensePool_hash( 'licensePoolId'=> $licensePoolId );
1941 if ($err){
1942 return &_giveErrorFeedback($msg_hash, "cannot get license pool from Opsi server: ".$res, $session_id);
1943 }
1944 # Add data to outgoing hash
1945 &add_content2xml_hash($out_hash, "licensePoolId", $res->{'licensePoolId'});
1946 &add_content2xml_hash($out_hash, "description", $res->{'description'});
1947 map(&add_content2xml_hash($out_hash, "productIds", "$_"), @{ $res->{'productIds'} });
1948 map(&add_content2xml_hash($out_hash, "windowsSoftwareIds", "$_"), @{ $res->{'windowsSoftwareIds'} });
1951 # Call Opsi two times
1952 my ($usages_res, $usages_err) = &_getSoftwareLicenseUsages_listOfHashes('licensePoolId'=>$licensePoolId);
1953 if ($usages_err){
1954 return &_giveErrorFeedback($msg_hash, "cannot get software license usage information from Opsi server: ".$usages_res, $session_id);
1955 }
1956 my ($licenses_res, $licenses_err) = &_getSoftwareLicenses_listOfHashes();
1957 if ($licenses_err){
1958 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server: ".$licenses_res, $session_id);
1959 }
1961 # Add data to outgoing hash
1962 # Parse through all software licenses and select those associated to the pool
1963 my $res_hash = { 'hit'=> [] };
1964 foreach my $license ( @$licenses_res) {
1965 # Each license hash has a list of licensePoolIds so go through this list and search for matching licensePoolIds
1966 my $found = 0;
1967 my @licensePoolIds_list = @{$license->{licensePoolIds}};
1968 foreach my $lPI ( @licensePoolIds_list) {
1969 if ($lPI eq $licensePoolId) { $found++ }
1970 }
1971 if (not $found ) { next; };
1972 # Found matching licensePoolId
1973 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
1974 'licenseKeys' => {},
1975 'expirationDate' => [$license->{'expirationDate'}],
1976 'boundToHost' => [$license->{'boundToHost'}],
1977 'maxInstallations' => [$license->{'maxInstallations'}],
1978 'licenseType' => [$license->{'licenseType'}],
1979 'licenseContractId' => [$license->{'licenseContractId'}],
1980 'licensePoolIds' => [],
1981 'hostIds' => [],
1982 };
1983 foreach my $licensePoolId (@{ $license->{'licensePoolIds'}}) {
1984 push( @{$license_hash->{'licensePoolIds'}}, $licensePoolId);
1985 $license_hash->{licenseKeys}->{$licensePoolId} = [ $license->{'licenseKeys'}->{$licensePoolId} ];
1986 }
1987 foreach my $usage (@$usages_res) {
1988 # Search for hostIds with matching softwareLicenseId
1989 if ($license->{'softwareLicenseId'} eq $usage->{'softwareLicenseId'}) {
1990 push( @{ $license_hash->{hostIds}}, $usage->{hostId});
1991 }
1992 }
1994 # Each softwareLicenseId has one licenseContractId, fetch contract details for each licenseContractId
1995 my ($lContract_res, $lContract_err) = &_getLicenseContract_hash('licenseContractId'=>$license->{licenseContractId});
1996 if ($lContract_err){
1997 return &_giveErrorFeedback($msg_hash, "cannot get software license contract information from Opsi server: ".$licenses_res, $session_id);
1998 }
1999 $license_hash->{$license->{'licenseContractId'}} = [];
2000 my $licenseContract_hash = { 'conclusionDate' => [$lContract_res->{conclusionDate}],
2001 'notificationDate' => [$lContract_res->{notificationDate}],
2002 'notes' => [$lContract_res->{notes}],
2003 'exirationDate' => [$lContract_res->{expirationDate}],
2004 'partner' => [$lContract_res->{partner}],
2005 };
2006 push( @{$license_hash->{licenseContractData}}, $licenseContract_hash );
2008 push( @{$res_hash->{hit}}, $license_hash );
2009 }
2010 $out_hash->{licenses} = [$res_hash];
2012 my $endTime = Time::HiRes::time;
2013 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2014 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2015 return ( &create_xml_string($out_hash) );
2016 }
2019 ################################
2020 # @brief Removes at first the software license from license pool and than deletes the software license.
2021 # Attention, the software license has to exists otherwise it will lead to an Opsi internal server error.
2022 # @param softwareLicenseId Identificator of a license.
2023 # @param licensePoolId The name of the pool.
2024 sub opsi_removeLicense {
2025 my $startTime = Time::HiRes::time;
2026 my ($msg, $msg_hash, $session_id) = @_;
2027 my $header = @{$msg_hash->{'header'}}[0];
2028 my $source = @{$msg_hash->{'source'}}[0];
2030 # Check input sanity
2031 my $softwareLicenseId;
2032 if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
2033 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
2034 } else {
2035 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2036 }
2037 my $licensePoolId;
2038 if (&_check_xml_tag_is_ok ($msg_hash, 'licensePoolId')) {
2039 $licensePoolId = @{$msg_hash->{'licensePoolId'}}[0];
2040 } else {
2041 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2042 }
2044 # Call Opsi
2045 my ($res, $err) = &_removeSoftwareLicenseFromLicensePool( 'licensePoolId' => $licensePoolId, 'softwareLicenseId' => $softwareLicenseId );
2046 if ($err){
2047 return &_giveErrorFeedback($msg_hash, "cannot delete software license from pool: ".$res, $session_id);
2048 }
2050 # Call Opsi
2051 ($res, $err) = &_deleteSoftwareLicense( 'softwareLicenseId'=>$softwareLicenseId );
2052 if ($err){
2053 return &_giveErrorFeedback($msg_hash, "cannot delete software license from Opsi server: ".$res, $session_id);
2054 }
2056 # Create hash for the answer
2057 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2058 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2059 my $endTime = Time::HiRes::time;
2060 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2061 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2062 return ( &create_xml_string($out_hash) );
2063 }
2066 ################################
2067 # @brief Return softwareLicenseId, maxInstallations, licenseType, licensePoolIds, licenseContractId, expirationDate, boundToHost and a list of productIds.
2068 # @param hostId Something like client_1.intranet.mydomain.de
2069 sub opsi_getReservedLicenses {
2070 my $startTime = Time::HiRes::time;
2071 my ($msg, $msg_hash, $session_id) = @_;
2072 my $header = @{$msg_hash->{'header'}}[0];
2073 my $source = @{$msg_hash->{'source'}}[0];
2075 # Check input sanity
2076 my $hostId;
2077 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
2078 $hostId = @{$msg_hash->{'hostId'}}[0];
2079 } else {
2080 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2081 }
2083 # Fetch informations from Opsi server
2084 my ($license_res, $license_err) = &_getSoftwareLicenses_listOfHashes();
2085 if ($license_err){
2086 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server: ".$license_res, $session_id);
2087 }
2089 # Parse result
2090 my $res_hash = { 'hit'=> [] };
2091 foreach my $license ( @$license_res) {
2092 if ($license->{boundToHost} ne $hostId) { next; }
2094 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
2095 'maxInstallations' => [$license->{'maxInstallations'}],
2096 'boundToHost' => [$license->{'boundToHost'}],
2097 'expirationDate' => [$license->{'expirationDate'}],
2098 'licenseContractId' => [$license->{'licenseContractId'}],
2099 'licenseType' => [$license->{'licenseType'}],
2100 'licensePoolIds' => [],
2101 };
2103 foreach my $licensePoolId (@{$license->{'licensePoolIds'}}) {
2104 # Fetch information for license pools containing a software license which is bound to given host
2105 my ($pool_res, $pool_err) = &_getLicensePool_hash( 'licensePoolId'=>$licensePoolId );
2106 if ($pool_err){
2107 return &_giveErrorFeedback($msg_hash, "cannot get license pool from Opsi server: ".$pool_res, $session_id);
2108 }
2110 # Add licensePool information to result hash
2111 push (@{$license_hash->{licensePoolIds}}, $licensePoolId);
2112 $license_hash->{$licensePoolId} = {'productIds'=>[], 'windowsSoftwareIds'=>[]};
2113 map (push (@{$license_hash->{$licensePoolId}->{productIds}}, $_), @{$pool_res->{productIds}});
2114 map (push (@{$license_hash->{$licensePoolId}->{windowsSoftwareIds}}, $_), @{$pool_res->{windowsSoftwareIds}});
2115 }
2116 push( @{$res_hash->{hit}}, $license_hash );
2117 }
2118 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2119 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2120 $out_hash->{licenses} = [$res_hash];
2122 my $endTime = Time::HiRes::time;
2123 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2124 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2125 return ( &create_xml_string($out_hash) );
2126 }
2128 ################################
2129 # @brief Bound the given softwareLicenseId to the given host.
2130 # @param hostId Opsi hostId
2131 # @param softwareLicenseId Identificator of a license (optional).
2132 sub opsi_boundHostToLicense {
2133 my $startTime = Time::HiRes::time;
2134 my ($msg, $msg_hash, $session_id) = @_;
2135 my $header = @{$msg_hash->{'header'}}[0];
2136 my $source = @{$msg_hash->{'source'}}[0];
2138 # Check input sanity
2139 my $hostId;
2140 if (&_check_xml_tag_is_ok ($msg_hash, 'hostId')) {
2141 $hostId = @{$msg_hash->{'hostId'}}[0];
2142 } else {
2143 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2144 }
2145 my $softwareLicenseId;
2146 if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
2147 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
2148 } else {
2149 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2150 }
2152 # Fetch informations from Opsi server
2153 my ($license_res, $license_err) = &_getSoftwareLicenses_listOfHashes();
2154 if ($license_err){
2155 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server: ".$license_res, $session_id);
2156 }
2158 # Memorize parameter for given softwareLicenseId
2159 my $licenseContractId;
2160 my $licenseType;
2161 my $maxInstallations;
2162 my $boundToHost;
2163 my $expirationDate = "";
2164 my $found;
2165 foreach my $license (@$license_res) {
2166 if ($license->{softwareLicenseId} ne $softwareLicenseId) { next; }
2167 $licenseContractId = $license->{licenseContractId};
2168 $licenseType = $license->{licenseType};
2169 $maxInstallations = $license->{maxInstallations};
2170 $expirationDate = $license->{expirationDate};
2171 $found++;
2172 }
2174 if (not $found) {
2175 return &_giveErrorFeedback($msg_hash, "no softwarelicenseId found with name '".$softwareLicenseId."'", $session_id);
2176 }
2178 # Set boundToHost option for a given software license
2179 my ($bound_res, $bound_err) = &_createSoftwareLicense('softwareLicenseId'=>$softwareLicenseId,
2180 'licenseContractId' => $licenseContractId,
2181 'licenseType' => $licenseType,
2182 'maxInstallations' => $maxInstallations,
2183 'boundToHost' => $hostId,
2184 'expirationDate' => $expirationDate);
2185 if ($bound_err) {
2186 return &_giveErrorFeedback($msg_hash, "cannot set boundToHost for given softwareLicenseId and hostId: ".$bound_res, $session_id);
2187 }
2189 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2190 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2192 my $endTime = Time::HiRes::time;
2193 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2194 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : $elapsedTime seconds", 1034);
2195 return ( &create_xml_string($out_hash) );
2196 }
2198 ################################
2199 # @brief Release a software license formerly bound to a host.
2200 # @param softwareLicenseId Identificator of a license.
2201 sub opsi_unboundHostFromLicense {
2202 # This is really mad! Opsi is not able to unbound a lincense from a host. To provide the functionality for GOsa
2203 # 4 rpc calls to Opsi are necessary. First, fetch all data for the given softwareLicenseId, then all details for the associated
2204 # licenseContractId, then delete the softwareLicense and finally recreate the softwareLicense without the boundToHost option. NASTY!
2205 my $startTime = Time::HiRes::time;
2206 my ($msg, $msg_hash, $session_id) = @_;
2207 my $header = @{$msg_hash->{'header'}}[0];
2208 my $source = @{$msg_hash->{'source'}}[0];
2210 # Check input sanity
2211 my $softwareLicenseId;
2212 if (&_check_xml_tag_is_ok ($msg_hash, 'softwareLicenseId')) {
2213 $softwareLicenseId = @{$msg_hash->{'softwareLicenseId'}}[0];
2214 } else {
2215 return &_giveErrorFeedback($msg_hash, $_, $session_id);
2216 }
2218 # Memorize parameter witch are required for this procedure
2219 my $licenseContractId;
2220 my $licenseType;
2221 my $maxInstallations;
2222 my $expirationDate;
2223 my $partner;
2224 my $conclusionDate;
2225 my $notificationDate;
2226 my $notes;
2227 my $licensePoolId;
2228 my $licenseKey;
2230 # Fetch license informations from Opsi server
2231 my ($license_res, $license_err) = &_getSoftwareLicenses_listOfHashes();
2232 if ($license_err){
2233 return &_giveErrorFeedback($msg_hash, "cannot get software license information from Opsi server, required to unbound license from host: ".$license_res, $session_id);
2234 }
2235 my $found = 0;
2236 foreach my $license (@$license_res) {
2237 if (($found > 0) || ($license->{softwareLicenseId} ne $softwareLicenseId)) { next; }
2238 $licenseContractId = $license->{licenseContractId};
2239 $licenseType = $license->{licenseType};
2240 $maxInstallations = $license->{maxInstallations};
2241 $expirationDate = $license->{expirationDate};
2242 $licensePoolId = @{$license->{licensePoolIds}}[0];
2243 $licenseKey = $license->{licenseKeys}->{$licensePoolId};
2244 $found++;
2245 }
2247 # Fetch contract informations from Opsi server
2248 my ($contract_res, $contract_err) = &_getLicenseContract_hash('licenseContractId'=>$licenseContractId);
2249 if ($contract_err){
2250 return &_giveErrorFeedback($msg_hash, "cannot get contract license information from Opsi server, required to unbound license from host: ".$license_res, $session_id);
2251 }
2252 $partner = $contract_res->{partner};
2253 $conclusionDate = $contract_res->{conclusionDate};
2254 $notificationDate = $contract_res->{notificationDate};
2255 $expirationDate = $contract_res->{expirationDate};
2256 $notes = $contract_res->{notes};
2258 # Delete software license
2259 my ($res, $err) = &_deleteSoftwareLicense( 'softwareLicenseId' => $softwareLicenseId, 'removeFromPools'=> "true" );
2260 if ($err) {
2261 return &_giveErrorFeedback($msg_hash, "cannot delet license from Opsi server, required to unbound license from host : ".$res, $session_id);
2262 }
2264 # Recreate software license without boundToHost
2265 ($res, $err) = &_createLicenseContract( 'licenseContractId' => $licenseContractId, 'partner' => $partner, 'conclusionDate' => $conclusionDate,
2266 'notificationDate' => $notificationDate, 'expirationDate' => $expirationDate, 'notes' => $notes );
2267 if ($err) {
2268 return &_giveErrorFeedback($msg_hash, "cannot create license contract at Opsi server, required to unbound license from host : ".$res, $session_id);
2269 }
2270 ($res, $err) = &_createSoftwareLicense( 'softwareLicenseId' => $softwareLicenseId, 'licenseContractId' => $licenseContractId, 'licenseType' => $licenseType,
2271 'maxInstallations' => $maxInstallations, 'boundToHost' => "", 'expirationDate' => $expirationDate );
2272 if ($err) {
2273 return &_giveErrorFeedback($msg_hash, "cannot create software license at Opsi server, required to unbound license from host : ".$res, $session_id);
2274 }
2275 ($res, $err) = &_addSoftwareLicenseToLicensePool( 'softwareLicenseId' => $softwareLicenseId, 'licensePoolId' => $licensePoolId, 'licenseKey' => $licenseKey );
2276 if ($err) {
2277 return &_giveErrorFeedback($msg_hash, "cannot add software license to license pool at Opsi server, required to unbound license from host : ".$res, $session_id);
2278 }
2280 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2281 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2283 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
2284 return ( &create_xml_string($out_hash) );
2285 }
2287 ################################
2288 # @brief Returns a list of licenses with softwaerLicenseId, maxInstallations, boundToHost, expirationDate, licenseContractId, licenseType, a list of licensePoolIds with associated licenseKeys
2289 sub opsi_getAllSoftwareLicenses {
2290 my $startTime = Time::HiRes::time;
2291 my ($msg, $msg_hash, $session_id) = @_;
2292 my $header = @{$msg_hash->{'header'}}[0];
2293 my $source = @{$msg_hash->{'source'}}[0];
2295 my ($res, $err) = &_getSoftwareLicenses_listOfHashes();
2296 if ($err) {
2297 return &_giveErrorFeedback($msg_hash, "cannot fetch software licenses from Opsi server : ".$res, $session_id);
2298 }
2300 # Parse result
2301 my $res_hash = { 'hit'=> [] };
2302 foreach my $license ( @$res) {
2303 my $license_hash = { 'softwareLicenseId' => [$license->{'softwareLicenseId'}],
2304 'maxInstallations' => [$license->{'maxInstallations'}],
2305 'boundToHost' => [$license->{'boundToHost'}],
2306 'expirationDate' => [$license->{'expirationDate'}],
2307 'licenseContractId' => [$license->{'licenseContractId'}],
2308 'licenseType' => [$license->{'licenseType'}],
2309 'licensePoolIds' => [],
2310 'licenseKeys'=> {}
2311 };
2312 foreach my $licensePoolId (@{$license->{'licensePoolIds'}}) {
2313 push( @{$license_hash->{'licensePoolIds'}}, $licensePoolId);
2314 $license_hash->{licenseKeys}->{$licensePoolId} = [ $license->{'licenseKeys'}->{$licensePoolId} ];
2315 }
2316 push( @{$res_hash->{hit}}, $license_hash );
2317 }
2319 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2320 $out_hash->{licenses} = [$res_hash];
2321 if (exists $msg_hash->{forward_to_gosa}) { &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]); }
2323 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
2324 return ( &create_xml_string($out_hash) );
2325 }
2328 ################################
2329 # @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
2330 # @param hostId Opsi hostId
2331 sub opsi_get_full_product_host_information {
2332 my $startTime = Time::HiRes::time;
2333 my ($msg, $msg_hash, $session_id) = @_;
2334 my $header = @{$msg_hash->{'header'}}[0];
2335 my $source = @{$msg_hash->{'source'}}[0];
2336 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
2337 my $hostId;
2339 my ($res, $err) = &_get_full_product_host_information( hostId=>@{$msg_hash->{'hostId'}}[0]);
2340 if ($err) {
2341 return &_giveErrorFeedback($msg_hash, "cannot fetch full_product_host_information from Opsi server : ".$res, $session_id);
2342 }
2344 # Build return message with twisted target and source
2345 my $out_hash = &main::create_xml_hash("answer_$header", $main::server_address, $source);
2346 if (defined $forward_to_gosa) {
2347 &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
2348 }
2349 &add_content2xml_hash($out_hash, "xxx", "");
2351 # Get hostId if defined
2352 if ((exists $msg_hash->{'hostId'}) && (@{$msg_hash->{'hostId'}} == 1)) {
2353 $hostId = @{$msg_hash->{'hostId'}}[0];
2354 &add_content2xml_hash($out_hash, "hostId", $hostId);
2355 }
2357 # Move to XML string
2358 my $xml_msg= &create_xml_string($out_hash);
2360 # Convert result in something usable
2361 my $replace= "";
2362 foreach my $product ( @$res) {
2364 # Open item
2365 $replace.= "<item>";
2367 # Add flat hash information
2368 my @entries= ( "priority", "onceScript", "licenseRequired", "packageVersion", "productVersion", "advice",
2369 "setupScript", "windowsSoftwareIds", "installationStatus", "pxeConfigTemplate", "name", "type",
2370 "creationTimestamp", "alwaysScript", "productId", "description", "actionRequest", "uninstallScript",
2371 "action", "updateScript", "productClassNames");
2372 foreach my $entry (@entries) {
2373 if (defined $product->{$entry}) {
2374 my $value= $product->{$entry};
2376 if(ref($value) eq 'ARRAY'){
2377 my $tmp= "";
2378 foreach my $element (@$value) {
2379 $tmp.= "<element>$element</element>";
2380 }
2381 $replace.= "<$entry>$tmp</$entry>";
2382 } else {
2383 $replace.= "<$entry>$value</$entry>";
2384 }
2385 }
2386 }
2388 # Add property information
2389 if (defined $product->{'properties'}) {
2390 $replace.= "<properties>";
2391 while ((my $key, my $value) = each(%{$product->{'properties'}})){
2392 $replace.= "<$key>";
2394 while ((my $pkey, my $pvalue) = each(%$value)){
2395 if(ref($pvalue) eq 'ARRAY'){
2396 my $tmp= "";
2397 foreach my $element (@$pvalue) {
2398 $tmp.= "<element>$element</element>";
2399 }
2400 $replace.= "<$pkey>$tmp</$pkey>";
2401 } else {
2402 $replace.= "<$pkey>$pvalue</$pkey>";
2403 }
2404 }
2405 $replace.= "</$key>";
2406 }
2407 $replace.= "</properties>";
2408 }
2410 # Close item
2411 $replace.= "</item>";
2412 }
2414 $xml_msg=~ s/<xxx><\/xxx>/\n$replace/;
2416 &main::daemon_log("0 DEBUG: time to process gosa-si message '$header' : ".sprintf("%.4f", (Time::HiRes::time - $startTime))." seconds", 1034);
2417 return ( $xml_msg );
2418 }
2421 sub opsi_test {
2422 my ($msg, $msg_hash, $session_id) = @_;
2423 my $header = @{$msg_hash->{'header'}}[0];
2424 my $source = @{$msg_hash->{'source'}}[0];
2425 my $pram1 = @{$msg_hash->{'productId'}}[0];
2428 # Fetch infos from Opsi server
2429 my $callobj = {
2430 method => 'getLicensePoolId',
2431 params => [ $pram1 ],
2432 id => 1,
2433 };
2434 my $res = $main::opsi_client->call($main::opsi_url, $callobj);
2436 return ();
2437 }
2440 # ----------------------------------------------------------------------------
2441 # internal methods handling the comunication with Opsi
2442 # ----------------------------------------------------------------------------
2444 ################################
2445 # @brief Checks if there is a specified tag and if the the tag has a content.
2446 sub _check_xml_tag_is_ok {
2447 my ($msg_hash,$tag) = @_;
2448 if (not defined $msg_hash->{$tag}) {
2449 $_ = "message contains no tag '$tag'";
2450 return 0;
2451 }
2452 if (ref @{$msg_hash->{$tag}}[0] eq 'HASH') {
2453 $_ = "message tag '$tag' has no content";
2454 return 0;
2455 }
2456 return 1;
2457 }
2459 ################################
2460 # @brief Writes the log line and returns the error message for GOsa.
2461 sub _giveErrorFeedback {
2462 my ($msg_hash, $err_string, $session_id) = @_;
2463 &main::daemon_log("$session_id ERROR: $err_string", 1);
2464 my $out_hash = &main::create_xml_hash("error", $main::server_address, @{$msg_hash->{source}}[0], $err_string);
2465 if (exists $msg_hash->{forward_to_gosa}) {
2466 &add_content2xml_hash($out_hash, "forward_to_gosa", @{$msg_hash->{'forward_to_gosa'}}[0]);
2467 }
2468 return ( &create_xml_string($out_hash) );
2469 }
2472 ################################
2473 # @brief Perform the call to the Opsi server and measure the time for the call
2474 sub _callOpsi {
2475 my %arg = ('method'=>undef, 'params'=>[], 'id'=>1, @_);
2477 my $callObject = {
2478 method => $arg{method},
2479 params => $arg{params},
2480 id => $arg{id},
2481 };
2483 my $startTime = Time::HiRes::time;
2484 my $opsiResult = $opsi_client->call($opsi_url, $callObject);
2485 my $endTime = Time::HiRes::time;
2486 my $elapsedTime = sprintf("%.4f", ($endTime - $startTime));
2488 &main::daemon_log("0 DEBUG: time to process opsi call '$arg{method}' : $elapsedTime seconds", 1034);
2490 return $opsiResult;
2491 }
2493 sub _getLicensePool_hash {
2494 my %arg = ( 'licensePoolId' => undef, @_ );
2496 if (not defined $arg{licensePoolId} ) {
2497 return ("function requires licensePoolId as parameter", 1);
2498 }
2500 my $res = &_callOpsi( method => 'getLicensePool_hash', params =>[$arg{licensePoolId}], id => 1 );
2501 my ($res_error, $res_error_str) = &check_opsi_res($res);
2502 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2504 return ($res->result, 0);
2505 }
2507 sub _getSoftwareLicenses_listOfHashes {
2509 my $res = &_callOpsi( method => 'getSoftwareLicenses_listOfHashes' );
2510 my ($res_error, $res_error_str) = &check_opsi_res($res);
2511 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2513 return ($res->result, 0);
2514 }
2516 sub _getSoftwareLicenseUsages_listOfHashes {
2517 my %arg = ( 'hostId' => "", 'licensePoolId' => "", @_ );
2519 my $res = &_callOpsi( method=>'getSoftwareLicenseUsages_listOfHashes', params=>[ $arg{hostId}, $arg{licensePoolId} ] );
2520 my ($res_error, $res_error_str) = &check_opsi_res($res);
2521 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2523 return ($res->result, 0);
2524 }
2526 sub _removeSoftwareLicenseFromLicensePool {
2527 my %arg = ( 'softwareLicenseId' => undef, 'licensePoolId' => undef, @_ );
2529 if (not defined $arg{softwareLicenseId} ) {
2530 return ("function requires softwareLicenseId as parameter", 1);
2531 }
2532 if (not defined $arg{licensePoolId} ) {
2533 return ("function requires licensePoolId as parameter", 1);
2534 }
2536 my $res = &_callOpsi( method=>'removeSoftwareLicenseFromLicensePool', params=>[ $arg{softwareLicenseId}, $arg{licensePoolId} ] );
2537 my ($res_error, $res_error_str) = &check_opsi_res($res);
2538 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2540 return ($res->result, 0);
2541 }
2543 sub _deleteSoftwareLicense {
2544 my %arg = ( 'softwareLicenseId' => undef, 'removeFromPools' => "false", @_ );
2546 if (not defined $arg{softwareLicenseId} ) {
2547 return ("function requires softwareLicenseId as parameter", 1);
2548 }
2549 my $removeFromPools = "";
2550 if ((defined $arg{removeFromPools}) && ($arg{removeFromPools} eq "true")) {
2551 $removeFromPools = "removeFromPools";
2552 }
2554 my $res = &_callOpsi( method=>'deleteSoftwareLicense', params=>[ $arg{softwareLicenseId}, $removeFromPools ] );
2555 my ($res_error, $res_error_str) = &check_opsi_res($res);
2556 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2558 return ($res->result, 0);
2559 }
2561 sub _getLicensePoolId {
2562 my %arg = ( 'productId' => undef, @_ );
2564 if (not defined $arg{productId} ) {
2565 return ("function requires productId as parameter", 1);
2566 }
2568 my $res = &_callOpsi( method => 'getLicensePoolId', params => [ $arg{productId} ] );
2569 my ($res_error, $res_error_str) = &check_opsi_res($res);
2570 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2572 return ($res->result, 0);
2573 }
2575 sub _getLicenseContract_hash {
2576 my %arg = ( 'licenseContractId' => undef, @_ );
2578 if (not defined $arg{licenseContractId} ) {
2579 return ("function requires licenseContractId as parameter", 1);
2580 }
2582 my $res = &_callOpsi( method => 'getLicenseContract_hash', params => [ $arg{licenseContractId} ] );
2583 my ($res_error, $res_error_str) = &check_opsi_res($res);
2584 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2586 return ($res->result, 0);
2587 }
2589 sub _createLicenseContract {
2590 my %arg = (
2591 'licenseContractId' => undef,
2592 'partner' => undef,
2593 'conclusionDate' => undef,
2594 'notificationDate' => undef,
2595 'expirationDate' => undef,
2596 'notes' => undef,
2597 @_ );
2599 my $res = &_callOpsi( method => 'createLicenseContract',
2600 params => [ $arg{licenseContractId}, $arg{partner}, $arg{conclusionDate}, $arg{notificationDate}, $arg{expirationDate}, $arg{notes} ],
2601 );
2602 my ($res_error, $res_error_str) = &check_opsi_res($res);
2603 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2605 return ($res->result, 0);
2606 }
2608 sub _createSoftwareLicense {
2609 my %arg = (
2610 'softwareLicenseId' => undef,
2611 'licenseContractId' => undef,
2612 'licenseType' => undef,
2613 'maxInstallations' => undef,
2614 'boundToHost' => undef,
2615 'expirationDate' => undef,
2616 @_ );
2618 my $res = &_callOpsi( method => 'createSoftwareLicense',
2619 params => [ $arg{softwareLicenseId}, $arg{licenseContractId}, $arg{licenseType}, $arg{maxInstallations}, $arg{boundToHost}, $arg{expirationDate} ],
2620 );
2621 my ($res_error, $res_error_str) = &check_opsi_res($res);
2622 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2624 return ($res->result, 0);
2625 }
2627 sub _addSoftwareLicenseToLicensePool {
2628 my %arg = (
2629 'softwareLicenseId' => undef,
2630 'licensePoolId' => undef,
2631 'licenseKey' => undef,
2632 @_ );
2634 if (not defined $arg{softwareLicenseId} ) {
2635 return ("function requires softwareLicenseId as parameter", 1);
2636 }
2637 if (not defined $arg{licensePoolId} ) {
2638 return ("function requires licensePoolId as parameter", 1);
2639 }
2641 my $res = &_callOpsi( method => 'addSoftwareLicenseToLicensePool', params => [ $arg{softwareLicenseId}, $arg{licensePoolId}, $arg{licenseKey} ] );
2642 my ($res_error, $res_error_str) = &check_opsi_res($res);
2643 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2645 return ($res->result, 0);
2646 }
2648 sub _getProductStates_hash {
2649 my %arg = ( 'hostId' => undef, @_ );
2651 if (not defined $arg{hostId} ) {
2652 return ("function requires hostId as parameter", 1);
2653 }
2655 my $res = &_callOpsi( method => 'getProductStates_hash', params => [$arg{hostId}]);
2656 my ($res_error, $res_error_str) = &check_opsi_res($res);
2657 if ($res_error){ return ( (caller(0))[3]." : ".$res_error_str, 1 ); }
2659 return ($res->result, 0);
2660 }
2662 sub _get_full_product_host_information {
2663 my %arg = ( 'hostId' => undef, @_ );
2665 if (not defined $arg{hostId}) {
2666 return ("function requires hostId as parameter", 1);
2667 }
2669 my $res = &_callOpsi( method => 'getFullProductHostInformation_list', params => [$arg{hostId}]);
2670 my ($res_error, $res_error_str) = &check_opsi_res($res);
2671 if ($res_error){ return ((caller(0))[3]." : ".$res_error_str, 1); }
2673 return ($res->result, 0);
2674 }
2676 1;