Code

update: opsi server integration
authorrettenbe <rettenbe@594d385d-05f5-0310-b6e9-bd551577e9d8>
Tue, 5 Aug 2008 08:59:26 +0000 (08:59 +0000)
committerrettenbe <rettenbe@594d385d-05f5-0310-b6e9-bd551577e9d8>
Tue, 5 Aug 2008 08:59:26 +0000 (08:59 +0000)
git-svn-id: https://oss.gonicus.de/repositories/gosa/trunk@12147 594d385d-05f5-0310-b6e9-bd551577e9d8

gosa-si/gosa-si-server
gosa-si/server/events/opsi_com.pm

index e273e9e0c04ef50dc78e664131fba949c20a25f2..ba12f2b97eb5cb673db23ee2826ed06d947f7ec2 100755 (executable)
@@ -88,6 +88,7 @@ our (%cfg_defaults, $log_file, $pid_file,
     $foreign_server_string, $server_domain, $ServerPackages_key, $foreign_servers_register_delay,
     $wake_on_lan_passwd, $job_synchronization, $modified_jobs_loop_delay,
     $arp_enabled, $arp_interface,
+    $opsi_enabled, $opsi_server, $opsi_admin, $opsi_password,
 );
 
 # additional variable which should be globaly accessable
@@ -205,7 +206,10 @@ my $max_children = 2;
 
 
 # loop delay for job queue to look for opsi jobs
-my $job_queue_opsi_delay = 2;
+my $job_queue_opsi_delay = 10;
+our $opsi_client;
+our $opsi_url;
 
 
 %cfg_defaults = (
@@ -256,6 +260,12 @@ my $job_queue_opsi_delay = 2;
     "enabled"   => [\$arp_enabled, "true"],
     "interface" => [\$arp_interface, "all"],
        },
+"Opsi" => {
+    "enabled"  => [\$opsi_enabled, "false"], 
+    "server"   => [\$opsi_server, "localhost"],
+    "admin"    => [\$opsi_admin, "opsi-admin"],
+    "password" => [\$opsi_password, "secret"],
+   },
 
 );
 
@@ -302,7 +312,7 @@ sub daemon_log {
             return 
         }
         chomp($msg);
