1 <?php
3 class InstallRecipe extends plugin
4 {
6 public $rpcErrorMessage = "";
7 public $deviceUUID = "";
9 // Template options
10 public $installTemplate = "";
11 public $installationTemplateNames = array();
12 public $templateToRelease = array();
13 public $installationTemplates = array();
15 // The selected installation release
16 public $installRelease = "";
18 // Selected config management variant
19 public $installConfigManagement = '';
20 public $installConfigManagementList = array();
22 // Bootstrap method
23 public $installBootstrapMethod = '';
24 public $installBootstrapMethodList = array();
26 // Timezone settings
27 public $installTimezone = "";
28 public $installTimeUTC = "";
30 // Kernel packages
31 public $installKernelPackage = "";
32 public $installKernelPackageList = array();
34 // System Locale
35 public $installSystemLocale = "";
36 public $installSystemLocaleList = array();
38 // Selected NTP Server
39 public $installNTPServer = array();
40 public $installNTPServerList = NULL;
42 // Root password
43 public $installRootEnabled = "";
44 public $installRootPasswordHash = "";
45 public $setPasswordHash = FALSE;
47 // Partition table variables
48 public $installPartitionTable = "";
49 private $partitionEdit = NULL;
51 // Keyboard-layout attribute
52 public $installKeyboardlayout = "";
53 public $installKeyboardlayoutList = array();
55 // Mirror related attribute
56 public $installMirror = "";
57 public $installMirrorList = array();
59 public $objectclasses = array();
60 public $attributes = array("installRelease", "installTemplate","installKeyboardlayout","installSystemLocale",
61 "installTimezone","installTimeUTC","installNTPServer","installMirror",
62 "installRootEnabled","installRootPasswordHash","installKernelPackage",
63 "installPartitionTable","installConfigManagement","installBootstrapMethod");
66 /* Some plugin management related attributes
67 * See class plugin for details.
68 */
69 public $view_logged = FALSE;
70 public $ignore_account = FALSE;
71 public $parent = NULL;
73 /*! \brief Initialize the plugin and its widgets.
74 * Finally call init() to load values from the backend.
75 */
76 function __construct(&$config, $dn, $parent)
77 {
78 plugin::plugin($config, $dn);
80 $this->is_account = $this->initially_was_account = FALSE;
82 $this->_device = &$parent;
83 $this->deviceUUID = $parent->deviceUUID;
85 // Set default password hash
86 $this->hash = $this->config->get_cfg_value("core","passwordDefaultHash");
88 // Get list of password hashes
89 $tmp = passwordMethod::get_available_methods();
90 $this->hashes = array();
91 foreach($tmp['name'] as $name){
92 $this->hashes[$name] = $name;
93 }
95 // Initialize plugin
96 $this->init_static_info();
97 $this->init($initially = TRUE);
98 }
100 function init($initially = FALSE)
101 {
102 // Init the object values.
103 $this->init_client_info();
105 // Prepare NTP servers list
106 $this->installNTPServerList= new sortableListing($this->installNTPServer);
107 $this->installNTPServerList->setDeleteable(true);
108 $this->installNTPServerList->setEditable(false);
109 $this->installNTPServerList->setColspecs(array('*'));
110 $this->installNTPServerList->setWidth("100%");
111 $this->installNTPServerList->setHeight("70px");
113 // Preset values for new devices
114 if(!$this->is_account){
115 $this->installTemplate = key($this->installationTemplates);
116 $this->installRelease = key($this->templateToRelease[$this->installTemplate]);
117 }else{
119 if(!isset($this->installationTemplates[$this->installTemplate])){
121 // The selected template is no longer available, select the next selectable template.
122 $new = key($this->installationTemplates);
124 if($initially){
125 $message = sprintf(_("The selected template '%s' is no longer available. Selecting '%s' as replacement!"),
126 $this->installTemplate, $new);
127 msg_dialog::display(_("Warning"), $message, WARNING_DIALOG);
128 }
129 $this->installTemplate = $new;
130 $installRelease = key($this->templateToRelease[$this->installTemplate]);
132 }elseif(!isset($this->installationTemplates[$this->installTemplate]['method'])){
134 // Not necessary to warn the user here, the input fields will be empty and thus
135 // avoid saving.
137 }elseif(!in_array($this->installRelease, $this->templateToRelease[$this->installTemplate])){
139 // The selected release is no longer available for the current template
140 // Warn the user and select the next selectable release.
141 $new = key($this->templateToRelease[$this->installTemplate]);
142 if($initially){
143 $message = sprintf(_("The selected release '%s' is no longer available. Selecting '%s' as replacement!"),
144 $this->installRelease, $new);
145 }
146 $this->installRelease = $new;
147 msg_dialog::display(_("Warning"), $message, WARNING_DIALOG);
148 }
149 }
151 // Update selectable items like kernels and mirrors depending on the current setup (relase)
152 $this->installBootstrapMethod = $this->installationTemplates[$this->installTemplate]['method'];
153 $this->reloadInstallationKernelPackages($initially);
154 $this->reloadInstallationMirrors($initially);
155 }
158 /*! \brief Loads client-information values from the GOsa-backend using jsonRPC
159 */
160 function init_client_info()
161 {
162 if(empty($this->deviceUUID)){
163 return;
164 }
166 $rpc = $this->config->getRpcHandle();
167 $res = $rpc->systemGetBaseInstallParameters($this->deviceUUID);
169 // Failed to load backend values, keep reported error and return with FALSE;
170 $this->rpcError = !$rpc->success();
171 if(!$rpc->success()){
172 $this->rpcErrorMessage = $rpc->get_error();
173 msg_dialog::display(_("Error"), msgPool::rpcError($this->rpcErrorMessage), ERROR_DIALOG);
174 return(NULL);
175 }
177 // Apply received options
178 $this->is_account = $res == True;
179 if($this->is_account){
181 $map = array(
182 'ntp-servers' => "installNTPServer",
183 'template' => "installTemplate",
184 'keyboard-layout' => "installKeyboardlayout");
186 // We receive an array for these attributes, but require a string instead
187 // we just use the first element of the array.
188 $mapArray = array(
189 'release' => "installRelease",
190 'timezone' => "installTimezone",
191 'utc' => "installTimeUTC",
192 'kernel' => "installKernelPackage",
193 'system-locale' => "installSystemLocale",
194 'root-user' => "installRootEnabled",
195 'root-hash' => "installRootPasswordHash",
196 'disk-setup' => "installPartitionTable");
198 foreach($res as $name => $data){
199 if(isset($map[$name])){
200 $target = $map[$name];
201 $value = $res[$name];
202 }elseif(isset($mapArray[$name])){
203 $target = $mapArray[$name];
204 $value = $res[$name][0];
205 }
206 $this->$target = $value;
207 }
209 // Convert Bool values to Bool.
210 $boolean = array("installRootEnabled", "installTimeUTC");
211 foreach($boolean as $attr){
212 $this->$attr = ($this->$attr != FALSE && !preg_match("/false/i", $this->$attr));
213 }
214 }
216 return;
217 }
220 function init_static_info()
221 {
222 // Load static values.
223 foreach(array(
224 "timeozones" => "getTimezones",
225 "distributions" => "loadDistributions",
226 "keyboardLayouts" => "loadInstallationKeyboardLayouts",
227 "installationTemplates" => "loadInstallationTemplates",
228 "installationMethods" => "loadInstallationMethods",
229 "locales" => "getSystemLocales" ) as $target => $func){
230 $$target = $this->$func();
231 if($$target == NULL){
232 $this->initFailed = TRUE;
233 msg_dialog::display(_("Error"), msgPool::rpcError($this->rpcErrorMessage), ERROR_DIALOG);
234 return;
235 }
236 }
238 // Assign fetchted values
239 $this->timezones = $timeozones;
240 $this->installBootstrapMethodList = $installationMethods['installBootstrapMethodList'];
241 $this->installConfigManagementList = $installationMethods['installConfigManagementList'];
242 $this->installSystemLocaleList = $locales;
243 $this->installKeyboardlayoutList = $keyboardLayouts;
244 $this->distributions = $distributions;
246 # Create template to relase map
247 $this->templateToRelease = array();
249 // Walk through installation templates and use the 'repositories' attribute
250 // to supported releases.
251 foreach($installationTemplates as $name => $tdata){
253 $mName = isset($this->installBootstrapMethodList[$tdata['method']]) ?
254 $this->installBootstrapMethodList[$tdata['method']]: $tdata['method'];
256 $this->installationTemplateNames[$name] = $tdata['description']." (".$mName.")";
257 $this->installationTemplates[$name] = $tdata;
258 $this->templateToRelease[$name] = array();
260 // Check if the 'repository'-category of the template can be found in any
261 // received release list.
262 if(isset($installationMethods[$tdata['method']]['repositories'])){
263 $repos = $installationMethods[$tdata['method']]['repositories'];
264 foreach($distributions as $dist){
265 if(in_array($dist['type']['name'],$repos) && isset($dist['releases'])){
266 foreach($dist['releases'] as $release){
267 $rname = $dist['name'].'/'.$release['name'];
268 $this->templateToRelease[$name][$rname] = $rname;
269 }
270 }
271 }
272 }
273 }
274 }
277 function check()
278 {
279 // Check if the parents deviceUUID has changed
280 if($this->deviceUUID != $this->_device->deviceUUID){
281 $this->deviceUUID = $this->_device->deviceUUID;
282 print "The device uuid has changed.";
283 }
284 }
287 function execute()
288 {
289 // Log account access
290 if($this->is_account && !$this->view_logged){
291 $this->view_logged = TRUE;
292 new log("view","Device/".get_class($this),$this->dn);
293 }
295 /***************
296 Handle account state
297 ***************/
299 // Allow to add or remove the distribution list extension
300 if(isset($_POST['modify_state'])){
301 if($this->is_account && $this->acl_is_removeable()){
302 $this->is_account= FALSE;
303 }elseif(!$this->is_account && $this->acl_is_createable()){
304 $this->is_account= TRUE;
305 }
306 }
308 // Show account status-changer
309 $display = "";
310 if ($this->parent !== NULL){
311 if ($this->is_account){
312 $display= $this->show_disable_header(_("Remove install profile"),
313 msgPool::featuresEnabled(_("Install profile")));
314 } else {
315 $display= $this->show_enable_header(_("Add install profile"),
316 msgPool::featuresDisabled(_("Install profile")));
317 return ($display);
318 }
319 }
321 /***************
322 Root password hash dialog
323 ***************/
325 $this->dialog = FALSE;
326 if($this->setPasswordHash){
327 $this->dialog = TRUE;
328 $smarty = get_smarty();
329 $smarty->assign('hashes', set_post($this->hashes));
330 $smarty->assign('hash', set_post($this->hash));
331 return($smarty->fetch(get_template_path('goto/Device/SetPassword.tpl', TRUE)));
332 }
334 /***************
335 Partition dialog
336 ***************/
338 if(isset($_POST['partition_finish']) && $this->partitionEdit){
339 $this->installPartitionTable = $this->partitionEdit->save();
340 $this->partitionEdit = NULL;
341 }
342 if(isset($_POST['partition_cancel']) && $this->partitionEdit){
343 $this->partitionEdit = NULL;
344 }
345 if(isset($_POST['edit_installPartitionTable'])){
346 $this->partitionEdit = new DevicePartition($this->config, $this->installPartitionTable);
347 }
348 if($this->partitionEdit){
349 $this->partitionEdit->save_object();
350 $this->dialog = TRUE;
351 return($this->partitionEdit->execute());
352 }
356 /***************
357 Generate HTML content
358 ***************/
360 $this->installNTPServerList->setAcl($this->getacl('installNTPServer'));
361 $this->installNTPServerList->update();
363 plugin::execute();
364 $smarty = get_smarty();
365 $smarty->assign('installTemplateList', $this->installationTemplateNames);
366 $smarty->assign('installReleaseList', $this->templateToRelease[$this->installTemplate]);
369 $smarty->assign('timezones', $this->timezones);
370 $smarty->assign('installKeyboardlayoutList', $this->installKeyboardlayoutList);
371 $smarty->assign('installKernelPackageList', $this->installKernelPackageList);
372 $smarty->assign('installMirrorList', $this->installMirrorList);
373 $smarty->assign('installSystemLocaleList', $this->installSystemLocaleList);
374 $smarty->assign('installNTPServerList', $this->installNTPServerList->render());
376 $smarty->assign('installBootstrapMethod', $this->installBootstrapMethod);
377 $smarty->assign('installBootstrapMethodList', $this->installBootstrapMethodList);
378 $smarty->assign('installConfigManagement', $this->installConfigManagement);
380 // Assign list of available config-management types.
381 if(isset($this->installConfigManagementList[$this->installBootstrapMethod])){
382 $smarty->assign('installConfigManagementList', $this->installConfigManagementList[$this->installBootstrapMethod]);
383 }else{
384 $smarty->assign('installConfigManagementList', array());
385 }
387 foreach($this->attributes as $attr){
388 $smarty->assign($attr, $this->$attr);
389 }
390 $this->dialog = false;
391 return($display.$smarty->fetch(get_template_path('goto/Device/InstallRecipe.tpl', TRUE)));
392 }
395 function save_object()
396 {
397 if(isset($_POST['InstallRecipePosted'])){
399 $currentInstallMethod = $this->installConfigManagement;
401 $oldRelease = $this->installRelease;
402 plugin::save_object();
403 $this->installRootEnabled = isset($_POST['installRootEnabled']);
404 $this->installTimeUTC = isset($_POST['installTimeUTC']);
407 if(isset($_POST['setPasswordHash'])){
408 $this->setPasswordHash = true;
409 }
411 $this->installNTPServerList->save_object();
412 $this->installNTPServer = $this->installNTPServerList->getMaintainedData();
413 if(isset($_POST['installNTPServer_Input']) && isset($_POST['installNTPServer_Add'])){
414 $add = get_post('installNTPServer_Input');
415 if(!in_array($add, $this->installNTPServer) && !empty($add)){
416 $this->installNTPServer[] = $add;
417 }
418 }
419 $this->installNTPServerList->setListData($this->installNTPServer);
420 $this->installBootstrapMethod = $this->installationTemplates[$this->installTemplate]['method'];
422 // The selected release is no longer available for the current template
423 if(!in_array($this->installRelease, $this->templateToRelease[$this->installTemplate])){
424 $this->installRelease = key($this->templateToRelease[$this->installTemplate]);
425 }
427 // Reload list of kernel packages and mirrors
428 if($oldRelease != $this->installRelease){
429 $this->reloadInstallationKernelPackages();
430 $this->reloadInstallationMirrors();
431 }
432 }
434 if(isset($_POST['cancelPassword'])) $this->setPasswordHash =false;
435 if(isset($_POST['setPassword'])) {
436 $this->setPasswordHash =false;
437 $hash = get_post('passwordHash');
439 // Not sure, why this is here, but maybe some encryption methods require it.
440 mt_srand((double) microtime()*1000000);
442 // Generate the requested hash
443 $methods = new passwordMethod($this->config, $this->dn);
444 $available = $methods->get_available_methods();
445 $test = new $available[$hash]($this->config,$this->dn);
446 $this->installRootPasswordHash = @$test->generate_hash(get_post('rootPassword'));
447 }
448 }
451 function save()
452 {
453 if(!$this->installRootEnabled) $this->installRootPasswordHash = "";
455 $map = array(
456 "installNTPServer"=>'ntp-servers',
457 "installTemplate"=>'template',
458 "installRelease"=>'release',
459 "installTimezone"=>'timezone',
460 "installTimeUTC"=>'utc',
461 "installKernelPackage"=>'kernel',
462 "installSystemLocale"=>'system-locale',
463 "installRootEnabled"=>'root-user',
464 "installRootPasswordHash"=>'root-hash',
465 "installPartitionTable"=>'disk-setup',
466 "installKeyboardlayout"=>'keyboard-layout',
467 );
469 // Collect values to be saved.
470 $data = array();
471 foreach($map as $source => $dest){
472 if(!empty($this->$source)){
473 $data[$dest] = $this->$source;
474 }
475 }
477 // Enforce an array for ntp-servers
478 $data['ntp-servers'] = array_values($data['ntp-servers']);
480 // Save Boolean like a String
481 $boolean = array("root-user" => "installRootEnabled", "utc" => "installTimeUTC");
482 foreach($boolean as $attr => $source){
483 $data[$attr] = ($this->$source) ? $data[$attr] = "TRUE" : $data[$attr] = "FALSE";
484 }
486 print_a($data);
488 $rpc = $this->config->getRpcHandle();
489 $res = $rpc->systemSetBaseInstallParameters($this->deviceUUID, $data);
491 // Failed to load backend values, keep reported error and return with FALSE;
492 $this->rpcError = !$rpc->success();
493 if(!$rpc->success()){
494 $this->rpcErrorMessage = $rpc->get_error();
495 msg_dialog::display(_("Error"), msgPool::rpcError($this->rpcErrorMessage), ERROR_DIALOG);
496 return(NULL);
497 }
499 }
502 function remove_from_parent()
503 {
504 print "Missing";
505 }
508 /*! \brief Refreshes the list of selectable kernel packages.
509 */
510 function reloadInstallationKernelPackages($initially = FALSE)
511 {
512 // Do nothing if no release is given.
513 if(empty($this->installRelease)){
514 $this->installKernelPackageList = array();
515 return;
516 }
518 $rpc = $this->config->getRpcHandle();
519 $res = $rpc->getKernelPackages($this->installRelease);
521 // Failed to load backend values, keep reported error and return with FALSE;
522 $this->rpcError = !$rpc->success();
523 if(!$rpc->success()){
524 $this->rpcErrorMessage = $rpc->get_error();
525 msg_dialog::display(_("Error"), msgPool::rpcError($this->rpcErrorMessage), ERROR_DIALOG);
526 }else{
527 $this->installKernelPackageList = array();
528 foreach($res as $name){
529 $this->installKernelPackageList[$name] = $name;
530 }
532 if(!isset($this->installKernelPackageList[$this->installKernelPackage])){
533 $new = key($this->installKernelPackageList);
534 if($initially){
535 msg_dialog::display(_("Warning"), sprintf(_("The selected kernel package '%s' is no longer available! The kernel package '%s' was selected as replacement!"), $this->installKernelPackage, $new), WARNING_DIALOG);
536 }
537 $this->installKernelPackage = $new;
538 }
539 }
540 }
543 /*! \brief Returns a list of distributions on success.
544 * In case of an error, it returns NULL.
545 */
546 function loadDistributions()
547 {
548 $rpc = $this->config->getRpcHandle();
549 $res = $rpc->getDistributions();
551 // Failed to load backend values, keep reported error and return with FALSE;
552 $this->rpcError = !$rpc->success();
553 if(!$rpc->success()){
554 $this->rpcErrorMessage = $rpc->get_error();
555 return(NULL);
556 }
557 return($res);
558 }
561 /*! \brief Returns a list of timezones on success.
562 * In case of an error, it returns NULL.
563 */
564 function getTimezones()
565 {
566 $rpc = $this->config->getRpcHandle();
567 $res = $rpc->getTimezones();
569 // Failed to load backend values, keep reported error and return with FALSE;
570 $this->rpcError = !$rpc->success();
571 if(!$rpc->success()){
572 $this->rpcErrorMessage = $rpc->get_error();
573 return(NULL);
574 }
575 return($res);
576 }
579 /*! \brief Returns a list of installation mirrors on success.
580 * In case of an error, it returns NULL.
581 */
582 function reloadInstallationMirrors($initially = FALSE)
583 {
584 $res = array(
585 'dc=intranet,dc=gonicus,dc=de' => 'Intranet',
586 'ou=systems,dc=intranet,dc=gonicus,dc=de' => 'System');
587 $this->installMirrorList =$res;
588 }
591 /*! \brief Returns a list of installation templates on success.
592 * In case of an error, it returns NULL.
593 */
594 function loadInstallationTemplates()
595 {
596 $rpc = $this->config->getRpcHandle();
597 $res = $rpc->installListTemplates();
599 // Failed to load backend values, keep reported error and return with FALSE;
600 $this->rpcError = !$rpc->success();
601 if(!$rpc->success()){
602 $this->rpcErrorMessage = $rpc->get_error();
603 return(NULL);
604 }
605 return($res);
606 }
609 /*! \brief Returns a list of keyboard layouts on success.
610 * In case of an error, it returns NULL.
611 */
612 function loadInstallationKeyboardLayouts()
613 {
614 $rpc = $this->config->getRpcHandle();
615 $res = $rpc->getKeyboardModels();
617 // Failed to load backend values, keep reported error and return with FALSE;
618 $this->rpcError = !$rpc->success();
619 if(!$rpc->success()){
620 $this->rpcErrorMessage = $rpc->get_error();
621 return(NULL);
622 }
623 $lay = array();
624 foreach($res as $key => $data){
625 $lay[$key] = "{$data[0]} - {$data[2]}";
626 }
627 asort($lay);
628 return($lay);
629 }
632 /*! \brief Returns a list of system locales on success.
633 * In case of an error, it returns NULL.
634 */
635 function getSystemLocales()
636 {
637 $rpc = $this->config->getRpcHandle();
638 $res = $rpc->getSystemLocales();
640 // Failed to load backend values, keep reported error and return with FALSE;
641 $this->rpcError = !$rpc->success();
642 if(!$rpc->success()){
643 $this->rpcErrorMessage = $rpc->get_error();
644 msg_dialog::display(_("Error"), msgPool::rpcError($this->rpcErrorMessage), ERROR_DIALOG);
645 return(NULL);
646 }
648 return($res);
649 }
652 /*! \brief Try to load install and bootstrap methods from the GOsa-backend
653 * This is done via jsonRPC, if calling the backend method fails,
654 * this method returns FALSE, in case of success it return TRUE;
655 */
656 function loadInstallationMethods()
657 {
658 $rpc = $this->config->getRpcHandle();
659 $res = $rpc->getSupportedBaseInstallMethods();
661 // Failed to load backend values, keep reported error and return with FALSE;
662 $this->rpcError = !$rpc->success();
663 if(!$rpc->success()){
664 $this->rpcErrorMessage = $rpc->get_error();
665 return(NULL);
666 }
668 // Walk through result and set bootstrap methods.
669 foreach($res as $name => $method){
670 $res['installBootstrapMethodList'][$name] = $method['name'];
671 foreach($method['methods'] as $m){
672 $res['installConfigManagementList'][$name][$m] = $m;
673 }
674 }
675 return($res);
676 }
679 static function plInfo()
680 {
681 return (array(
682 "plShortName" => _("Device"),
683 "plDescription" => _("Registered device"),
684 "plSelfModify" => FALSE,
685 "plDepends" => array(),
686 "plPriority" => 1,
687 "plSection" => array("administration"),
688 "plCategory" => array("Device"),
689 "plProvidedAcls" => array(
690 "member" => _("Member"),
691 "installTemplate" => _("Installation template"),
692 "installRelease" => _("Installation release"),
694 "installBootstrapMethod" => _("Bootstrap method"),
695 "installConfigManagement" => _("Config management"),
696 "installKeyboardlayout" => _("Keyboard layout"),
697 "installSystemLocale" => _("System locale"),
698 "installTimezone" => _("Timezone"),
699 "installTimeUTC" => _("Time"),
700 "installNTPServer" => _("NTP-Server"),
701 "installMirror" => _("Mirror"),
702 "installRootEnabled" => _("Root login enabled"),
703 "installRootPasswordHash" => _("Root password hash"),
704 "installKernelPackage" => _("Kernel package"),
705 "installPartitionTable" => _("Partition table")
706 )
707 )
708 );
709 }
710 }
711 ?>