X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;ds=sidebyside;f=gosa-plugins%2Fopsi%2Fadmin%2Fopsi%2Fclass_opsigeneric.inc;h=bc3740b07406f6767ad44c3b9f9a7cb19c4ae165;hb=1069abb526ffe35a330b8a73658695193fbb6035;hp=ab2fcebc4b3e915662d3a0200a37c230777d1b90;hpb=28182a91109772ab05db418afd20b4d301e4fa08;p=gosa.git diff --git a/gosa-plugins/opsi/admin/opsi/class_opsigeneric.inc b/gosa-plugins/opsi/admin/opsi/class_opsigeneric.inc index ab2fcebc4..bc3740b07 100644 --- a/gosa-plugins/opsi/admin/opsi/class_opsigeneric.inc +++ b/gosa-plugins/opsi/admin/opsi/class_opsigeneric.inc @@ -15,6 +15,7 @@ class opsiGeneric extends plugin /* Contains a list of all available netboot products */ private $a_availableNetbootProducts = array(); + private $a_initial_availableNetbootProducts = array(); private $s_selectedNetbootProduct = ""; private $s_initial_selectedNetbootProduct = ""; @@ -29,7 +30,7 @@ class opsiGeneric extends plugin private $opsi; // The opsi handle public $parent = NULL; // The parent object (in case of samba) - private $hostId = ""; // The host Id of the currently edit opsi host + public $hostId = ""; // The host Id of the currently edit opsi host public $mac = ""; // The hosts mac address public $note = ""; // A note public $description = ""; // The client description @@ -39,28 +40,30 @@ class opsiGeneric extends plugin public $initial_description = ""; private $init_failed = FALSE; // Is true if the opsi communication failed - private $parent_mode = TRUE; // Is true if this is a standlone plugin. (Not samba) + private $standalone = TRUE; // Is true if this is a standlone plugin. (Not samba) private $is_installed= FALSE; // Is true is the hast is already installed. public $attributes = array("mac","note","description"); + public $netConfigDNS = NULL; /*! \brief Initialize this class @param Object The GOsa base config. @param String The Id of the host that we want to edit. @param Object The parent object. (in case of samba) */ - public function __construct($config,$hostId,&$parent = NULL) + public function __construct(&$config,$hostId,&$parent = NULL) { /* Create opsi handle */ $this->opsi = new opsi($config); + $this->config = $config; /* Check if we are are part of a windows workstation */ $this->parent = $parent; if($parent instanceof wingeneric){ - $this->parent_mode = FALSE; + $this->standalone = FALSE; } /* Get hostId @@ -73,7 +76,7 @@ class opsiGeneric extends plugin $this->hostId = preg_replace('/\$$/',"",$this->hostId); } } - + /* Try to plugin */ $this->init(); } @@ -88,9 +91,16 @@ class opsiGeneric extends plugin $this->init_failed = FALSE; $this->initially_was_account = FALSE; + /* We are a standalone plugin. + */ + if($this->standalone ) { + $this->is_account = TRUE; + } + + /* Try to load client infos from the gosa support daemon */ - if($this->hostId != "new"){ + if(!empty($this->hostId)){ $list = $this->opsi->list_clients($this->hostId); $err |= $this->opsi->is_error(); @@ -99,8 +109,9 @@ class opsiGeneric extends plugin #FIXME Implement an opsi method which returns infos for only one opsi client, not all. */ foreach($list as $entry){ - if(preg_match("/^".normalizePreg($this->hostId)."$/i",$entry['NAME'][0]['VALUE'])){ + if(preg_match("/^".preg_quote($this->hostId, '/')."$/i",$entry['NAME'][0]['VALUE'])){ $this->initially_was_account = TRUE; + $this->is_account = TRUE; foreach(array( "is_installed" => "LASTSEEN", "description" => "DESCRIPTION", @@ -114,58 +125,82 @@ class opsiGeneric extends plugin } } - /* Fetch all product infos from support daemon - */ - if(!$err){ - $this->a_availableNetbootProducts = $this->opsi->get_netboot_products(); - $err |= $this->opsi->is_error(); - } - if(!$err) { - $this->a_availableLocalProducts = $this->opsi->get_local_products(); - $err |= $this->opsi->is_error(); - } + // Get package info + $list = array(); + $list = $this->opsi->get_full_product_host_information($this->hostId); + $err |= $this->opsi->is_error(); - /* Get products selected by this host. + /* Read informations about available netboot products. + If not already done, before. */ - if(!$err && !empty($this->hostId)) { - $tmp = array_keys($this->opsi->get_netboot_products($this->hostId)); - if(count($tmp)){ - $this->s_selectedNetbootProduct = $tmp[0]; + if(!$err){ + foreach($list as $key => $entry){ + + $tmp = array('DESC'=>$entry['data']['DESCRIPTION'],'NAME'=>$key); + if($entry['configurable']){ + $tmp['CFG'] = $entry['data']['PROPERTIES']; + } + + if($entry['data']['TYPE'] == "localboot"){ + if(!$entry['installed']){ + $this->a_availableLocalProducts[$key] = $tmp; + }else{ + $this->a_selectedLocalProducts[$key] = $tmp; + } + }else{ + $this->a_availableNetbootProducts[$key] = $tmp; + if($entry['installed']){ + $this->s_selectedNetbootProduct= $key; + } + } } - $err |= $this->opsi->is_error(); - } - if(!$err && !empty($this->hostId)) { - $tmp = $this->opsi->get_local_products($this->hostId); - $err |= $this->opsi->is_error(); - $this->a_selectedLocalProducts = $tmp; } - /* Load product configuration for all already selected products. - */ - if(!$err && !empty($this->hostId)) { - foreach($this->a_selectedLocalProducts as $name => $data){ - $CFG = $this->opsi->get_product_properties($name,$this->hostId); - $err |= $this->opsi->is_error(); - $this->a_selectedLocalProducts[$name]['CFG'] = $CFG; - } - } - /* Check if everything went fine else reset everything and display a retry button */ if($err){ - $this->a_availableNetbootProducts = array(); - $this->s_selectedNetbootProduct = ""; - $this->s_initial_selectedNetbootProduct = ""; - $this->a_availableLocalProducts = array(); - $this->a_selectedLocalProducts = array(); - $this->a_initial_selectedLocalProducts = array(); $this->init_failed = TRUE; + }else{ - /* Remember initial settings */ - $this->is_account = $this->initially_was_account; + /* Remember initial settings */ $this->a_initial_selectedLocalProducts = $this->a_selectedLocalProducts; $this->s_initial_selectedNetbootProduct = $this->s_selectedNetbootProduct; + $this->a_initial_availableNetbootProducts = $this->a_availableNetbootProducts; + + /* Ensure that a valid netboot is selected product is. + */ + if(empty($this->s_selectedNetbootProduct)){ + $this->s_selectedNetbootProduct = key($this->a_availableNetbootProducts); + } + + // Now fake a valid ldap entry ... this is necessary to avoid + // modifications in the dns/dhcp classes + + // First fake cn + $this->attrs['hostId'][0] = $this->hostId; + $this->attrs['cn'][0] = $this->hostId; + + // Second detect DNS settings. + $ldap = $this->config->get_ldap_link(); + $ldap->cd($this->config->current['BASE']); + $strippedHostId = preg_replace("/\..*$/","",$this->hostId); + $ldap->search("(&(objectClass=dNSZone)(|(relativeDomainName=".$this->hostId.")(relativeDomainName=".$strippedHostId."))(aRecord=*))",array("aRecord")); + if($ldap->count()){ + $attrs = $ldap->fetch(); + $this->attrs['ipHostNumber']['count'] = 0; + $this->attrs['ipHostNumber'][0] = $attrs['aRecord'][0]; + } + + $this->attrs['macAddress']['count'] = 1; + $this->attrs['macAddress'][0] = &$this->mac; + + // Initialize DHCP and DNS + $this->netConfigDNS = new termDNS($this->config,$this,$this->objectclasses, FALSE, "hostId"); + $this->netConfigDNS->set_acl_category("opsi"); + $this->netConfigDNS->set_acl_base($this->config->current['BASE']); + $this->netConfigDNS->IPisMust = FALSE; + $this->netConfigDNS->MACisMust = TRUE; } } @@ -175,8 +210,15 @@ class opsiGeneric extends plugin */ public function check() { - return(array()); + + // In case of initialization problem, we do not save anything. + // We can skip checks here, the date isn't usable. + if($this->init_failed){ + return; + }; + $messages = plugin::check(); + $messages= array_merge($messages, $this->netConfigDNS->check()); if(empty($this->hostId)){ $messages[] = msgPool::required(_("Name")); @@ -185,7 +227,7 @@ class opsiGeneric extends plugin /* The hostId must contain a domain part */ $messages[] = msgPool::invalid(_("Name"),$this->hostId,"", - _("The client name must contain a domain part (e.g. '.company.de').")); + _("The field 'Name' must contain a domain part!")); }elseif(preg_match("/[^a-z0-9\.\-_]/",$this->hostId)){ $messages[] = msgPool::invalid(_("Name"),$this->hostId,"/[a-z0-9\.\-_]/"); } @@ -211,29 +253,33 @@ class opsiGeneric extends plugin */ if($this->init_failed){ $smarty = get_smarty(); + $smarty->assign("standalone ", $this->standalone ); $smarty->assign("init_failed",TRUE); $smarty->assign("message",$this->opsi->get_error()); return($smarty->fetch(get_template_path("generic.tpl",TRUE,dirname(__FILE__)))); } + /* If we are not a stand alone opsi client, we must be a samba client which has the opsi tab enabled. Check if the opsi is added or removed and display state buttons. */ - if(!$this->parent_mode){ + if(!$this->standalone ){ + + /* Do we need to flip is_account state? */ if(isset($_POST['modify_state'])){ - if($this->is_account){ + if($this->is_account && $this->acl_is_removeable()){ $this->is_account= FALSE; - }elseif(!$this->is_account){ + }elseif(!$this->is_account && $this->acl_is_createable()){ $this->is_account= TRUE; } } if($this->is_account){ - $display = $this->show_disable_header(msgPool::removeFeaturesButton(_("Opsi")), - msgPool::featuresEnabled(_("Opsi"))); + $display = $this->show_disable_header(msgPool::removeFeaturesButton(_("OPSI")), + msgPool::featuresEnabled(_("OPSI"))); }else{ - $display = $this->show_enable_header(msgPool::addFeaturesButton(_("Opsi")), - msgPool::featuresDisabled(_("Opsi"))); + $display = $this->show_enable_header(msgPool::addFeaturesButton(_("OPSI")), + msgPool::featuresDisabled(_("OPSI"))); return($display); } } @@ -248,11 +294,17 @@ class opsiGeneric extends plugin /* Create HTML output of this plugin */ $smarty = get_smarty(); + $smarty->assign("standalone", $this->standalone ); foreach($this->attributes as $attr){ $smarty->assign($attr,$this->$attr); } - $smarty->assign("parent_mode", $this->parent_mode); + /* Assign ACLs */ + $tmp = $this->plInfo(); + foreach($tmp['plProvidedAcls'] as $name => $translated){ + $smarty->assign($name."ACL",$this->getacl($name)); + } + $smarty->assign("is_installed", $this->is_installed); $smarty->assign("init_failed",FALSE); $divSLP = new divSelectBox(); @@ -260,7 +312,6 @@ class opsiGeneric extends plugin /* Create list of available local products */ - ksort($this->a_availableLocalProducts); foreach($this->a_availableLocalProducts as $name => $data){ if(isset($this->a_selectedLocalProducts[$name])) continue; @@ -268,33 +319,60 @@ class opsiGeneric extends plugin $name_tab = array("string" => $name); $desc_tab = array("string" => "
".$data['DESC']."
", "attach" => "title='".$data['DESC']."' style='border-right:0px;'"); - $divALP->AddEntry(array($add_tab,$name_tab,$desc_tab)); + + if($this->acl_is_writeable("localProduct")){ + $divALP->AddEntry(array($add_tab,$name_tab,$desc_tab)); + }else{ + $divALP->AddEntry(array($name_tab,$desc_tab)); + } } /* Create list of selected local products */ ksort($this->a_selectedLocalProducts); - foreach($this->a_selectedLocalProducts as $name => $data){ + if($this->acl_is_readable("localProduct")){ + foreach($this->a_selectedLocalProducts as $name => $data){ - $name_tab = array("string" => $name); - $desc_tab = array( - "string" => "
".$data['DESC']."
", - "attach" => "title='".$data['DESC']."'"); + $name_tab = array("string" => $name); + $desc_tab = array( + "string" => "
".$data['DESC']."
", + "attach" => "title='".$data['DESC']."'"); - /* Only display edit button, if there is something to edit - */ - $edit = " "; - if(count($data['CFG'])){ - $edit = ""; + /* Only display edit button, if there is something to edit + */ + $edit = " "; + if(count($data['CFG'])){ + $edit = ""; + } + $del = ""; + + $opt_tab = array("string" => $edit.$del, + "attach" => "style='border-right:0px; width: 40px; text-align:right;'"); + + if($this->acl_is_writeable("localProduct")){ + $divSLP->AddEntry(array($name_tab,$desc_tab,$opt_tab)); + }else{ + $divSLP->AddEntry(array($name_tab,$desc_tab)); + } } - $del = ""; + } + + /* Check if netboot product is configurable + */ + $cfg_able =FALSE; + if(isset($this->a_availableNetbootProducts[$this->s_selectedNetbootProduct]['CFG'])){ + $cfg_able = count($this->a_availableNetbootProducts[$this->s_selectedNetbootProduct]['CFG']); + $cfg_able &= $this->acl_is_readable("netbootProduct"); + } - $opt_tab = array("string" => $edit.$del, - "attach" => "style='border-right:0px; width: 40px; text-align:right;'"); - $divSLP->AddEntry(array($name_tab,$desc_tab,$opt_tab)); + // Get net config template + $str = $this->netConfigDNS->execute(); + if(is_object($this->netConfigDNS->dialog)){ + return($str); } + $smarty->assign("netconfig", $str); - ksort($this->a_availableNetbootProducts); + $smarty->assign("netboot_configurable",$cfg_able); $smarty->assign("hostId", $this->hostId); $smarty->assign("divSLP", $divSLP->DrawList()); $smarty->assign("divALP", $divALP->DrawList()); @@ -308,6 +386,9 @@ class opsiGeneric extends plugin */ public function save() { + if($this->init_failed){ + return; + } /* Check if we have to create a new opsi client or just have to save client modifications. @@ -334,10 +415,18 @@ class opsiGeneric extends plugin } } + + /*********** + Detect local netboot product changes + - Check which products were removed. + - Check which products were added. + ***********/ + + /* Detect which products were removed an which added. */ - $add = array_diff_assoc($this->a_selectedLocalProducts,$this->a_initial_selectedLocalProducts); $del = array_diff_assoc($this->a_initial_selectedLocalProducts,$this->a_selectedLocalProducts); + $add = array_diff_assoc($this->a_selectedLocalProducts,$this->a_initial_selectedLocalProducts); /* Remove products from client */ @@ -350,6 +439,7 @@ class opsiGeneric extends plugin } /* Add products to client + And set the product properties. */ foreach($add as $name => $data){ $this->opsi->add_product_to_client($name,$this->hostId); @@ -373,9 +463,9 @@ class opsiGeneric extends plugin /* Update product properties if there are changes */ - #if(serialize($data['CFG']) != serialize($this->a_initial_selectedLocalProducts[$name]['CFG'])){ - if($data['CFG'] != $this->a_initial_selectedLocalProducts[$name]['CFG']){ - $this->opsi->set_product_properties($name,$data['CFG'],$this->hostId); + $diffs = $this->get_config_changes($data['CFG'],$this->a_initial_selectedLocalProducts[$name]['CFG']); + if(count($diffs)){ + $this->opsi->set_product_properties($name,$diffs,$this->hostId); if($this->opsi->is_error()){ msg_dialog::display(_("Error"),msgPool::siError($this->opsi->get_error()),ERROR_DIALOG); return; @@ -383,6 +473,12 @@ class opsiGeneric extends plugin } } + /********* + Detect Netboot product changes + - Check if another netboot product was selected. + - Check if the product properties were changes. + *********/ + /* Update used netboot product. */ if($this->s_selectedNetbootProduct != $this->s_initial_selectedNetbootProduct){ @@ -399,6 +495,57 @@ class opsiGeneric extends plugin return; } } + + /* Check if we have to update the netboot product properties + This is the case, if this product is newly selected. + Or if there was at least one configuration attribute modified. + */ + $cfg_1 = $cfg_2 = array(); + if(isset($this->a_availableNetbootProducts[$this->s_selectedNetbootProduct]['CFG'])){ + $cfg_1 = $this->a_availableNetbootProducts[$this->s_selectedNetbootProduct]['CFG']; + } + if(isset($this->a_initial_availableNetbootProducts[$this->s_selectedNetbootProduct]['CFG'])){ + $cfg_2 = $this->a_initial_availableNetbootProducts[$this->s_selectedNetbootProduct]['CFG']; + } + $diffs = $this->get_config_changes($cfg_1,$cfg_2); + $to_update = array(); + if( !$this->initially_was_account || + $this->s_selectedNetbootProduct != $this->s_initial_selectedNetbootProduct){ + $to_update = $this->a_availableNetbootProducts[$this->s_selectedNetbootProduct]['CFG']; + }elseif(count($diffs)){ + $to_update = $diffs; + } + + if(count($to_update)){ + $name = $this->s_selectedNetbootProduct; + $this->opsi->set_product_properties($name,$to_update,$this->hostId); + if($this->opsi->is_error()){ + msg_dialog::display(_("Error"),msgPool::siError($this->opsi->get_error()),ERROR_DIALOG); + return; + } + } + + $this->netConfigDNS->cn = $this->hostId; + $this->netConfigDNS->save(); + } + + + public function get_config_changes($c1,$c2) + { + /* Get key which are not present in both entries + */ + $res = array(); + foreach($c2 as $name => $value){ + if(!isset($c1[$name]) || $c1[$name]['CURRENT'] != $c2[$name]['CURRENT']){ + $res[$name] = $c2[$name]; + } + } + foreach($c1 as $name => $value){ + if(!isset($c2[$name]) || $c2[$name]['CURRENT'] != $c1[$name]['CURRENT']){ + $res[$name] = $c1[$name]; + } + } + return($res); } @@ -406,6 +553,11 @@ class opsiGeneric extends plugin */ public function remove_from_parent() { + if($this->init_failed){ + return; + } + $this->netConfigDNS->remove_from_parent(); + $this->opsi->del_client($this->hostId); if($this->opsi->is_error()){ msg_dialog::display(_("Error"),msgPool::siError($this->opsi->get_error()),ERROR_DIALOG); @@ -437,9 +589,18 @@ class opsiGeneric extends plugin $pro = $this->dialog->get_product(); $CFG = $this->dialog->get_cfg(); if(isset($this->a_selectedLocalProducts[$pro])){ - $this->a_selectedLocalProducts[$pro]['CFG'] = $CFG; + if($this->acl_is_writeable("localProduct")){ + $this->a_selectedLocalProducts[$pro]['CFG'] = $CFG; + } + $this->dialog = NULL; + }elseif($this->s_selectedNetbootProduct == $pro){ + if($this->acl_is_writeable("netbootProduct")){ + $this->a_availableNetbootProducts[$pro]['CFG'] = $CFG; + } + $this->dialog = NULL; + }else{ + trigger_error("Fatal, unknown product was configured."); } - $this->dialog = NULL; } /* Save html post @@ -447,27 +608,43 @@ class opsiGeneric extends plugin if(isset($_POST['opsiGeneric_posted'])){ plugin::save_object(); - + $this->netConfigDNS->save_object(); + $this->mac = $this->netConfigDNS->macAddress; + /* Get hostId */ - if(isset($_POST['hostId']) && $this->parent_mode){ + if(isset($_POST['hostId']) && $this->standalone && $this->acl_is_writeable("hostId")){ $this->hostId = get_post('hostId'); } /* Send actions like 'install' or 'wake' to the si server */ - if(isset($_POST['opsi_action']) && isset($_POST['opsi_trigger_action']) && $this->parent_mode){ + if($this->acl_is_writeable("triggerAction") && + isset($_POST['opsi_action']) && + isset($_POST['opsi_trigger_action']) && + $this->standalone ){ $action = $_POST['opsi_action']; if($action == "install"){ $this->install_client(); } + if($action == "wake"){ + $this->wake_client(); + } } /* Get selected netboot product. */ - if(isset($_POST['opsi_netboot_product'])){ + if(isset($_POST['opsi_netboot_product']) && $this->acl_is_writeable("netbootProduct")){ $SNP = trim($_POST['opsi_netboot_product']); if(isset($this->a_availableNetbootProducts[$SNP])){ + if(!isset($this->a_availableNetbootProducts[$SNP]['CFG'])){ + $CFG = $this->opsi->get_product_properties($SNP); + $this->a_availableNetbootProducts[$SNP]['CFG'] = $CFG; + if($this->opsi->is_error()){ + $this->init_failed = TRUE; + return; + } + } $this->s_selectedNetbootProduct = $SNP; } } @@ -475,14 +652,27 @@ class opsiGeneric extends plugin /* Add/remove/edit local products */ foreach($_POST as $name => $value){ + + /* Check if netboot product configuration is requested + */ + if(preg_match("/^configure_netboot/",$name) && $this->acl_is_readable("netbootProduct")){ + $pro = $this->s_selectedNetbootProduct; + $cfg = $this->a_availableNetbootProducts[$pro]['CFG']; + $this->dialog = new opsiProperties($this->config,$pro,$cfg,$this->hostId); + break; + } /* Add product */ - if(preg_match("/^add_lp_/",$name)){ + if(preg_match("/^add_lp_/",$name) && $this->acl_is_writeable("localProduct")){ $product = preg_replace("/^add_lp_(.*)_.$/","\\1",$name); if(isset($this->a_availableLocalProducts[$product]) && !isset($this->a_selectedLocalProducts[$product])){ $this->a_selectedLocalProducts[$product] = $this->a_availableLocalProducts[$product]; $CFG = $this->opsi->get_product_properties($product); + if($this->opsi->is_error()){ + $this->init_failed = TRUE; + return; + } $this->a_selectedLocalProducts[$product]['CFG'] = $CFG; } break; @@ -490,7 +680,7 @@ class opsiGeneric extends plugin /* Delete product */ - if(preg_match("/^del_lp_/",$name)){ + if(preg_match("/^del_lp_/",$name) && $this->acl_is_writeable("localProduct")){ $product = preg_replace("/^del_lp_(.*)_.$/","\\1",$name); if(isset($this->a_selectedLocalProducts[$product])){ unset($this->a_selectedLocalProducts[$product]); @@ -500,7 +690,7 @@ class opsiGeneric extends plugin /* Edit a product */ - if(preg_match("/^edit_lp_/",$name)){ + if(preg_match("/^edit_lp_/",$name) && $this->acl_is_readable("localProduct")){ $product = preg_replace("/^edit_lp_(.*)_.$/","\\1",$name); $this->dialog = new opsiProperties($this->config, $product,$this->a_selectedLocalProducts[$product]['CFG'],$this->hostId); @@ -522,22 +712,46 @@ class opsiGeneric extends plugin } + /* Wake up client + */ + function wake_client() + { + /* Check if we are able to communicate with the GOsa supprot daemon + */ + if(class_available("gosaSupportDaemon")){ + $o = new gosaSupportDaemon(); + if($o->connect() && class_available("DaemonEvent_wakeup")){ + $evt = new DaemonEvent_wakeup($this->config); + $evt->add_targets(array($this->mac)); + $o->append($evt); + } + } + } + + /* Return plugin informations for acl handling */ static function plInfo() { return (array( "plShortName" => _("Generic"), - "plDescription" => _("Opsi generic"), + "plDescription" => _("OPSI generic"), "plSelfModify" => FALSE, "plDepends" => array(), "plPriority" => 1, "plSection" => array("administration"), - "plCategory" => array("opsi" => array("description" => _("Opsi client"), - "objectClass" => "dummy_class_opsi")), - "plProvidedAcls"=> array() + "plCategory" => array("opsi" => array("description" => _("Opsi"), + "objectClass" => "dummy_class_opsi")), + + "plProvidedAcls"=> array( + "hostId" => _("Name"), + "mac" => _("MAC address"), + "description" => _("Description"), + "note" => _("Note"), + "netbootProduct" => _("Netboot product"), + "localProduct" => _("Local product"), + "triggerAction" => _("Action")) )); } - }