-        $msg =~s/\n//g;   # no newlines are allowed in log messages, this is important for later log parsing
+        #$msg =~s/\n//g;   # no newlines are allowed in log messages, this is important for later log parsing
         if($level <= $verbose){
             my ($seconds, $minutes, $hours, $monthday, $month,
                     $year, $weekday, $yearday, $sommertime) = localtime(time);
@@ -1445,13 +1455,31 @@ sub session_start {
        $kernel->delay_set('watch_for_new_jobs', $job_queue_loop_delay);
        $kernel->delay_set('watch_for_done_jobs', $job_queue_loop_delay); 
     $kernel->delay_set('watch_for_modified_jobs', $modified_jobs_loop_delay); 
-    $kernel->delay_set('watch_for_opsi_jobs', $job_queue_opsi_delay); 
        $kernel->delay_set('watch_for_new_messages', $messaging_db_loop_delay);
     $kernel->delay_set('watch_for_delivery_messages', $messaging_db_loop_delay);
        $kernel->delay_set('watch_for_done_messages', $messaging_db_loop_delay);
     $kernel->delay_set('watch_for_old_known_clients', $job_queue_loop_delay);
 
+    # Start opsi check
+    if ($opsi_enabled eq "true") {
+        $kernel->delay_set('watch_for_opsi_jobs', $job_queue_opsi_delay); 
+    }
+
+}
+
 
+sub check_opsi_res {
+    my $res= shift;
+    if($res) {
+        if ($res->is_error) {
+            &main::daemon_log("ERROR: opsi configed communication failed: ".$res->error_message, 1);
+        } else {
+            return 1;
+        }
+    } else {
+        &main::daemon_log("ERROR: opsi configed communication failed: ".$opsi_client->status_line, 1);
+    }
+    return 0;
 }
 
 
@@ -1473,7 +1501,7 @@ sub watch_for_done_jobs {
 
 
 sub watch_for_opsi_jobs {
-    my ($kernel) = @_[KERNEL];
+    my ($kernel) = $_[KERNEL];
 
     my $sql_statement = "SELECT * FROM ".$job_queue_tn." WHERE ((headertag='opsi_install_client') AND (status='processing'))";
        my $res = $job_db->select_dbentry( $sql_statement );
@@ -1482,53 +1510,56 @@ sub watch_for_opsi_jobs {
 
         # Ask OPSI for an update of the running jobs
         my $hostId = $hit->{'plainname'};
-        print STDERR "\n\n$hostId\n";
-#        my $result= {};
-#        
-#        # For hosts, only return the products that are or get installed
-#        my $callobj;
-#        $callobj = {
-#            method  => 'getProductStates_hash',
-#            params  => [ $hostId ],
-#            id  => 1,
-#        };
-#        
-#        my $hres = $client->call($opsi_url, $callobj);
-#        if (check_res($hres)){
-#            my $htmp= $hres->result->{$hostId};
-#        
-#        # check state != not_installed or action == setup -> load and add
-#            my $products= 0;
-#            my $installed= 0;
-#            my $error= 0;
-#            foreach my $product (@{$htmp}){
-#        
-#                if ($product->{'installationStatus'} ne "not_installed" or
-#                        $product->{'actionRequest'} eq "setup"){
-#        
-#        # Increase number of products for this host
-#                    $products++;
-#        
-#                    if ($product->{'installationStatus'} eq "failed"){
-#                        $result->{$product->{'productId'}}= "error";
-#                        $error++;
-#                    }
-#                    if ($product->{'installationStatus'} eq "installed"){
-#                        $result->{$product->{'productId'}}= "installed";
-#                        $installed++;
-#                    }
-#                    if ($product->{'installationStatus'} eq "installing"){
-#                        $result->{$product->{'productId'}}= "installing";
-#                    }
-#                }
-#            }
-#        
-#        # Estimate "rough" progress
-#            $result->{'progress'}= int($installed * 100 / $products);
-#}
-#
-#return $result;
-#
+print STDERR "\n\n$hostId\n";
+        my $result= {};
+        
+        # For hosts, only return the products that are or get installed
+        my $callobj;
+        $callobj = {
+            method  => 'getProductStates_hash',
+            params  => [ $hostId ],
+            id  => 1,
+        };
+        
+        my $hres = $opsi_client->call($opsi_url, $callobj);
+        if (&check_opsi_res($hres)){
+            my $htmp= $hres->result->{$hostId};
+        
+        # check state != not_installed or action == setup -> load and add
+            my $products= 0;
+            my $installed= 0;
+            my $error= 0;
+            foreach my $product (@{$htmp}){
+
+                if ($product->{'installationStatus'} ne "not_installed" or
+                        $product->{'actionRequest'} eq "setup"){
+
+        # Increase number of products for this host
+                    $products++;
+        
+                    if ($product->{'installationStatus'} eq "failed"){
+                        $result->{$product->{'productId'}}= "error";
+                        $error++;
+                    }
+                    if ($product->{'installationStatus'} eq "installed"){
+                        $result->{$product->{'productId'}}= "installed";
+                        $installed++;
+                    }
+                    if ($product->{'installationStatus'} eq "installing"){
+                        $result->{$product->{'productId'}}= "installing";
+                    }
+                }
+            }
+        
+        # Estimate "rough" progress
+            $result->{'progress'}= int($installed * 100 / $products);
+        }
+
+        #return $result;
+print STDERR Dumper($result);        
+    
+        # Set updates to job queue
+
     }
 
     $kernel->delay_set('watch_for_opsi_jobs', $job_queue_opsi_delay);
@@ -3074,11 +3105,20 @@ foreach my $foreign_server (@foreign_server_list) {
 }
 
 
-# import all modules
+# Import all modules
 &import_modules;
-# check wether all modules are gosa-si valid passwd check
+
+# Check wether all modules are gosa-si valid passwd check
 &password_check;
 
+# Prepare for using Opsi 
+if ($opsi_enabled eq "true") {
+    use JSON::RPC::Client;
+    use XML::Quote qw(:all);
+    $opsi_url= "https://".$opsi_admin.":".$opsi_password."@".$opsi_server.":4447/rpc";
+    $opsi_client = new JSON::RPC::Client;
+}
+
 
 POE::Component::Server::TCP->new(
     Alias => "TCP_SERVER",
index ce1c1ed818be2f90f8ac044f254cedd30a90777a..5b934ccfc1b45941c2b91bdb46c30f9a2b1700bd 100644 (file)
@@ -9,11 +9,16 @@ use Exporter;
 my @events = (
     "get_events",
     "opsi_install_client",
-#    "opsi_get_netboot_products",
-#    "opsi_get_local_products",
-#    "opsi_get_product_properties",
-#    "opsi_get_client_hardware",
-#    "opsi_get_client_software",
+    #"opsi_get_netboot_products",  
+    #"opsi_get_local_products",
+    #"opsi_get_client_hardware",
+    #"opsi_get_client_software",
+    #"opsi_get_product_properties",
+    #"opsi_set_product_properties",
+    #"opsi_list_clients",
+    #"opsi_del_client",
+    #"opsi_install_client",
+
    );
 @EXPORT = @events;
 
@@ -36,8 +41,8 @@ sub get_events {
 
     
 ## @method opsi_install_client
-# 
-# @param msg - STRING - xml message with tags 
+# A new windows installing job is created at job_queue_db.
+# @param msg - STRING - xml message with tags macaddress and hostId
 # @param msg_hash - HASHREF - message information parsed into a hash
 # @param session_id - INTEGER - POE session id of the processing of this message
 sub opsi_install_client {
@@ -112,7 +117,7 @@ sub opsi_install_client {
             xmlmessage=>$msg,
             macaddress=>$macaddress,
             plainname=>$plain_name,
-            siserver=>"windowsOpsi",
+            siserver=>"localhost",
             modified=>"1",
         };
         my $res = $main::job_db->add_dbentry($insert_dic);
@@ -128,45 +133,748 @@ sub opsi_install_client {
 }
 
 
+## @method opsi_get_netboot_products
+# ???
+# @param msg - STRING - xml message with tag hostId
+# @param msg_hash - HASHREF - message information parsed into a hash
+# @param session_id - INTEGER - POE session id of the processing of this message
+sub opsi_get_netboot_products {
+  my ($msg, $msg_hash, $session_id) = @_;
+  my $header = @{$msg_hash->{'header'}}[0];
+  my $source = @{$msg_hash->{'source'}}[0];
+  my $target = @{$msg_hash->{'target'}}[0];
+  my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
+  my $hostId;
 
+  # build return message with twisted target and source
+  my $out_hash = &main::create_xml_hash("answer_$header", $target, $source);
+  #&add_content2xml_hash($out_hash, "session_id", $session_id);   ### possibly not needed, to be checked
+  if (defined $forward_to_gosa) {
+    &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
+  }
 
-#sub opsi_get_netboot_products {
-#        my ($msg, $msg_hash, $session_id) = @_;
-#        $msg =~ s/gosa_opsi/opsi/g;
-#        return ( $msg );
-#}
+  # Get hostID if defined
+  if (defined @{$msg_hash->{'hostId'}}[0]){
+    $hostId = @{$msg_hash->{'hostId'}}[0];
+    &add_content2xml_hash($out_hash, "hostId", $hostId);
+  }
+
+  &add_content2xml_hash($out_hash, "xxx", "");
+  my $xml_msg= &create_xml_string($out_hash);
+
+  # For hosts, only return the products that are or get installed
+  my $callobj;
+  $callobj = {
+    method  => 'getNetBootProductIds_list',
+    params  => [ ],
+    id  => 1,
+  };
+
+  my $res = $main::opsi_client->call($main::opsi_url, $callobj);
+  my %r = ();
+  for (@{$res->result}) { $r{$_} = 1 }
+
+  if (check_res($res)){
+
+    if (defined $hostId){
+      $callobj = {
+        method  => 'getProductStates_hash',
+        params  => [ $hostId ],
+        id  => 1,
+      };
+
+      my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
+      if (check_res($hres)){
+        my $htmp= $hres->result->{$hostId};
+
+        # check state != not_installed or action == setup -> load and add
+        foreach my $product (@{$htmp}){
+
+          if (!defined ($r{$product->{'productId'}})){
+            next;
+          }
+
+          # Now we've a couple of hashes...
+          if ($product->{'installationStatus'} ne "not_installed" or
+              $product->{'actionRequest'} eq "setup"){
+            my $state= "<state>".$product->{'installationStatus'}."</state><action>".$product->{'actionRequest'}."</action>";
+
+            $callobj = {
+              method  => 'getProduct_hash',
+              params  => [ $product->{'productId'} ],
+              id  => 1,
+            };
+
+            my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
+            if (check_res($sres)){
+              my $tres= $sres->result;
+
+              my $name= xml_quote($tres->{'name'});
+              my $r= $product->{'productId'};
+              my $description= xml_quote($tres->{'description'});
+              $name=~ s/\//\\\//;
+              $description=~ s/\//\\\//;
+              $xml_msg=~ s/<xxx><\/xxx>/<item><ProductId>$r<\/ProductId><name><\/name><description>$description<\/description><\/item>$state<xxx><\/xxx>/;
+            }
+
+          }
+        }
+
+      }
+
+    } else {
+      foreach my $r (@{$res->result}) {
+        $callobj = {
+          method  => 'getProduct_hash',
+          params  => [ $r ],
+          id  => 1,
+        };
+
+        my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
+        if (check_res($sres)){
+          my $tres= $sres->result;
+
+          my $name= xml_quote($tres->{'name'});
+          my $description= xml_quote($tres->{'description'});
+          $name=~ s/\//\\\//;
+          $description=~ s/\//\\\//;
+          $xml_msg=~ s/<xxx><\/xxx>/<item><ProductId>$r<\/ProductId><name><\/name><description>$description<\/description><\/item><xxx><\/xxx>/;
+        }
+
+      }
+
+    }
+  }
+
+  $xml_msg=~ s/<xxx><\/xxx>//;
+
+  return ($xml_msg);
+}
+
+
+## @method opsi_get_product_properties
+# ???
+# @param msg - STRING - xml message with tags ProductId and hostId
+# @param msg_hash - HASHREF - message information parsed into a hash
+# @param session_id - INTEGER - POE session id of the processing of this message
+sub opsi_get_product_properties {
+    my ($msg, $msg_hash, $session_id) = @_;
+    my $header = @{$msg_hash->{'header'}}[0];
+    my $source = @{$msg_hash->{'source'}}[0];
+    my $target = @{$msg_hash->{'target'}}[0];
+    my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
+    my $productId = @{$msg_hash->{'ProductId'}}[0];
+    my $hostId;
+
+    # build return message with twisted target and source
+    my $out_hash = &main::create_xml_hash("answer_$header", $target, $source);
+    &add_content2xml_hash($out_hash, "session_id", $session_id);
+
+    # Get hostID if defined
+    if (defined @{$msg_hash->{'hostId'}}[0]){
+      $hostId = @{$msg_hash->{'hostId'}}[0];
+      &add_content2xml_hash($out_hash, "hostId", $hostId);
+    }
+
+    if (defined $forward_to_gosa) {
+      &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
+    }
+    &add_content2xml_hash($out_hash, "ProducId", "$productId");
+
+    # Load actions
+    my $callobj = {
+      method  => 'getPossibleProductActions_list',
+      params  => [ $productId ],
+      id  => 1,
+    };
+    my $res = $main::opsi_client->call($main::opsi_url, $callobj);
+    if (check_res($res)){
+      foreach my $action (@{$res->result}){
+        &add_content2xml_hash($out_hash, "action", $action);
+      }
+    }
+
+    # Add place holder
+    &add_content2xml_hash($out_hash, "xxx", "");
+
+    # Move to XML string
+    my $xml_msg= &create_xml_string($out_hash);
+
+    # JSON Query
+    $callobj = {
+      method  => 'getProductProperties_hash',
+      params  => [ $productId ],
+      id  => 1,
+    };
+
+    $res = $main::opsi_client->call($main::opsi_url, $callobj);
+
+    if (check_res($res)){
+        my $r= $res->result;
+        foreach my $key (keys %{$r}) {
+          my $item= "<item>";
+          my $value= $r->{$key};
+          if (UNIVERSAL::isa( $value, "ARRAY" )){
+            foreach my $subval (@{$value}){
+              $item.= "<$key>".xml_quote($subval)."</$key>";
+            }
+          } else {
+            $item.= "<$key>".xml_quote($value)."</$key>";
+          }
+          $item.= "</item>";
+          $xml_msg=~ s/<xxx><\/xxx>/$item<xxx><\/xxx>/;
+        }
+    }
+
+
+  $xml_msg=~ s/<xxx><\/xxx>//;
+
+  return ($xml_msg);
+}
+
+
+## @method opsi_set_product_properties
+# ???
+# @param msg - STRING - xml message with tags ProductId, hostId, action and state
+# @param msg_hash - HASHREF - message information parsed into a hash
+# @param session_id - INTEGER - POE session id of the processing of this message
+sub opsi_set_product_properties {
+    my ($msg, $msg_hash, $session_id) = @_;
+    my $header = @{$msg_hash->{'header'}}[0];
+    my $source = @{$msg_hash->{'source'}}[0];
+    my $target = @{$msg_hash->{'target'}}[0];
+    my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
+    my $productId = @{$msg_hash->{'ProductId'}}[0];
+    my $hostId;
+
+    # build return message with twisted target and source
+    my $out_hash = &main::create_xml_hash("answer_$header", $target, $source);
+    &add_content2xml_hash($out_hash, "session_id", $session_id);
+    &add_content2xml_hash($out_hash, "ProductId", $productId);
+
+    # Get hostID if defined
+    if (defined @{$msg_hash->{'hostId'}}[0]){
+      $hostId = @{$msg_hash->{'hostId'}}[0];
+      &add_content2xml_hash($out_hash, "hostId", $hostId);
+    }
+
+    # Set product states if requested
+    if (defined @{$msg_hash->{'action'}}[0]){
+      &_set_action($productId, @{$msg_hash->{'action'}}[0], $hostId);
+    }
+    if (defined @{$msg_hash->{'state'}}[0]){
+      &_set_state($productId, @{$msg_hash->{'state'}}[0], $hostId);
+    }
+
+    if (defined $forward_to_gosa) {
+        &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
+    }
+
+    # Find properties
+    foreach my $item (@{$msg_hash->{'item'}}){
+      # JSON Query
+      my $callobj;
+
+      if (defined $hostId){
+        $callobj = {
+          method  => 'setProductProperty',
+          params  => [ $productId, $item->{'name'}[0], $item->{'value'}[0], $hostId ],
+          id  => 1,
+        };
+      } else {
+        $callobj = {
+          method  => 'setProductProperty',
+          params  => [ $productId, $item->{'name'}[0], $item->{'value'}[0] ],
+          id  => 1,
+        };
+      }
+
+      my $res = $main::opsi_client->call($main::opsi_url, $callobj);
+
+      if (!check_res($res)){
+        &main::daemon_log("ERROR: no communication failed while setting '".$item->{'name'}[0]."': ".$res->error_message, 1);
+        &add_content2xml_hash($out_hash, "error", $res->error_message);
+      }
+
+    }
+
+    # return message
+    return ( &create_xml_string($out_hash) );
+}
+
+
+## @method opsi_get_client_hardware
+# ???
+# @param msg - STRING - xml message with tag hostId
+# @param msg_hash - HASHREF - message information parsed into a hash
+# @param session_id - INTEGER - POE session id of the processing of this message
+sub opsi_get_client_hardware {
+    my ($msg, $msg_hash, $session_id) = @_;
+    my $header = @{$msg_hash->{'header'}}[0];
+    my $source = @{$msg_hash->{'source'}}[0];
+    my $target = @{$msg_hash->{'target'}}[0];
+    my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
+    my $hostId = @{$msg_hash->{'hostId'}}[0];
+
+    # build return message with twisted target and source
+    my $out_hash = &main::create_xml_hash("answer_$header", $target, $source);
+    &add_content2xml_hash($out_hash, "session_id", $session_id);
+
+    if (defined $forward_to_gosa) {
+      &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
+    }
+    &add_content2xml_hash($out_hash, "hostId", "$hostId");
+    &add_content2xml_hash($out_hash, "xxx", "");
+    my $xml_msg= &create_xml_string($out_hash);
+
+    # JSON Query
+    my $callobj = {
+      method  => 'getHardwareInformation_hash',
+      params  => [ $hostId ],
+      id  => 1,
+    };
+
+    my $res = $main::opsi_client->call($main::opsi_url, $callobj);
+    if (check_res($res)){
+      my $result= $res->result;
+      foreach my $r (keys %{$result}){
+        my $item= "<item><id>".xml_quote($r)."</id>";
+        my $value= $result->{$r};
+        foreach my $sres (@{$value}){
+
+          foreach my $dres (keys %{$sres}){
+            if (defined $sres->{$dres}){
+              $item.= "<$dres>".xml_quote($sres->{$dres})."</$dres>";
+            }
+          }
+
+        }
+          $item.= "</item>";
+          $xml_msg=~ s%<xxx></xxx>%$item<xxx></xxx>%;
+
+      }
+    }
+
+    $xml_msg=~ s/<xxx><\/xxx>//;
+
+    return ( $xml_msg );
+}
+
+
+## @method opsi_list_clients
+# ???
+# @param msg - STRING - xml message 
+# @param msg_hash - HASHREF - message information parsed into a hash
+# @param session_id - INTEGER - POE session id of the processing of this message
+sub opsi_list_clients {
+    my ($msg, $msg_hash, $session_id) = @_;
+    my $header = @{$msg_hash->{'header'}}[0];
+    my $source = @{$msg_hash->{'source'}}[0];
+    my $target = @{$msg_hash->{'target'}}[0];
+    my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
+
+    # build return message with twisted target and source
+    my $out_hash = &main::create_xml_hash("answer_$header", $target, $source);
+    &add_content2xml_hash($out_hash, "session_id", $session_id);
+
+    if (defined $forward_to_gosa) {
+      &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
+    }
+
+    &add_content2xml_hash($out_hash, "xxx", "");
+    my $xml_msg= &create_xml_string($out_hash);
+
+    # JSON Query
+    my $callobj = {
+      method  => 'getClients_listOfHashes',
+      params  => [ ],
+      id  => 1,
+    };
+
+    my $res = $main::opsi_client->call($main::opsi_url, $callobj);
+    if (check_res($res)){
+
+      foreach my $host (@{$res->result}){
+        my $item= "<item><name>".$host->{'hostId'}."</name>";
+        if (defined($host->{'description'})){
+          $item.= "<description>".xml_quote($host->{'description'})."</description>";
+        }
+        $item.= "</item>";
+        $xml_msg=~ s%<xxx></xxx>%$item<xxx></xxx>%;
+      }
+
+    }
+
+    $xml_msg=~ s/<xxx><\/xxx>//;
+    return ( $xml_msg );
+}
+
+
+## @method opsi_get_client_software
+# ???
+# @param msg - STRING - xml message with tag hostId
+# @param msg_hash - HASHREF - message information parsed into a hash
+# @param session_id - INTEGER - POE session id of the processing of this message
+sub opsi_get_client_software {
+    my ($msg, $msg_hash, $session_id) = @_;
+    my $header = @{$msg_hash->{'header'}}[0];
+    my $source = @{$msg_hash->{'source'}}[0];
+    my $target = @{$msg_hash->{'target'}}[0];
+    my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
+    my $hostId = @{$msg_hash->{'hostId'}}[0];
+
+    # build return message with twisted target and source
+    my $out_hash = &main::create_xml_hash("answer_$header", $target, $source);
+    &add_content2xml_hash($out_hash, "session_id", $session_id);
+
+    if (defined $forward_to_gosa) {
+      &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
+    }
+    &add_content2xml_hash($out_hash, "hostId", "$hostId");
+    &add_content2xml_hash($out_hash, "xxx", "");
+    my $xml_msg= &create_xml_string($out_hash);
+
+    # JSON Query
+    my $callobj = {
+      method  => 'getSoftwareInformation_hash',
+      params  => [ $hostId ],
+      id  => 1,
+    };
+
+    my $res = $main::opsi_client->call($main::opsi_url, $callobj);
+    if (check_res($res)){
+      my $result= $res->result;
+    }
+
+    $xml_msg=~ s/<xxx><\/xxx>//;
+
+    return ( $xml_msg );
+}
+
+
+## @method opsi_get_local_products
+# ???
+# @param msg - STRING - xml message with tag hostId
+# @param msg_hash - HASHREF - message information parsed into a hash
+# @param session_id - INTEGER - POE session id of the processing of this message
+sub opsi_get_local_products {
+  my ($msg, $msg_hash, $session_id) = @_;
+  my $header = @{$msg_hash->{'header'}}[0];
+  my $source = @{$msg_hash->{'source'}}[0];
+  my $target = @{$msg_hash->{'target'}}[0];
+  my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
+  my $hostId;
+
+  # build return message with twisted target and source
+  my $out_hash = &main::create_xml_hash("answer_$header", $target, $source);
+  &add_content2xml_hash($out_hash, "session_id", $session_id);
+
+  # Get hostID if defined
+  if (defined @{$msg_hash->{'hostId'}}[0]){
+    $hostId = @{$msg_hash->{'hostId'}}[0];
+    &add_content2xml_hash($out_hash, "hostId", $hostId);
+  }
+
+  if (defined $forward_to_gosa) {
+    &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
+  }
+  &add_content2xml_hash($out_hash, "xxx", "");
+  my $xml_msg= &create_xml_string($out_hash);
+
+  # For hosts, only return the products that are or get installed
+  my $callobj;
+  $callobj = {
+    method  => 'getLocalBootProductIds_list',
+    params  => [ ],
+    id  => 1,
+  };
+
+  my $res = $main::opsi_client->call($main::opsi_url, $callobj);
+  my %r = ();
+  for (@{$res->result}) { $r{$_} = 1 }
+
+  if (check_res($res)){
+
+    if (defined $hostId){
+      $callobj = {
+        method  => 'getProductStates_hash',
+        params  => [ $hostId ],
+        id  => 1,
+      };
+
+      my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
+      if (check_res($hres)){
+        my $htmp= $hres->result->{$hostId};
+
+        # check state != not_installed or action == setup -> load and add
+        foreach my $product (@{$htmp}){
+
+          if (!defined ($r{$product->{'productId'}})){
+            next;
+          }
+
+          # Now we've a couple of hashes...
+          if ($product->{'installationStatus'} ne "not_installed" or
+              $product->{'actionRequest'} eq "setup"){
+            my $state= "<state>".$product->{'installationStatus'}."</state><action>".$product->{'actionRequest'}."</action>";
+
+            $callobj = {
+              method  => 'getProduct_hash',
+              params  => [ $product->{'productId'} ],
+              id  => 1,
+            };
+
+            my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
+            if (check_res($sres)){
+              my $tres= $sres->result;
+
+              my $name= xml_quote($tres->{'name'});
+              my $r= $product->{'productId'};
+              my $description= xml_quote($tres->{'description'});
+              $name=~ s/\//\\\//;
+              $description=~ s/\//\\\//;
+              $xml_msg=~ s/<xxx><\/xxx>/<item><ProductId>$r<\/ProductId><name><\/name><description>$description<\/description><\/item>$state<xxx><\/xxx>/;
+            }
+
+          }
+        }
+
+      }
+
+    } else {
+      foreach my $r (@{$res->result}) {
+        $callobj = {
+          method  => 'getProduct_hash',
+          params  => [ $r ],
+          id  => 1,
+        };
+
+        my $sres = $main::opsi_client->call($main::opsi_url, $callobj);
+        if (check_res($sres)){
+          my $tres= $sres->result;
+
+          my $name= xml_quote($tres->{'name'});
+          my $description= xml_quote($tres->{'description'});
+          $name=~ s/\//\\\//;
+          $description=~ s/\//\\\//;
+          $xml_msg=~ s/<xxx><\/xxx>/<item><ProductId>$r<\/ProductId><name><\/name><description>$description<\/description><\/item><xxx><\/xxx>/;
+        }
+
+      }
+
+    }
+  }
+
+  $xml_msg=~ s/<xxx><\/xxx>//;
+
+  return ( $xml_msg );
+}
+
+
+### @method _opsi_get_client_status
+## 
+## @param msg - STRING - xml message with tags 
+## @param msg_hash - HASHREF - message information parsed into a hash
+## @param session_id - INTEGER - POE session id of the processing of this message
+#sub _opsi_get_client_status {
+#  my $hostId = shift;
+#  my $result= {};
 #
+#  # For hosts, only return the products that are or get installed
+#  my $callobj;
+#  $callobj = {
+#    method  => 'getProductStates_hash',
+#    params  => [ $hostId ],
+#    id  => 1,
+#  };
 #
-#sub opsi_set_product_properties {
-#        my ($msg, $msg_hash, $session_id) = @_;
-#        $msg =~ s/gosa_opsi/opsi/g;
-#        return ( $msg );
-#}
+#  my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
+#  if (check_res($hres)){
+#    my $htmp= $hres->result->{$hostId};
 #
+#    # check state != not_installed or action == setup -> load and add
+#    my $products= 0;
+#    my $installed= 0;
+#    my $error= 0;
+#    foreach my $product (@{$htmp}){
 #
-#sub opsi_get_product_properties {
-#        my ($msg, $msg_hash, $session_id) = @_;
-#        $msg =~ s/gosa_opsi/opsi/g;
-#        return ( $msg );
-#}
+#      if ($product->{'installationStatus'} ne "not_installed" or
+#          $product->{'actionRequest'} eq "setup"){
 #
+#        # Increase number of products for this host
+#        $products++;
 #
-#sub opsi_get_local_products {
-#        my ($msg, $msg_hash, $session_id) = @_;
-#        $msg =~ s/gosa_opsi/opsi/g;
-#        return ( $msg );
-#}
+#        if ($product->{'installationStatus'} eq "failed"){
+#          $result->{$product->{'productId'}}= "error";
+#          $error++;
+#        }
+#        if ($product->{'installationStatus'} eq "installed"){
+#          $result->{$product->{'productId'}}= "installed";
+#          $installed++;
+#        }
+#        if ($product->{'installationStatus'} eq "installing"){
+#          $result->{$product->{'productId'}}= "installing";
+#        }
+#      }
+#    }
 #
-#sub opsi_get_client_hardware {
-#        my ($msg, $msg_hash, $session_id) = @_;
-#        $msg =~ s/gosa_opsi/opsi/g;
-#        return ( $msg );
-#}
+#    # Estimate "rough" progress
+#    $result->{'progress'}= int($installed * 100 / $products);
+#  }
 #
-#sub opsi_get_client_software {
-#        my ($msg, $msg_hash, $session_id) = @_;
-#        $msg =~ s/gosa_opsi/opsi/g;
-#        return ( $msg );
+#  return $result;
 #}
+
+
+## @method opsi_del_client
+# ???
+# @param msg - STRING - xml message with tag hostId
+# @param msg_hash - HASHREF - message information parsed into a hash
+# @param session_id - INTEGER - POE session id of the processing of this message
+sub opsi_del_client {
+    my ($msg, $msg_hash, $session_id) = @_;
+    my $header = @{$msg_hash->{'header'}}[0];
+    my $source = @{$msg_hash->{'source'}}[0];
+    my $target = @{$msg_hash->{'target'}}[0];
+    my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
+    my $hostId = @{$msg_hash->{'hostId'}}[0];
+
+    # build return message with twisted target and source
+    my $out_hash = &main::create_xml_hash("answer_$header", $target, $source);
+    &add_content2xml_hash($out_hash, "session_id", $session_id);
+
+    if (defined $forward_to_gosa) {
+      &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
+    }
+    &add_content2xml_hash($out_hash, "hostId", "$hostId");
+
+    # JSON Query
+    my $callobj = {
+      method  => 'deleteClient',
+      params  => [ $hostId ],
+      id  => 1,
+    };
+
+    my $res = $main::opsi_client->call($main::opsi_url, $callobj);
+
+    my $xml_msg= &create_xml_string($out_hash);
+    return ( $xml_msg );
+}
+
+
+## @method opsi_install_client
+# ???
+# @param msg - STRING - xml message with tag hostId
+# @param msg_hash - HASHREF - message information parsed into a hash
+# @param session_id - INTEGER - POE session id of the processing of this message
+sub opsi_install_client {
+    my ($msg, $msg_hash, $session_id) = @_;
+    my $header = @{$msg_hash->{'header'}}[0];
+    my $source = @{$msg_hash->{'source'}}[0];
+    my $target = @{$msg_hash->{'target'}}[0];
+    my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
+    my $hostId = @{$msg_hash->{'hostId'}}[0];
+
+    # build return message with twisted target and source
+    my $out_hash = &main::create_xml_hash("answer_$header", $target, $source);
+    &add_content2xml_hash($out_hash, "session_id", $session_id);
+
+    if (defined $forward_to_gosa) {
+      &add_content2xml_hash($out_hash, "forward_to_gosa", $forward_to_gosa);
+    }
+    &add_content2xml_hash($out_hash, "hostId", "$hostId");
+
+    # Load all products for this host with status != "not_installed" or actionRequest != "none"
+    if (defined $hostId){
+      my $callobj = {
+        method  => 'getProductStates_hash',
+        params  => [ $hostId ],
+        id  => 1,
+      };
+
+      my $hres = $main::opsi_client->call($main::opsi_url, $callobj);
+      if (check_res($hres)){
+        my $htmp= $hres->result->{$hostId};
+
+        # check state != not_installed or action == setup -> load and add
+        foreach my $product (@{$htmp}){
+
+          # Now we've a couple of hashes...
+          if ($product->{'installationStatus'} ne "not_installed" or
+              $product->{'actionRequest'} ne "none"){
+
+            # Do an action request for all these -> "setup".
+            $callobj = {
+              method  => 'setProductActionRequest',
+              params  => [ $product->{'productId'}, $hostId, "setup" ],
+              id  => 1,
+            };
+            my $res = $main::opsi_client->call($main::opsi_url, $callobj);
+            if (!check_res($res)){
+              &main::daemon_log("ERROR: cannot set product action request for $hostId!", 1);
+            } else {
+              &main::daemon_log("INFO: requesting 'setup' for '".$product->{'productId'}."' on $hostId", 1);
+            }
+
+          }
+        }
+      }
+    }
+
+
+
+#    # JSON Query
+#    my $callobj = {
+#      method  => 'deleteClient',
+#      params  => [ $hostId ],
+#      id  => 1,
+#    };
 #
+#    my $res = $main::opsi_client->call($main::opsi_url, $callobj);
+
+    my $xml_msg= &create_xml_string($out_hash);
+    return ($xml_msg);
+}
+
+
+## @method _set_action
+# ???
+# @param product - STRING - ???
+# @param action - STRING - ???
+# @param hostId - STRING - ???
+sub _set_action {
+  my $product= shift;
+  my $action = shift;
+  my $hostId = shift;
+  my $callobj;
+
+  $callobj = {
+    method  => 'setProductActionRequest',
+    params  => [ $product, $hostId, $action],
+    id  => 1,
+  };
+
+  $main::opsi_client->call($main::opsi_url, $callobj);
+}
+
+## @method _set_state
+# ???
+# @param product - STRING - ???
+# @param action - STRING - ???
+# @param hostId - STRING - ???
+sub _set_state {
+  my $product = shift;
+  my $hostId = shift;
+  my $action = shift;
+  my $callobj;
+
+  $callobj = {
+    method  => 'setProductState',
+    params  => [ $product, $hostId, $action ],
+    id  => 1,
+  };
+
+  $main::opsi_client->call($main::opsi_url, $callobj);
+}
+
 1;