gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r33105 - in eclectic: . gplmt-ui


From: gnunet
Subject: [GNUnet-SVN] r33105 - in eclectic: . gplmt-ui
Date: Thu, 17 Apr 2014 11:25:12 +0200

Author: wachs
Date: 2014-04-17 11:25:12 +0200 (Thu, 17 Apr 2014)
New Revision: 33105

Added:
   eclectic/gplmt-ui/
   eclectic/gplmt-ui/README
   eclectic/gplmt-ui/zabbix.diff
Log:
diff for web ui


Added: eclectic/gplmt-ui/README
===================================================================
--- eclectic/gplmt-ui/README                            (rev 0)
+++ eclectic/gplmt-ui/README    2014-04-17 09:25:12 UTC (rev 33105)
@@ -0,0 +1,4 @@
+GPLMT Web UI
+============
+
+This is a diff which has to be applied against Zabbix version 2.2
\ No newline at end of file

Added: eclectic/gplmt-ui/zabbix.diff
===================================================================
--- eclectic/gplmt-ui/zabbix.diff                               (rev 0)
+++ eclectic/gplmt-ui/zabbix.diff       2014-04-17 09:25:12 UTC (rev 33105)
@@ -0,0 +1,3212 @@
+diff --git a/zabbix/data.sql b/zabbix/data.sql
+new file mode 100644
+index 0000000..c2b36b6
+--- /dev/null
++++ b/zabbix/data.sql
+@@ -0,0 +1,54 @@
++-- phpMyAdmin SQL Dump
++-- version 3.4.11.1deb2
++-- http://www.phpmyadmin.net
++--
++-- Host: localhost
++-- Generation Time: Sep 26, 2013 at 04:40 PM
++-- Server version: 5.5.31
++-- PHP Version: 5.4.4-14+deb7u4
++
++SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
++SET time_zone = "+00:00";
++
++
++/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
++/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
++/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
++/*!40101 SET NAMES utf8 */;
++
++--
++-- Database: `zabbix`
++--
++
++--
++-- Dumping data for table `exp_config`
++--
++
++INSERT INTO `exp_config` (`configid`, `section`, `name`, `label`, 
`description`, `type`, `default_value`, `user_editable`) VALUES
++(1, 'ssh', 'ssh_username', 'SSH username', 'Username for SSH access', 'text', 
'', 1),
++(2, 'ssh', 'ssh_password', 'SSH password', 'Password for SSH access or 
password for the SSH keyfile', 'password', '', 1),
++(3, 'ssh', 'ssh_keyfile', 'SSH keyfile', 'SSH key for login', 'file', '', 1),
++(16, 'gplmt', 'notification', 'Notification', 'Which notification mechanism 
to use: simple, result', 'text', 'result', 0),
++(17, 'gplmt', 'max_parallelism', 'Max Parallelism', 'Number of parallel 
workers, use 0 for unlimited', 'integer', '10', 0),
++(18, 'planetlab', 'slice', 'Planetlab Slice', 'Name of your PlanetLab Slice', 
'text', '', 1),
++(20, 'planetlab', 'api_url', 'PLC/PLE', 'Use PlanetLab Central or PlanetLab 
Europe', 'enum', 'https://www.planet-lab.eu/PLCAPI/', 1),
++(21, 'planetlab', 'username', 'PlanetLab API username', 'Your login to the 
planetlab website\r\nto access the planetlab API', 'text', '', 1),
++(22, 'planetlab', 'password', 'PlanetLab API password', 'Your password for 
the planetlab\r\nwebsite to access the planetlab API', 'password', '', 1),
++(25, 'ssh', 'ssh_transfer', 'SSH Transfer', 'Protocol for put get operations: 
scp, sftp', 'text', 'scp', 0),
++(26, 'ssh', 'ssh_use_known_hosts', 'SSH: Use Known Hosts', 'Use system''s SSH 
"known hosts" file', 'boolean', 'yes', 0),
++(27, 'ssh', 'add_unkown_hostkeys', 'SSH: Add Unknown Hostkeys', 'Add node 
hostkeys automatically', 'boolean', 'yes', 0),
++(28, 'gplmt', 'userdir', 'User Directory', 'User specific directory for 
put/get operations', 'text', '', 0);
++
++INSERT INTO `zabbix`.`exp_config` (`configid`, `section`, `name`, `label`, 
`description`, `type`, `default_value`, `user_editable`) VALUES (NULL, 
'planetlab', 'pl_keyfile', 'Planetlab keyfile', 'Private key file for 
connecting to planetlab nodes', 'file', '', '1'), (NULL, 'planetlab', 
'pl_keyfile_password', 'Planetlab keyfile password', 'Password used to unlock 
private key file (if needed)', 'password', '', '1');
++
++--
++-- Dumping data for table `exp_configenum`
++--
++
++INSERT INTO `exp_configenum` (`id`, `configid`, `label`, `value`) VALUES
++(1, 20, 'Planetlab Central', 'https://www.planet-lab.org/PLCAPI/'),
++(2, 20, 'Planetlab Europe', 'https://www.planet-lab.eu/PLCAPI/');
++
++/*!40101 SET address@hidden */;
++/*!40101 SET address@hidden */;
++/*!40101 SET address@hidden */;
+diff --git a/zabbix/frontends/php/conf.php b/zabbix/frontends/php/conf.php
+new file mode 100644
+index 0000000..c88d8a6
+--- /dev/null
++++ b/zabbix/frontends/php/conf.php
+@@ -0,0 +1,31 @@
++<?php
++
++require_once dirname(__FILE__).'/include/config.inc.php';
++require_once dirname(__FILE__).'/include/experiments/inc.php';
++
++$page['title'] = _('User Configuration');
++$page['file'] = 'conf.php';
++$page['hist_arg'] = array('confid');
++
++require_once dirname(__FILE__).'/include/page_header.php';
++
++/*
++ * Actions
++ */
++if(isset($_REQUEST['update']))
++{
++    //print_r($_REQUEST);
++    expconfig_update($_REQUEST);
++}
++
++/*
++ * Display
++ */
++$filesView = new CView('experiments.conf');
++
++$filesView->set('conf', expconfig_getuserconfig());
++
++$filesView->render();
++$filesView->show();
++
++require_once dirname(__FILE__).'/include/page_footer.php';
+diff --git a/zabbix/frontends/php/dashboard.php 
b/zabbix/frontends/php/dashboard.php
+index fe17a67..e71abb8 100644
+--- a/zabbix/frontends/php/dashboard.php
++++ b/zabbix/frontends/php/dashboard.php
+@@ -253,6 +253,11 @@ insert_js('var page_menu='.zbx_jsvalue($menu).";\n".'var 
page_submenu='.zbx_jsva
+  */
+ $leftColumn = array();
+ 
++// Manage monitoring
++$manage_wdgt = new CUIWidget('hat_managemonitoring', 
make_manage_monitoring(), 1);
++$manage_wdgt->setHeader(_('Manage Monitoring'));
++$leftColumn[] = $manage_wdgt;
++
+ // favorite graphs
+ $graph_menu = get_icon('menu', array('menu' => 'graphs'));
+ $fav_grph = new CUIWidget('hat_favgrph', make_favorite_graphs(), 
CProfile::get('web.dashboard.hats.hat_favgrph.state', 1));
+@@ -297,6 +302,12 @@ if ($USER_DETAILS['type'] == USER_TYPE_SUPER_ADMIN) {
+       $rightColumn[] = $zbxStatus;
+ }
+ 
++// run scripts
++$scripts_wdgt = new CUIWidget('hat_runscripts', make_run_scripts(), 1);
++$scripts_wdgt->setHeader(_('Run Scripts'));
++//$scripts_wdgt->setFooter(new CLink(_('Graphs').' &raquo;', 'charts.php', 
'highlight'), true);
++$rightColumn[] = $scripts_wdgt;
++
+ // system status
+ $refresh_menu = new CIcon(_('Menu'), 'iconmenu', 
'create_page_menu(event,"hat_syssum");');
+ $sys_stat = new CUIWidget('hat_syssum', new CSpan(_('Loading...'), 
'textcolorstyles'), CProfile::get('web.dashboard.hats.hat_syssum.state', 1));
+diff --git a/zabbix/frontends/php/execute.php 
b/zabbix/frontends/php/execute.php
+new file mode 100644
+index 0000000..0428d3e
+--- /dev/null
++++ b/zabbix/frontends/php/execute.php
+@@ -0,0 +1,69 @@
++<?php
++
++require_once dirname(__FILE__).'/include/config.inc.php';
++require_once dirname(__FILE__).'/include/experiments/inc.php';
++
++$page['title'] = _('Deploy & Execute');
++$page['file'] = 'execute.php';
++$page['hist_arg'] = array('execid');
++
++require_once dirname(__FILE__).'/include/page_header.php';
++
++// VAR        TYPE    OPTIONAL        FLAGS   VALIDATION      EXCEPTION
++/*$fields = array(
++      'run' =>                array(T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, 
null),
++      'nodes' =>              array(T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, 
'isset({run})'),
++      'usetasklist' =>   array(T_ZBX_INT, O_OPT, P_SYS|P_ACT, IN('0,1'), 
'isset({run})'),
++      'tasklist' =>   array(T_ZBX_INT, O_OPT, P_SYS|P_ACT, null, 
'isset({run})'),
++      'cmd' =>   array(T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, 'isset({run})'),
++      'sync' =>   array(T_ZBX_INT, O_OPT, null, null, null)
++);
++check_fields($fields);*/
++
++
++/*
++ * Actions
++ */
++
++if(isset($_REQUEST['run']))
++{
++    $usetasklist = intval($_REQUEST['usetasklist']);
++    $tasklist = intval($_REQUEST['tasklist']);
++
++    $cmd = trim($_REQUEST['cmd']);
++    $cmd_empty = empty($cmd);
++    
++    if($usetasklist == 0 && $cmd_empty)
++        error("Please specify the command to run.");
++    elseif(!isset($_REQUEST['target']))
++        error("Please specify target.");
++    elseif(!isset($_REQUEST['hosts']) || count($_REQUEST['hosts']) == 0)
++        error("Please specify hosts to run");
++    else
++    {
++        $res = exprun_new($_REQUEST['target'], $_REQUEST['hosts'], 
$usetasklist, $tasklist, $cmd);
++        if($res == EXP_ERR_GPLMT_DIR)
++            error("Could not verify GPLMT files, please make sure that they 
exist and write permissions are enabled.");
++        elseif($res == EXP_ERR_PERMISSION)
++            error("Permission error.");
++        elseif($res == EXP_ERR_INVALID_TARGET)
++            error("Invalid target!");
++        else
++            jsRedirect('results.php');
++    }
++}
++
++/*
++ * Display
++ */
++
++$execView = new CView('experiments.execute');
++
++$execView->set('tasklists', exptasklist_getall());
++$execView->set('targets', $exp_targetlist);
++$execView->set('currenttarget', 
isset($_REQUEST['target'])?$_REQUEST['target']:reset($exp_targetlist));
++
++$execView->render();
++$execView->show();
++
++require_once dirname(__FILE__).'/include/page_footer.php';
+diff --git a/zabbix/frontends/php/files.php b/zabbix/frontends/php/files.php
+new file mode 100644
+index 0000000..5326ccc
+--- /dev/null
++++ b/zabbix/frontends/php/files.php
+@@ -0,0 +1,58 @@
++<?php
++
++require_once dirname(__FILE__).'/include/config.inc.php';
++require_once dirname(__FILE__).'/include/experiments/inc.php';
++
++$page['title'] = _('User Files');
++$page['file'] = 'files.php';
++$page['hist_arg'] = array('fileid');
++
++//before any headers are written, check if trying to download
++if(isset($_REQUEST['download']))
++{
++    $filename = $_REQUEST['download'];
++    
++    expfiles_download($filename);
++}
++
++require_once dirname(__FILE__).'/include/page_header.php';
++
++// VAR        TYPE    OPTIONAL        FLAGS   VALIDATION      EXCEPTION
++/*$fields = array(
++);
++check_fields($fields);*/
++
++/*
++ * Actions
++ */
++if(isset($_REQUEST['upload']) && isset($_FILES['file']))
++{
++    //some validations
++    if($_FILES["file"]["error"] > 0)
++        error('File upload error: '.$_FILES["file"]["error"]);
++    else
++    {
++        $filename = $_FILES["file"]["name"];
++        $fullpath = expfiles_getnewfilepath($filename);
++        move_uploaded_file($_FILES["file"]["tmp_name"], $fullpath);
++        
++        info("File uploaded successfully.");
++    }
++}
++if(isset($_REQUEST['delete']))
++{
++    if(expfiles_delete($_REQUEST['delete'])) jsRedirect('files.php');
++}
++
++/*
++ * Display
++ */
++$filesView = new CView('experiments.files');
++
++$filesView->set('files', expfiles_getuserfiles());
++
++$filesView->render();
++$filesView->show();
++
++
++require_once dirname(__FILE__).'/include/page_footer.php';
+diff --git a/zabbix/frontends/php/images/general/question_mark.png 
b/zabbix/frontends/php/images/general/question_mark.png
+new file mode 100644
+index 0000000..8dee9d0
+Binary files /dev/null and 
b/zabbix/frontends/php/images/general/question_mark.png differ
+diff --git a/zabbix/frontends/php/include/blocks.inc.php 
b/zabbix/frontends/php/include/blocks.inc.php
+index 3896140..7b1321a 100644
+--- a/zabbix/frontends/php/include/blocks.inc.php
++++ b/zabbix/frontends/php/include/blocks.inc.php
+@@ -1401,3 +1401,174 @@ function makeTriggersPopup(array $triggers, array 
$ackParams) {
+ 
+       return $popupTable;
+ }
++
++function make_run_scripts()
++{
++      //create big table
++      $bigTable = new CTableInfo();
++      
++    //create table 1
++    $scriptsTable = new CTableInfo(_('No scripts defined.'));
++    $scriptsTable->setHeader(array(
++          _('Name'),
++          _('Run on Host'),
++          _('Run on Host Group')
++    ));
++    
++    //get list of scripts
++    $scripts = API::Script()->get(array(
++              'output' => array('name')
++      ));
++      
++      //get list of hosts
++      $hosts = API::Host()->get(array(
++              'sortfield' => 'name',
++              'output' => array('name')
++      ));
++      
++      //get list of host groups
++    $hostgroups = API::HostGroup()->get(array(
++              'sortfield' => 'name',
++              'output' => array('name')
++      ));
++      
++      //add rows
++      foreach($scripts as $script)
++      {
++          //create hostgroups combobox & run button
++        $runForm = new CForm('GET', 'scripts_exec.php');
++        $runForm->attr("target", "_blank");
++        $runForm->addItem(new CInput('hidden', 'execute', '1'));
++        $runForm->addItem(new CInput('hidden', 'scriptid', 
$script['scriptid']));
++        
++        $grpsComboBox = new CComboBox('groupid');
++        foreach($hostgroups as $hostgroup)
++            $grpsComboBox->addItem(new CComboItem($hostgroup['groupid'], 
$hostgroup['name']));
++
++        $runForm->addItem($grpsComboBox);
++        $runForm->addItem(new CInput('submit', 'submit', 'Run'));
++        
++        //create hosts combobox & run button
++        $runFormHosts = new CForm('GET', 'scripts_exec.php');
++        $runFormHosts->attr("target", "_blank");
++        $runFormHosts->addItem(new CInput('hidden', 'execute', '1'));
++        $runFormHosts->addItem(new CInput('hidden', 'scriptid', 
$script['scriptid']));
++        
++        $hostsComboBox = new CComboBox('hostid');
++        foreach($hosts as $host)
++            $hostsComboBox->addItem(new CComboItem($host['hostid'], 
$host['name']));
++
++        $runFormHosts->addItem($hostsComboBox);
++        $runFormHosts->addItem(new CInput('submit', 'submit', 'Run'));
++        
++        $scriptsTable->addRow(array(
++                  new CLink($script['name'], 
'scripts.php?form=1&scriptid='.$script['scriptid']),
++                  $runFormHosts,
++                  $runForm
++          ));
++      }
++      
++      //create multiple run form
++      $multForm = new CFormTable(null, 'scripts_exec.php', 'GET');
++      
++      $scriptsCmbbox = new CComboBox('scriptid');
++      foreach($scripts as $script)
++              $scriptsCmbbox->addItem(new CComboItem($script['scriptid'], 
$script['name']));
++      
++      $hostsListBox = new CListBox('hosts[]', null, 15);
++      foreach($hosts as $host)
++        $hostsListBox->addItem(new CComboItem($host['hostid'], 
$host['name']));
++    
++    $multForm->addRow($scriptsCmbbox);
++    $multForm->addRow($hostsListBox);
++    $multForm->attr("target", "_blank");
++    $multForm->addRow(new CInput('hidden', 'execute', '1'), new 
CInput('submit', 'submit', 'Run'));
++    
++    $bigTable->addRow(array(
++      $scriptsTable,
++      $multForm
++    ));
++    
++    return $bigTable;
++}
++
++function template_items_status($template_id)
++{
++      //fetch main template    
++    $options = array(
++              'templateids' => array($template_id),
++              'selectItems' => array('status'),
++              'output' => array('name')
++      );
++
++      $template = API::Template()->get($options);
++      
++      $total = 0;
++      $enabled = 0;
++      
++      foreach($template[0]['items'] as $item)
++      {
++              $total++;
++              if($item['status'] == 0) $enabled++;
++      }
++      
++      return array('total' => $total, 'enabled' => $enabled);
++}
++
++function make_manage_monitoring()
++{
++    $templates = array(10001, 10176, 10177);
++    
++    //fetch important templates
++    $options = array(
++              'templateids' => $templates,
++              'output' => array('name')
++      );
++      $templates = API::Template()->get($options);
++      
++      //create link/unlink all forms
++      $linkAllForm = new CForm('POST', 'manage_monitoring.php');
++      $unlinkAllForm = new CForm('POST', 'manage_monitoring.php');
++      foreach($templates as $temp)
++      {
++              $linkAllForm->addItem(new CInput('hidden', 
'template['.$temp['hostid'].']', $temp['hostid']));
++              $unlinkAllForm->addItem(new CInput('hidden', 
'template['.$temp['hostid'].']', $temp['hostid']));
++      }
++      $linkAllForm->addItem(new CInput('submit', 'submit', 'Enable All'));
++    $linkAllForm->addItem(new CInput('hidden', 'action', 'enable'));
++
++      $unlinkAllForm->addItem(new CInput('submit', 'submit', 'Disable All'));
++    $unlinkAllForm->addItem(new CInput('hidden', 'action', 'disable'));
++      
++      //table that will contain forms
++      $table = new CTable();
++      
++      foreach($templates as $template)
++      {
++              $items_status = template_items_status($template['hostid']);
++              
++          $r = new CRow();
++          $r->addItem(new CLabel($template['name'] . ' [' . 
$items_status['enabled'] . '/' . $items_status['total'] . ']'));
++          
++          $enableForm = new CForm('POST', 'manage_monitoring.php');
++          $enableForm->addItem(new CInput('hidden', 
'template['.$template['hostid'].']', $template['hostid']));
++          $enableForm->addItem(new CInput('submit', 'submit', 'Disable'));
++        $enableForm->addItem(new CInput('hidden', 'action', 'disable'));
++          
++          $disableForm = new CForm('POST', 'manage_monitoring.php');
++        $disableForm->addItem(new CInput('hidden', 
'template['.$template['hostid'].']', $template['hostid']));
++      $disableForm->addItem(new CInput('submit', 'submit', 'Enable'));
++      $disableForm->addItem(new CInput('hidden', 'action', 'enable'));
++
++          $r->addItem($enableForm);        
++          $r->addItem($disableForm);
++          
++          $table->addRow($r);
++      }
++      $totalRows = new CRow();
++      $totalRows->addItem($linkAllForm);
++      $totalRows->addItem($unlinkAllForm);
++      $table->addRow($totalRows);
++      
++      return $table;
++}
+diff --git a/zabbix/frontends/php/include/experiments/conf.php 
b/zabbix/frontends/php/include/experiments/conf.php
+new file mode 100644
+index 0000000..9bef025
+--- /dev/null
++++ b/zabbix/frontends/php/include/experiments/conf.php
+@@ -0,0 +1,9 @@
++<?php
++
++$GLOBALS['GPLMT_DIR'] = '/home/omar/workspace/gnunet-planetlab/gplmt/';
++
++$GLOBALS['GPLMT_TASKLISTS_DIR'] = $GLOBALS['GPLMT_DIR'].'contrib/tasklists/';
++$GLOBALS['GPLMT_CONF_DIR'] = $GLOBALS['GPLMT_DIR'].'contrib/configurations/';
++$GLOBALS['GPLMT_NODES_DIR'] = $GLOBALS['GPLMT_DIR'].'contrib/nodes/';
++$GLOBALS['GPLMT_RESULTS_DIR'] = $GLOBALS['GPLMT_DIR'].'contrib/results/';
++$GLOBALS['GPLMT_FILES_DIR'] = $GLOBALS['GPLMT_DIR'].'contrib/files/';
+diff --git a/zabbix/frontends/php/include/experiments/config.php 
b/zabbix/frontends/php/include/experiments/config.php
+new file mode 100644
+index 0000000..1e4ed5a
+--- /dev/null
++++ b/zabbix/frontends/php/include/experiments/config.php
+@@ -0,0 +1,106 @@
++<?php
++
++function expconfig_update($data)
++{
++    //get user editable config
++    $editable = expconfig_getuserconfig();
++    
++    foreach($data as $k => $v)
++    {
++        if(!isset($editable[$k])) continue;
++        $v = trim($v);
++        $enabled = ($v != '');
++        
++        if(($editable[$k]['type'] == 'file') && $enabled)
++            $v = expfiles_getuserdir().exp_cleanfilename($v);
++        
++        expdb_update('exp_userconfig',
++            array('value' => $v, 'enabled' => strval($enabled)),
++            array('configid' => $k, 'userid' => CWebUser::$data['userid']));
++    }
++    
++    expconfig_writefile();
++}
++
++function expconfig_getconfigbyname($configname)
++{
++    $uid = CWebUser::$data['userid'];
++    $sql = "SELECT exp_userconfig.value, exp_userconfig.enabled
++        FROM exp_config, exp_userconfig
++        WHERE exp_config.configid = exp_userconfig.configid
++        AND exp_config.name = '$configname'
++        AND exp_userconfig.userid = $uid";
++    $result = DBfetchArray(DBselect($sql));
++    if(count($result) == 0) return null;
++    if(!$result[0]['enabled']) return null;
++    return $result[0]['value'];
++}
++
++function expconfig_getuserconfig($editableOnly = true)
++{
++    $uid = CWebUser::$data['userid'];
++    $sql = "SELECT u.configid, c.section, c.name, c.label, c.description, 
c.type, u.value
++            FROM exp_config c, exp_userconfig u
++            WHERE c.configid = u.configid
++            AND c.user_editable = 1
++            AND u.userid = $uid
++            ORDER BY c.section, c.configid";
++    return DBfetchArrayAssoc(DBselect($sql), 'configid');
++}
++
++function expconfig_getenum($configid)
++{
++    return expdb_select('exp_configenum', array('configid' => $configid));
++}
++
++function expconfig_writefile()
++{
++    $uid = CWebUser::$data['userid'];
++    $sql = "SELECT c.section, c.name, u.value
++            FROM exp_config c, exp_userconfig u
++            WHERE c.configid = u.configid
++            AND u.enabled = 1
++            AND u.userid = $uid
++            ORDER BY c.section";
++    $conf = DBfetchArray(DBselect($sql));
++    
++    $filename = $GLOBALS['GPLMT_CONF_DIR'].strval($uid);
++    $f = fopen($filename, 'w+');
++    $current_sec = '';
++    
++    foreach($conf as $c)
++    {
++        if($c['section'] != $current_sec)
++        {
++            $current_sec = $c['section'];
++            fwrite($f, "[$current_sec]\n");
++        }
++        $k = $c['name'];
++        $v = $c['value'];
++        fwrite($f, "$k = $v\n");
++    }
++    fclose($f);
++}
++
++function expconfig_verifyuserconfig()
++{
++    $uid = CWebUser::$data['userid'];
++    $default_config = expdb_select('exp_config', array(), 'configid');
++    $user_config = expdb_select('exp_userconfig', array('userid' => $uid), 
'configid');
++    
++    if(count($default_config) == count($user_config)) return;
++    
++    foreach($default_config as $dc_k => $dc)
++    {
++        if(isset($user_config[$dc_k])) continue;
++        
++        $newval = $dc['default_value'];
++        if($dc['name'] == 'userdir') //special cases, user specific
++            $newval = expfiles_getuserdir();
++        $enabled = strval(($newval != ''));
++        
++        expdb_insert('exp_userconfig',
++            array('configid' => $dc_k, 'userid' => $uid, 'value' => $newval, 
'enabled' => $enabled));
++    }
++    expconfig_writefile();
++}
+diff --git a/zabbix/frontends/php/include/experiments/db.php 
b/zabbix/frontends/php/include/experiments/db.php
+new file mode 100644
+index 0000000..14f1b7c
+--- /dev/null
++++ b/zabbix/frontends/php/include/experiments/db.php
+@@ -0,0 +1,85 @@
++<?php
++
++function expdb_genwhere($where)
++{
++    if(sizeof($where) == 0) return '';
++    
++    $where_str = ' WHERE ';
++    
++    $first = true;
++    foreach($where as $k => $v)
++    {
++        if(!$first) $where_str .= ' AND ';
++        else $first = false;
++        $where_str .= $k.'=';
++        if(is_string($v))
++            $where_str .= ("'".mysql_real_escape_string(trim($v))."'");
++        else
++            $where_str .= $v;
++    }
++    
++    return $where_str;
++}
++
++function expdb_insert($table, $data)
++{
++    $keys_str = implode(',', array_keys($data));
++    
++    $vals = array();
++    foreach($data as $v)
++    {
++        if(is_string($v)) $vals[] = 
"'".mysql_real_escape_string(trim($v))."'";
++        else $vals[] = $v;
++    }
++    
++    $vals_str = implode(',', $vals);
++    
++    $sql = "INSERT INTO $table ($keys_str) VALUES ($vals_str)";
++    
++    DBexecute($sql);
++    return mysql_insert_id(); #TODO: mysql specific, need to be changed to be 
generic
++}
++
++function expdb_update($table, $data, $where)
++{
++    $set_str = '';
++    $first = true;
++    foreach($data as $k => $v)
++    {
++        if(!$first) $set_str .= ',';
++        else $first = false;
++        $set_str .= $k.'=';
++        if(is_string($v))
++            $set_str .= ("'".mysql_real_escape_string(trim($v))."'");
++        else
++            $set_str .= $v;
++    }
++    
++    $where_str = expdb_genwhere($where);
++    
++    $sql = "UPDATE $table SET $set_str $where_str";
++    
++    return DBexecute($sql);
++}
++
++
++function expdb_select($table, $where, $assocField = null)
++{
++    $where_str = expdb_genwhere($where);
++    
++    $sql = "SELECT * FROM $table $where_str";
++    
++    if($assocField)
++        return DBfetchArrayAssoc(DBselect($sql), $assocField);
++    else
++        return DBfetchArray(DBselect($sql));
++}
++
++function expdb_delete($table, $where)
++{
++    $where_str = expdb_genwhere($where);
++    
++    $sql = "DELETE FROM $table $where_str";
++    
++    return DBexecute($sql);
++}
+diff --git a/zabbix/frontends/php/include/experiments/files.php 
b/zabbix/frontends/php/include/experiments/files.php
+new file mode 100644
+index 0000000..a2f5fe8
+--- /dev/null
++++ b/zabbix/frontends/php/include/experiments/files.php
+@@ -0,0 +1,82 @@
++<?php
++
++/*
++ * Get the full path for the directory containing the user personal file
++ */
++function expfiles_getuserdir()
++{
++    $uid = CWebUser::$data['userid'];
++    $dir = $GLOBALS['GPLMT_FILES_DIR'].strval($uid).'/';
++    if(!file_exists($dir)) mkdir($dir);
++    return $dir;
++}
++
++/*
++ * Returns an array with the names of files inside the user personal directory
++ */
++function expfiles_getuserfiles()
++{
++    $dirpath = expfiles_getuserdir();
++    
++    $res = scandir($dirpath);
++    $res = array_diff($res, array('.', '..'));
++    return $res;
++}
++
++/*
++ * Given a file name for a new file to be uploaded, returns a full path 
++ * with the same or modified filename if already exists
++ */
++function expfiles_getnewfilepath($filename = 'new')
++{
++    $filename = exp_cleanfilename($filename);
++    $dirpath = expfiles_getuserdir();
++    
++    $parts = explode('.', $filename);
++    $orig = $parts[0];
++    
++    $counter = 0;
++    while(file_exists($dirpath.implode('.', $parts)))
++    {
++        $parts[0] = $orig.strval($counter);
++        $counter++;
++    }
++    
++    return $dirpath.implode('.', $parts);
++}
++
++function expfiles_delete($filename)
++{
++    $filename = exp_cleanfilename($filename);
++    $fullpath = expfiles_getuserdir().$filename;
++    if(file_exists($fullpath)) unlink($fullpath);
++    return true;
++}
++
++function expfiles_download($filename)
++{
++    $filename = exp_cleanfilename($filename);
++    $fullpath = expfiles_getuserdir().$filename;
++    if(!file_exists($fullpath))
++    {
++        error("File doesn't exist");
++        return false;
++    }
++    
++    $size = filesize($fullpath);
++    $mime_type="application/force-download";
++    
++    //@ob_end_clean();
++    
++    header('Content-Type: ' . $mime_type);
++    header('Content-Disposition: attachment; filename="'.$filename.'"');
++    header("Content-Transfer-Encoding: binary");
++    header('Accept-Ranges: bytes');
++    header("Cache-control: private");
++    header('Pragma: private');
++    header('Content-Length: ' . $size);
++    ob_clean();
++    flush();
++    readfile($fullpath); 
++    exit;
++}
+diff --git a/zabbix/frontends/php/include/experiments/inc.php 
b/zabbix/frontends/php/include/experiments/inc.php
+new file mode 100644
+index 0000000..0823b39
+--- /dev/null
++++ b/zabbix/frontends/php/include/experiments/inc.php
+@@ -0,0 +1,50 @@
++<?php
++
++require_once dirname(__FILE__).'/conf.php';
++require_once dirname(__FILE__).'/db.php';
++require_once dirname(__FILE__).'/tasklist.php';
++require_once dirname(__FILE__).'/run.php';
++require_once dirname(__FILE__).'/files.php';
++require_once dirname(__FILE__).'/config.php';
++require_once dirname(__FILE__).'/nodes.php';
++require_once dirname(__FILE__).'/targets.php';
++
++define('EXP_OK', '0');
++define('EXP_ERR_GPLMT_DIR', '1');
++define('EXP_ERR_PERMISSION', '2');
++define('EXP_ERR_INVALID_TARGET', '3');
++
++
++function exp_cleanfilename($filename)
++{
++    return preg_replace("/[^a-z0-9\.]/", "", strtolower($filename));
++}
++
++
++function exp_gettargets()
++{
++    $cmd = 'python '.$GLOBALS['GPLMT_DIR'].'gplmt/Targets.py';
++    $res = array();
++    exec($cmd, $res);
++    return $res;
++}
++
++function exp_verifygplmtdir()
++{
++    if(!file_exists($GLOBALS['GPLMT_DIR'].'gplmt.py'))
++    {
++        error('GPLMT path invalid!');
++        return false;
++    }
++    
++    if(!file_exists($GLOBALS['GPLMT_TASKLISTS_DIR'])) 
mkdir($GLOBALS['GPLMT_TASKLISTS_DIR']);
++    if(!file_exists($GLOBALS['GPLMT_CONF_DIR'])) 
mkdir($GLOBALS['GPLMT_CONF_DIR']);
++    if(!file_exists($GLOBALS['GPLMT_NODES_DIR'])) 
mkdir($GLOBALS['GPLMT_NODES_DIR']);
++    if(!file_exists($GLOBALS['GPLMT_RESULTS_DIR'])) 
mkdir($GLOBALS['GPLMT_RESULTS_DIR']);
++    if(!file_exists($GLOBALS['GPLMT_FILES_DIR'])) 
mkdir($GLOBALS['GPLMT_FILES_DIR']);
++    
++    return true;
++}
++
++exp_verifygplmtdir();
++expconfig_verifyuserconfig();
+diff --git a/zabbix/frontends/php/include/experiments/nodes.php 
b/zabbix/frontends/php/include/experiments/nodes.php
+new file mode 100644
+index 0000000..08a4f22
+--- /dev/null
++++ b/zabbix/frontends/php/include/experiments/nodes.php
+@@ -0,0 +1,88 @@
++<?php
++
++function expnodes_getbyrunid($run_id)
++{
++    $run_id = mysql_real_escape_string($run_id);
++    
++    $sql = "SELECT exp_host.hostid, exp_host.host
++            FROM exp_runnode, exp_host
++            WHERE exp_runnode.hostid = exp_host.hostid
++            AND exp_runnode.runid = $run_id";
++    
++    return DBfetchArray(DBselect($sql));
++}
++
++function expnodes_writefile($nodes, $run_id)
++{
++    $nodes_file = $GLOBALS['GPLMT_NODES_DIR'].$run_id;
++    
++    $f = fopen($nodes_file, 'w+');
++    foreach($nodes as $n) fwrite($f, "$n\n");
++    fclose($f);
++}
++
++function expnodes_gethosts($target)
++{
++    $userid = CWebUser::$data['userid'];
++    return expdb_select('exp_host', array('userid' => $userid, 'target' => 
$target));
++}
++
++function expnodes_gethostbyid($hostid)
++{
++    $res = expdb_select('exp_host', array('hostid' => $hostid));
++    if(count($res) == 0) return null;
++    return $res[0];
++}
++
++function expnodes_gethostinterface($hostid)
++{
++    $h = API::Host()->get(array(
++        'hostids' => $hostid,
++        'output' => array(),
++        'selectInterfaces' => API_OUTPUT_EXTEND
++    ));
++    
++    if(count($h) == 0) return '';
++    foreach($h[0]['interfaces'] as $i)
++    {
++        if($i['main'] == 1)
++        {
++            if($i['useip'] == 1) return $i['ip'];
++            else return $i['dns'];
++        }
++    }
++}
++
++function expnodes_getzabbixnodes()
++{
++    $hosts = API::Host()->get(array(
++        'output' => array('hostid', 'host'),
++        'selectInterfaces' => API_OUTPUT_EXTEND
++    ));
++    
++    $nodes = array();
++    
++    foreach($hosts as $h)
++    {
++        $n = array();
++        $n['hostid'] = $h['hostid'];
++        $n['host'] = $h['host'];
++        
++        foreach($h['interfaces'] as $i)
++        {
++            if($i['main'] == 1)
++            {
++                $n['interfaceid'] = $i['interfaceid'];
++                if($i['useip'] == 1) $n['interface'] = $i['ip'];
++                else $n['interface'] = $i['dns'];
++                
++                break;
++            }
++        }
++        
++        $nodes[] = $n;
++    }
++    
++    return $nodes;
++}
++
+diff --git a/zabbix/frontends/php/include/experiments/run.php 
b/zabbix/frontends/php/include/experiments/run.php
+new file mode 100644
+index 0000000..c0d0700
+--- /dev/null
++++ b/zabbix/frontends/php/include/experiments/run.php
+@@ -0,0 +1,290 @@
++<?php
++
++define('EXP_STATUS_FAILED', -1);
++define('EXP_STATUS_NOT_STARTED', 0);
++define('EXP_STATUS_RUNNING', 1);
++define('EXP_STATUS_DONE_WITH_ERRORS', 2);
++define('EXP_STATUS_DONE_SUCCESSFULLY', 10);
++
++function exprun_getstatusstring($status)
++{
++    switch($status)
++    {
++        case -1:
++            return "Failed";
++        case 0:
++            return "Not started";
++        case 1:
++            return "Running";
++        case 2:
++            return "Done with errors";
++        case 10:
++            return "Done successfully";
++        default:
++            return "Undefined status";
++    }
++}
++
++function exprun_getall($extended = false, $string_status = true)
++{
++    exprun_updateresults(); //update database with any new results
++
++    $where['userid'] = intval(CWebUser::$data['userid']);
++
++    $res = expdb_select('exp_run', $where);
++    
++    for($i = 0; $i < sizeof($res); $i++)
++    {
++        $sql = "SELECT exp_runnode.*, exp_host.host as interface FROM 
exp_runnode, exp_host
++                WHERE exp_runnode.runid = ".$res[$i]['runid']."
++                AND exp_runnode.hostid = exp_host.hostid
++                ORDER BY exp_runnode.status DESC, exp_runnode.percentage 
DESC, exp_host.host ASC";
++        $nodes = DBfetchArray(DBselect($sql));
++        
++        if($string_status)
++            $res[$i]['status'] = exprun_getstatusstring($res[$i]['status']);
++        
++        for($j = 0; $j < sizeof($nodes); $j++)
++        {
++            if($string_status)
++                $nodes[$j]['status'] = 
exprun_getstatusstring($nodes[$j]['status']);
++        }
++        
++        $res[$i]['nodes'] = $nodes;
++    }
++    
++    return $res;
++}
++
++function exprun_updateresults()
++{
++    $running = expdb_select('exp_run', array('status' => 1));
++    foreach($running as $r)
++    {
++        $updates = exprun_parseresult($r['runid']);
++        expdb_update('exp_run', array('status' => $updates['status'], 
'percentage' => $updates['percentage']), array('runid' => $r['runid']));
++        foreach($updates['nodes_results'] as $nr)
++        {
++            expdb_update('exp_runnode',
++                array('status' => $nr['status'], 'percentage' => 
$nr['percentage'], 'log' => $nr['log']),
++                array('runid' => $r['runid'], 'hostid' => $nr['hostid']));
++        }
++    }
++}
++
++function exprun_pidrunning($pid)
++{
++    $cmd = "ps --no-headers -p ".$pid;
++    $res = exec($cmd);
++    return !empty($res);
++}
++
++function exprun_calculatestatus($percentage, $running, $failure)
++{
++    if($percentage < 100) $status = ($running) ? EXP_STATUS_RUNNING : 
EXP_STATUS_FAILED;
++    else $status = ($failure) ? EXP_STATUS_DONE_WITH_ERRORS : 
EXP_STATUS_DONE_SUCCESSFULLY;
++    return $status;
++}
++
++function exprun_parseresult($run_id)
++{
++    $prog = 0;
++    $total = 1;
++    $failure = false;
++    $nodes_results = array();
++    
++    //Read metadata
++    $meta = exprun_getbyid($run_id);
++    
++    //Check if the process is already running
++    $running = exprun_pidrunning($meta['pid']);
++
++    $results_file = $GLOBALS['GPLMT_RESULTS_DIR'].$run_id;
++    if(file_exists($results_file))
++    {
++        //Read nodes from DB
++        $nodes = expnodes_getbyrunid($run_id);
++
++        //Read loaded tasks (if available)
++        if($meta['usetasklist'])
++            $tasks = exec('grep -Po "(?<=Loaded )\d+(?= tasks)" 
'.$results_file);
++        else
++            $tasks = 1;
++        if(!empty($tasks))
++        {
++            $tasks = intval($tasks);
++
++            $total = count($nodes) * $tasks;
++
++            //for each node, calculate progress from result output    
++            foreach($nodes as $n)
++            {
++                $node_failure = false;
++                $interface = $n['host'];
++
++                $res = array();
++                exec('grep -Po "'.$interface.'\s*\| .* \| \K.*" 
'.$results_file, $res); //final result
++                if(count($res) > 0)
++                {
++                    if(trim($res[0]) != 'success')
++                    {
++                        $failure = true;
++                        $node_failure = true;
++                    }
++                    $node_prog = $tasks;
++                }
++                else
++                {
++                    //tasks completed for node
++                    $tasks_completed = array();
++                    exec('grep -Po "'.$interface.' : Task \'.*\' completed" 
'.$results_file, $tasks_completed);
++                    $node_prog = count($tasks_completed);
++                }
++                
++                //get all node logs
++                $node_log_arr = array();
++                exec("grep -E '^$interface' $results_file", $node_log_arr);
++                $node_log = implode("\n", $node_log_arr);
++                
++                $node_perc = $node_prog * 100 / $tasks;
++                $nodes_results[] = array('status' => 
exprun_calculatestatus($node_perc, $running, $node_failure),
++                                    'percentage' => ($running) ? $node_perc : 
100,
++                                    'log' => $node_log,
++                                    'hostid' => $n['hostid']);
++                $prog += $node_prog;
++            }
++        }
++    }
++    
++    $perc = $prog * 100 / $total; //percentage done
++    $status = exprun_calculatestatus($perc, $running, $failure); //total 
status
++    
++    return array('status' => $status, 'percentage' => ($running) ? $perc : 
100, 'nodes_results' => $nodes_results);
++}
++
++function exprun_new($target, $params, $usetasklist, $tasklist, $cmd)
++{
++    if(!exp_verifygplmtdir()) return EXP_ERR_GPLMT_DIR;
++    if($usetasklist == 1 && exptasklist_allowed($tasklist) == 0) return 
EXP_ERR_PERMISSION;
++    
++    //create run record
++    $run_data = array();
++    $run_data['usetasklist'] = $usetasklist;
++    if($usetasklist == 1)
++        $run_data['tasklistid'] = $tasklist;
++    else
++        $run_data['command'] = $cmd;
++    $run_data['userid'] = intval(CWebUser::$data['userid']);
++    $run_data['target'] = $target;
++    
++    $run_id = expdb_insert('exp_run', $run_data);
++
++    //create run-nodes records
++    switch($target)
++    {
++        case 'ssh':
++        case 'planetlab':
++            $hostnames = array();
++            foreach($params as $h) //get hostnames and save to DB
++            {
++                $hostnames[] = expnodes_gethostbyid($h)['host'];
++                expdb_insert('exp_runnode', array('runid' => $run_id, 
'hostid' => $h, 'target' => $target));
++            }
++            //write GPLMT nodes file
++            expnodes_writefile($hostnames, $run_id);
++            break;
++            
++        default: //invalid target
++            expdb_delete('exp_run', array('runid' => $run_id));
++            return EXP_ERR_INVALID_TARGET;
++    }
++    
++    exprun_gplmt($run_id);
++    
++    return EXP_OK;
++}
++
++function exprun_getbyid($run_id)
++{
++    $res = expdb_select('exp_run', array('runid' => $run_id));
++    return $res[0];
++}
++
++function exprun_rerun($run_id)
++{
++    $meta = exprun_getbyid($run_id);
++    if(exprun_pidrunning($meta['pid'])) return;
++    
++    exprun_gplmt($run_id);
++}
++
++function exprun_checkpermission($run_id)
++{
++    if(CWebUser::$data['type'] == 3) return true;
++    
++    $res = expdb_select('exp_run', array('userid' => 
CWebUser::$data['userid'], 'runid' => $run_id));
++    
++    return (sizeof($res) > 0);
++}
++
++function exprun_interrupt($run_id)
++{
++    $meta = exprun_getbyid($run_id);
++    
++    if(!exprun_checkpermission($run_id)) return;
++    
++    $cmd = "kill -15 ".$meta['pid'];
++    exec($cmd);
++}
++
++function exprun_delete($run_id)
++{
++    $meta = exprun_getbyid($run_id);    
++
++    //check permissions
++    if(!exprun_checkpermission($run_id)) return;
++    
++    //check if tool still running
++    if(exprun_pidrunning($meta['pid'])) return;
++
++    $n = $GLOBALS['GPLMT_NODES_DIR'].$run_id;
++    if(file_exists($n)) unlink($n);
++    $r = $GLOBALS['GPLMT_RESULTS_DIR'].$run_id;
++    if(file_exists($r)) unlink($r);
++    
++    expdb_delete('exp_run', array('runid' => $run_id));
++    expdb_delete('exp_runnode', array('runid' => $run_id));
++}
++
++function exprun_verifyid($run_id)
++{
++    $res = expdb_select('exp_run', array('runid' => $run_id));
++    return (sizeof($res) > 0);
++}
++
++function exprun_gplmt($run_id)
++{
++    $run_data = exprun_getbyid($run_id);
++    if($run_data['usetasklist'])
++        $tasklist_data = exptasklist_getbyid($run_data['tasklistid']);
++    
++    //compose and run command
++    $cmd = 'python -u '.$GLOBALS['GPLMT_DIR'].'gplmt.py -V'; // GPLMT
++    $cmd .= ' -c '.$GLOBALS['GPLMT_CONF_DIR'].CWebUser::$data['userid']; // 
Conf file
++    $cmd .= ' -n '.$GLOBALS['GPLMT_NODES_DIR'].$run_id; // Nodes file
++    if($run_data['target'] == 'ssh')
++        $cmd .= ' -t remote_ssh';
++    elseif($run_data['target'] == 'planetlab')
++        $cmd .= ' -t planetlab';
++    if($run_data['usetasklist'])
++        $cmd .= ' -l 
'.$GLOBALS['GPLMT_TASKLISTS_DIR'].$tasklist_data['fsname']; // Tasklist file
++    else
++        $cmd .= " -C '".$run_data['command']."'"; // Command to run
++    $cmd .= ' > '.$GLOBALS['GPLMT_RESULTS_DIR'].$run_id; // Results file
++    $cmd .= ' 2>&1 & echo $!'; // Redirect stderr, run in background and get 
pid
++    
++    $pid = system($cmd);
++
++    expdb_update("exp_run", array('fullcommand' => $cmd, 'pid' => $pid, 
'status' => EXP_STATUS_RUNNING), array('runid' => $run_id));
++}
++
+diff --git a/zabbix/frontends/php/include/experiments/targets.php 
b/zabbix/frontends/php/include/experiments/targets.php
+new file mode 100644
+index 0000000..3e3cc79
+--- /dev/null
++++ b/zabbix/frontends/php/include/experiments/targets.php
+@@ -0,0 +1,184 @@
++<?php
++
++require_once 'XML/RPC2/Client.php';
++
++$exp_targetlist = array(
++    'SSH' => 'ssh',
++    'Planetlab' => 'planetlab');
++
++/*
++ * Planetlab
++ */
++
++function exppl_getauth()
++{
++    $pl_user = expconfig_getconfigbyname('username');
++    if(!$pl_user) fatal_error('Please specify planetlab username in config');
++    $pl_pass = expconfig_getconfigbyname('password');
++    if(!$pl_pass) fatal_error('Please specify planetlab password in config');
++    
++    return array(
++        "AuthMethod" => 'password',
++        "Username" => $pl_user,
++        "AuthString" => $pl_pass
++        );
++}
++
++function exppl_getclient()
++{
++    $pl_api = expconfig_getconfigbyname('api_url');
++    if(!$pl_api) fatal_error('Please specify planetlab API in config');
++    
++    return XML_RPC2_Client::create($pl_api, array('sslverify' => false));
++}
++
++function exppl_getslicename()
++{
++    $pl_slice = expconfig_getconfigbyname('slice');
++    if(!$pl_slice) fatal_error('Please specify planetlab slice in config');
++    return $pl_slice;
++}
++
++function exppl_getAvailableNodes($page_offset, $page_size, $hostfilter = null)
++{
++    $page_offset = intval($page_offset);
++    $page_size = intval($page_size);
++
++    $pl_slice = exppl_getslicename();
++    $auth = exppl_getauth();
++    $client = exppl_getclient();
++    
++    //get node IDs in slice (for negation)
++    try
++    {
++        $node_ids = $client->GetSlices($auth, $pl_slice, 
array('node_ids'))[0]['node_ids'];
++    }
++    catch (XML_RPC2_FaultException $e)
++    {
++        fatal_error($e->getFaultCode() . ' : ' . $e->getFaultString());
++    }
++    
++    $filter = array('~node_id' => $node_ids,
++                    '-SORT' => 'hostname',
++                    '-OFFSET' => $page_offset,
++                    '-LIMIT' => $page_size);
++    if($hostfilter) $filter['hostname'] = "*$hostfilter*";
++    
++    try
++    {
++        return $client->GetNodes($auth, $filter, array('hostname', 
'node_id'));
++    }
++    catch (XML_RPC2_FaultException $e)
++    {
++        fatal_error($e->getFaultCode() . ' : ' . $e->getFaultString());
++    }
++}
++
++function exppl_getSliceNodes()
++{
++    $pl_slice = exppl_getslicename();
++    $auth = exppl_getauth();
++    $client = exppl_getclient();
++
++    //get node IDs
++    try
++    {
++        $node_ids = $client->GetSlices($auth, $pl_slice, 
array('node_ids'))[0]['node_ids'];
++    }
++    catch (XML_RPC2_FaultException $e)
++    {
++        fatal_error($e->getFaultCode() . ' : ' . $e->getFaultString());
++    }
++    
++    //get node hostnames + IDs
++    try
++    {
++        $res = $client->GetNodes($auth, $node_ids, array('hostname', 
'node_id'));
++    }
++    catch (XML_RPC2_FaultException $e)
++    {
++        fatal_error($e->getFaultCode() . ' : ' . $e->getFaultString());
++    }
++    $res = exppl_updateSliceNodesDB($res);
++    return $res;
++}
++
++function exppl_updateSliceNodes($nodes)
++{
++    $pl_slice = exppl_getslicename();
++    $auth = exppl_getauth();
++    $client = exppl_getclient();
++    
++    try
++    {
++        $client->UpdateSlice($auth, $pl_slice, array('nodes' => 
array_map('intval', array_values($nodes))));
++    }
++    catch (XML_RPC2_FaultException $e)
++    {
++        fatal_error($e->getFaultCode() . ' : ' . $e->getFaultString());
++    }
++}
++
++function exppl_updateSliceNodesDB($nodes)
++{
++    if(!is_array($nodes)) return;
++    
++    $userid = CWebUser::$data['userid'];
++    
++    // No delete so as not to break previous runs
++    // Insert new hosts not seen before
++    
++    for($i = 0; $i < count($nodes); $i++)
++    {
++        if(!exppl_getHostByPLNodeId($nodes[$i]['node_id'])) //Does not exist
++            $nodes[$i]['hostid'] = expdb_insert('exp_host', array('userid' => 
$userid, 'host' => $nodes[$i]['hostname'], 'target' => 'planetlab', 'pl_nodeid' 
=> $nodes[$i]['node_id']));
++        else
++            $nodes[$i]['hostid'] = 
exppl_getHostByPLNodeId($nodes[$i]['node_id'])['hostid'];
++    }
++    
++    return $nodes;
++}
++
++function exppl_getHostByPLNodeId($pl_nodeid)
++{
++    $res = expdb_select('exp_host', array('pl_nodeid' => $pl_nodeid));
++    if(count($res) == 0) return null;
++    return $res[0];
++}
++
++/*
++ * SSH
++ */
++
++function expssh_updatehosts($hostlist)
++{
++    if(!is_array($hostlist)) return;
++    
++    $userid = CWebUser::$data['userid'];
++    
++    $old_hostlist = array();
++    $new_hostlist = array();
++    foreach($hostlist as $h)
++    {
++        $hc = mysql_real_escape_string(trim($h));
++        if(!$hc) continue;
++        if(is_numeric($hc))
++            $old_hostlist[] = $hc;
++        else //added hosts value is the host itself not an ID
++            $new_hostlist[] = $hc;
++    }
++    
++    //look for deleted hosts
++    if(count($old_hostlist) > 0)
++    {
++        $sql = 'DELETE FROM exp_host
++            WHERE userid = '.$userid
++            .' AND target = "ssh"'
++            .' AND hostid NOT IN ('.implode(',', $old_hostlist).')';
++        DBexecute($sql);
++    }
++    
++    //look for new hosts
++    foreach($new_hostlist as $h)
++        expdb_insert('exp_host', array('userid' => $userid, 'host' => $h, 
'target' => 'ssh'));
++}
+diff --git a/zabbix/frontends/php/include/experiments/tasklist.php 
b/zabbix/frontends/php/include/experiments/tasklist.php
+new file mode 100644
+index 0000000..5e45902
+--- /dev/null
++++ b/zabbix/frontends/php/include/experiments/tasklist.php
+@@ -0,0 +1,287 @@
++<?php
++
++require_once dirname(__FILE__).'/files.php';
++
++//default XML elements (for creating empty nods)
++$exptasklist_defaults = array();
++$exptasklist_defaults['sequence'] = new SimpleXMLElement('<sequence 
name=""></sequence>');
++$exptasklist_defaults['run'] = new SimpleXMLElement('<run 
name=""><command></command><arguments></arguments><timeout>0</timeout><expected_return_code>0</expected_return_code><expected_output></expected_output><stop_on_fail>false</stop_on_fail></run>');
++$exptasklist_defaults['run_per_host'] = new SimpleXMLElement('<run_per_host 
name=""><command_file></command_file><output_prefix></output_prefix><timeout>0</timeout><expected_return_code>0</expected_return_code><expected_output></expected_output><stop_on_fail>false</stop_on_fail></run_per_host>');
++$exptasklist_defaults['put'] = new SimpleXMLElement('<put 
name=""><source></source><destination></destination><stop_on_fail>false</stop_on_fail></put>');
++$exptasklist_defaults['get'] = new SimpleXMLElement('<get 
name=""><source></source><destination>./</destination><stop_on_fail>false</stop_on_fail></get>
 ');
++
++function exptasklist_addall()
++{
++    $sql = "SELECT * FROM exp_tasklist";
++    $indb = DBfetchArrayAssoc(DBSelect($sql), 'fsname');
++    
++    $indir = scandir($GLOBALS['GPLMT_TASKLISTS_DIR']);
++    
++    foreach($indir as $i)
++    {
++        if(substr($i, -4) != '.xml') continue;
++        if(isset($indb[$i])) continue;
++        $name = str_replace('_', ' ', $i);
++        $name = str_replace('.xml', '', $name);
++        
++        expdb_insert('exp_tasklist', array('name' => $name, 'fsname' => $i, 
'userid' => CWebUser::$data['userid'], 'shared' => 1));
++    }
++}
++
++function exptasklist_getall($editable = false)
++{
++    $sql = "SELECT exp_tasklist.*, CONCAT_WS(' ', users.name, users.surname) 
as username
++            FROM exp_tasklist INNER JOIN users ON exp_tasklist.userid = 
users.userid";
++    if(!(CWebUser::$data['type'] == 3)) //not super admin
++    {
++        $sql .= ' WHERE exp_tasklist.userid = '.CWebUser::$data['userid'];
++        if(!$editable)
++            $sql .= ' OR exp_tasklist.shared = 1';
++    }
++    
++    return DBfetchArray(DBselect($sql));
++}
++
++function exptasklist_getbyid($tasklistid)
++{
++    $res = expdb_select('exp_tasklist', array('tasklistid' => $tasklistid));
++    if(count($res) == 0) return null;
++    return $res[0];
++}
++
++function exptasklist_getcontent($tasklistid)
++{
++    $tl_row = exptasklist_getbyid($tasklistid);
++    if(!$tl_row) return null;
++    $file = $GLOBALS['GPLMT_TASKLISTS_DIR'].$tl_row['fsname'];
++    if(!file_exists($file)) return null;
++    return file_get_contents($file);
++}
++
++/**
++ * Given a tasklist id, returns 0, 1 or 2 for No access, read, read/write 
respectively
++ *
++ * @return int
++ */
++function exptasklist_allowed($tasklistid)
++{
++    $tl_row = exptasklist_getbyid($tasklistid);
++    if(!$tl_row) return 0;
++    if(CWebUser::$data['type'] == 3 || $tl_row['userid'] == 
CWebUser::$data['userid']) return 2;
++    if($tl_row['shared']) return 1;
++    return 0;
++}
++
++function exptasklist_delete($tid)
++{
++    $meta = exptasklist_getbyid($tid);
++    if(!$meta)
++    {
++        error("Invalid tasklist ID");
++        return false;
++    }
++    $fullFileName = $GLOBALS['GPLMT_TASKLISTS_DIR'].$meta['fsname'];
++    
++    //delete from DB
++    expdb_delete('exp_tasklist', array('tasklistid' => $tid));
++    
++    //delete file
++    if(file_exists($fullFileName)) unlink($fullFileName);
++    
++    return true;
++}
++
++function exptasklist_sxmlappend(SimpleXMLElement $to, SimpleXMLElement $from)
++{
++    $toDom = dom_import_simplexml($to);
++    $fromDom = dom_import_simplexml($from);
++    $newDom = $toDom->appendChild($toDom->ownerDocument->importNode($fromDom, 
true));
++    return simplexml_import_dom($newDom);
++}
++
++function exptasklist_constructxml($data)
++{
++    global $exptasklist_defaults;
++    
++    $xml = new SimpleXMLElement('<?xml version="1.0" 
encoding="UTF-8"?><tasklist></tasklist>');
++    $xml->addAttribute('xsi:noNamespaceSchemaLocation', 
"../tasklist_schema.xsd", "http://www.w3.org/2001/XMLSchema-instance";);
++    $xml->addChild('options');
++
++    //name
++    if(empty($data['name']))
++    {
++        error("Missing name field");
++        return false;
++    }
++    $name = $data['name'];
++    $xml->addAttribute('name', $name);
++    
++    //target
++    /*if(!empty($data['target']))
++        $xml->options->addChild('target', $data['target']);*/
++
++    //log dir
++    if(!empty($data['logdir']))
++        $xml->options->addChild('log_dir', $data['logdir']);
++    
++    //index for node components
++    $nodesIndex = array();
++    
++    foreach($data as $k => $v)
++    {
++        $parts = explode('_', $k);
++        $parts_count = count($parts);
++        if($parts_count == 1 || $parts_count > 3) continue;
++        
++        $field = str_replace('$', '_', $parts[0]);
++        $value = trim($v);
++        $index = implode('_', array_slice($parts, 1));
++        
++        if($field == 'type') //initial field in the node
++        {
++            if(!array_key_exists($value, $exptasklist_defaults)) continue; 
//invalid type
++            
++            if($parts_count == 2) $parent = $xml;
++            else $parent = $nodesIndex[$parts[1]];
++            
++            $newXml = $exptasklist_defaults[$value];
++            if($value != 'sequence') $newXml['id'] = $parts[$parts_count - 
1]; //GPLMT doesn't accept ID in sequence but mandatory for others
++            $newXml['enabled'] = 'false'; //Disabled by default unless we get 
the enabled flag from form
++            
++            $nodesIndex[$index] = exptasklist_sxmlappend($parent, $newXml);
++            
++            
++            continue;
++        }
++        
++        if(!array_key_exists($index, $nodesIndex)) continue; //problem or 
data element that is not related to the XML
++        
++        $subxml = $nodesIndex[$index];
++        $type = $subxml->getName();
++        
++        //validations:
++        switch($field)
++        {
++            //bool
++            case 'enabled': case 'stop_on_fail':
++                $value = strtolower($value);
++                if($value != 'yes' && $value != 'no')
++                {
++                    error("Value for $field should be true or false!");
++                    return false;
++                }
++                $value = ($value == 'yes') ? 'true' : 'false';
++                break;
++            
++            //int
++            case 'timeout': case 'expected_return_code':
++                if(!is_numeric($value))
++                {
++                    error("Value for $field should be an integer!");
++                    return false;
++                }
++                break;
++
++            //file
++            case 'source':
++                if($type == 'put')
++                {
++                    $value = exp_cleanfilename($value);
++                }
++                break;
++            case 'destination':
++                if($type == 'get')
++                {
++                    $value = './';
++                }
++                break;
++        }
++        
++        //writing values
++        switch($field)
++        {
++            //attributes
++            case 'enabled': case 'name':
++                $subxml[$field] = $value;
++                break;
++            
++            case 'command': case 'arguments': case 'timeout': case 
'expected_return_code': case 'expected_output':
++            case 'stop_on_fail': case 'command_file': case 'output_prefix': 
case 'source': case 'destination':
++                $subxml->$field = $value;
++                break;
++            
++            default:
++                error("Unknown field: $field");
++        }
++    }
++    
++    //save the resulting XML to file (formatted)
++    $dom = dom_import_simplexml($xml)->ownerDocument;
++    $dom->formatOutput = true;
++    return $dom->saveXML();
++}
++
++function exptasklist_add($data)
++{
++    $xml = exptasklist_constructxml($data);
++    if(!$xml) return false;
++    
++    //name
++    $name = $data['name'];
++    
++    //description
++    $description = empty($data['description']) ? '' : $data['description'];
++    
++    //shared
++    $shared = false;
++    $shared = (!empty($data['shared']) && ($data['shared'] == 'yes'));
++    
++    //create new fsname
++    $fsname = str_replace(' ', '_', $name);
++    $fsname = str_replace('\\', '_', $fsname);
++    $counter = 0;
++    while(file_exists($GLOBALS['GPLMT_TASKLISTS_DIR'].$fsname.'.xml'))
++    {
++        $fsname .= strval($counter);
++        $counter++;
++    }
++    $fsname .= '.xml';
++    
++    //user ID
++    $userid = CWebUser::$data['userid'];
++    
++    //save to file
++    file_put_contents($GLOBALS['GPLMT_TASKLISTS_DIR'].$fsname, $xml);
++    
++    //save to DB
++    expdb_insert('exp_tasklist',
++        array('name' => $name, 'description' => $description, 'fsname' => 
$fsname, 'userid' => $userid, 'shared' => intval($shared)));
++    
++    return true;
++}
++
++function exptasklist_update($tasklistid, $data)
++{
++    $meta = exptasklist_getbyid($tasklistid); //get task meta data from db
++    
++    $xml = exptasklist_constructxml($data);
++    if(!$xml) return false;
++    
++    //name
++    $name = $data['name'];
++    
++    //description
++    $description = empty($data['description']) ? '' : $data['description'];
++    
++    //shared
++    $shared = false;
++    $shared = (!empty($data['shared']) && ($data['shared'] == 'yes'));
++    
++    file_put_contents($GLOBALS['GPLMT_TASKLISTS_DIR'].$meta['fsname'], $xml);
++    
++    //update DB
++    expdb_update('exp_tasklist', array('name' => $name, 'description' => 
$description, 'shared' => intval($shared)),
++        array('tasklistid' => $tasklistid));
++    
++    return true;
++}
+diff --git a/zabbix/frontends/php/include/menu.inc.php 
b/zabbix/frontends/php/include/menu.inc.php
+index 6e27065..51b0d56 100644
+--- a/zabbix/frontends/php/include/menu.inc.php
++++ b/zabbix/frontends/php/include/menu.inc.php
+@@ -281,6 +281,38 @@ $ZBX_MENU = array(
+                       )
+               )
+       ),
++      'experiment' => array(
++              'label'                         => _('Experiments'),
++              'user_type'                     => USER_TYPE_ZABBIX_ADMIN,
++              'node_perm'                     => PERM_READ_WRITE,
++              'default_page_id'       => 0,
++              'pages' => array(
++                      array(
++                              'url' => 'execute.php',
++                              'label' => _('Deploy & Execute')
++                      ),
++                      array(
++                              'url' => 'results.php',
++                              'label' => _('Results')
++                      ),
++                      array(
++                              'url' => 'targets.php',
++                              'label' => _('Targets')
++                      ),
++                      array(
++                              'url' => 'tasklist.php',
++                              'label' => _('Tasklists')
++                      ),
++                      array(
++                              'url' => 'files.php',
++                              'label' => _('Files')
++                      ),
++                      array(
++                              'url' => 'conf.php',
++                              'label' => _('Configuration')
++                      )
++              )
++      ),
+       'login' => array(
+               'label'                                 => _('Login'),
+               'user_type'                             => 0,
+diff --git a/zabbix/frontends/php/include/views/administration.script.list.php 
b/zabbix/frontends/php/include/views/administration.script.list.php
+index bb42f3f..aab1244 100644
+--- a/zabbix/frontends/php/include/views/administration.script.list.php
++++ b/zabbix/frontends/php/include/views/administration.script.list.php
+@@ -40,9 +40,18 @@ $scriptsTable->setHeader(array(
+       make_sorting_header(_('Commands'), 'command'),
+       _('User group'),
+       _('Host group'),
+-      _('Host access')
++      _('Host access'),
++      _('Run on Host Group')
+ ));
+ 
++//get list of host groups
++$hostgroups = API::HostGroup()->get(array(
++              'not_proxy_host' => 1,
++              'sortfield' => 'name',
++              'editable' => true,
++              'output' => array('name')
++      ));
++
+ foreach ($this->data['scripts'] as $script) {
+       $scriptid = $script['scriptid'];
+ 
+@@ -72,6 +81,18 @@ foreach ($this->data['scripts'] as $script) {
+               $scriptExecuteOn = '';
+       }
+ 
++    //create hostgroups combobox
++    $runForm = new CForm('GET', 'scripts_exec.php');
++    $runForm->addItem(new CInput('hidden', 'execute', '1'));
++    $runForm->addItem(new CInput('hidden', 'scriptid', $script['scriptid']));
++    
++    $grpsComboBox = new CComboBox('groupid');
++    foreach($hostgroups as $hostgroup)
++        $grpsComboBox->addItem(new CComboItem($hostgroup['groupid'], 
$hostgroup['name']));
++
++    $runForm->addItem($grpsComboBox);
++    $runForm->addItem(new CInput('submit', 'submit', 'Run'));
++
+       $scriptsTable->addRow(array(
+               new CCheckBox('scripts['.$script['scriptid'].']', 'no', null, 
$script['scriptid']),
+               new CLink($script['name'], 
'scripts.php?form=1&scriptid='.$script['scriptid']),
+@@ -80,7 +101,8 @@ foreach ($this->data['scripts'] as $script) {
+               zbx_nl2br(htmlspecialchars($script['command'], ENT_COMPAT, 
'UTF-8')),
+               ('' == $script['userGroupName']) ? _('All') : 
$script['userGroupName'],
+               ('' == $script['hostGroupName']) ? _('All') : 
$script['hostGroupName'],
+-              ((PERM_READ_WRITE == $script['host_access']) ? _('Write') : 
_('Read'))
++              ((PERM_READ_WRITE == $script['host_access']) ? _('Write') : 
_('Read')),
++              $runForm
+       ));
+ }
+ 
+diff --git a/zabbix/frontends/php/include/views/experiments.conf.php 
b/zabbix/frontends/php/include/views/experiments.conf.php
+new file mode 100644
+index 0000000..0af85d5
+--- /dev/null
++++ b/zabbix/frontends/php/include/views/experiments.conf.php
+@@ -0,0 +1,66 @@
++<?php
++
++$conf = $this->get('conf');
++
++$cWidget = new CWidget();
++
++$cForm = new CForm('post');
++$cTable = new CTableInfo();
++
++$current_section = '';
++foreach($conf as $c)
++{
++    if($c['section'] != $current_section)
++    {
++        $current_section = $c['section'];
++        $cTable->addRow(strtoupper($current_section));
++    }
++    
++    switch($c['type'])
++    {
++        case 'text': case 'integer':
++            $cInput = new CTextBox($c['configid'], $c['value']);
++            break;
++        
++        case 'password':
++            $cInput = new CPassBox($c['configid'], $c['value'], 20);
++            break;
++        
++        case 'boolean':
++            $cHidden = new CInput('hidden', $c['configid'], 'no');
++            $cChkbox = new CCheckBox($c['configid'], $c['value']);
++            $cInput = array($cHidden, $cChkbox);
++            break;
++        
++        case 'file':
++            $userfiles = expfiles_getuserfiles();
++            $selectedfile = '';
++            if(!empty($c['value'])) $selectedfile = basename($c['value']);
++            $cInput = new CComboBox($c['configid']);
++            $cInput->addItem('', '');
++            foreach($userfiles as $uf)
++                $cInput->addItem($uf, $uf, ($selectedfile == $uf)?'yes':null);
++            break;
++
++        case 'enum':
++            $options = expconfig_getenum($c['configid']);
++            $cInput = new CComboBox($c['configid']);
++            foreach($options as $o)
++                $cInput->addItem($o['value'], $o['label'], ($c['value'] == 
$o['value'])?'yes':null);
++            break;
++
++        default:
++            $cInput = new CLabel('Invalid type');
++            break;
++    }
++    
++    $help_image = new CImg('images/general/question_mark.png');
++    $help_image->attr('title', $c['description']);
++    
++    $cTable->addRow(array($c['label'], array($cInput, $help_image)));
++}
++$cTable->addRow(new CSubmit('update', 'Update'));
++
++$cForm->addItem($cTable);
++$cWidget->addItem($cForm);
++return $cWidget;
+diff --git a/zabbix/frontends/php/include/views/experiments.execute.php 
b/zabbix/frontends/php/include/views/experiments.execute.php
+new file mode 100644
+index 0000000..bc87ce3
+--- /dev/null
++++ b/zabbix/frontends/php/include/views/experiments.execute.php
+@@ -0,0 +1,100 @@
++<?php
++
++$targets = $this->get('targets');
++$currenttarget = $this->get('currenttarget');
++
++//Main Form
++$exec_frm = new CForm();
++$exec_frm->setName('web.experiment.execute.php.');
++$exec_frm->attr('id', 'mainfrm');
++
++//Main table
++$main_table = new CTable();
++
++//Row 1 - Targets
++$targets_cmb = new CComboBox('target');
++foreach($targets as $k => $v)
++    $targets_cmb->addItem($v, $k, ($v == $currenttarget)?'yes':null);
++$targets_cmb->attr('onchange', "jQuery('#mainfrm').submit();");
++
++$main_table->addRow(new CRow(array(
++    'Select Target:',
++    $targets_cmb)));
++
++//Row 2 - Target settings
++$settings_enabled = false;
++switch($currenttarget)
++{
++    case 'ssh':
++        $settings_enabled = true;
++        
++        $sshhosts = expnodes_gethosts('ssh');
++        $sshhosts_tb = new CTweenBox($exec_frm, 'hosts');
++        foreach($sshhosts as $sh)
++            $sshhosts_tb->addItem($sh['hostid'], $sh['host'], true);
++        
++        $settings_elm = $sshhosts_tb->get('Selected:', 'Excluded:');
++        
++        break;
++    
++    case 'planetlab':
++        $settings_enabled = true;
++        
++        $plhosts = exppl_getSliceNodes();
++        $plhosts_tb = new CTweenBox($exec_frm, 'hosts');
++        foreach($plhosts as $ph)
++            $plhosts_tb->addItem($ph['hostid'], $ph['hostname'], true);
++        
++        $settings_elm = $plhosts_tb->get('Selected:', 'Excluded:');
++    
++        break;
++    
++    default:
++        $settings_enabled = true;
++        $settings_elm = 'Invalid Target. WHY?';
++        break;
++}
++if($settings_enabled)
++    $main_table->addRow(new CRow(array(
++        'Target Settings:',
++        $settings_elm)));
++
++//Row 3 - Tasklists
++$tasklists = $this->get('tasklists');
++
++$tasklists_tbl = new CTable();
++
++$tasklists_rad1 = new CRadioButton('usetasklist', '1', 'input radio', null, 
true);
++$tasklists_rad2 = new CRadioButton('usetasklist', '0', 'input radio');
++$tasklists_cmb = new CComboBox('tasklist');
++foreach($tasklists as $t)
++    $tasklists_cmb->addItem($t['tasklistid'], $t['name']);
++$tasklists_txt = new CTextBox('cmd');
++
++
++$tasklists_tbl->addRow(
++array(
++new CDiv(array(
++$tasklists_rad1, 'Tasklist:')),
++$tasklists_cmb));
++$tasklists_tbl->addRow(
++array(
++new CDiv(array(
++$tasklists_rad2, 'Command:')),
++$tasklists_txt));
++
++$main_table->addRow(new CRow(array(
++    'Select Tasklist / Command:',
++    $tasklists_tbl
++)));
++
++
++$exec_frm->addItem($main_table);
++
++/*
++ * footer
++ */
++$run_submit = array(new CSubmit('run', 'Run'));
++$exec_frm->addItem(makeFormFooter($run_submit));
++
++return $exec_frm;
+diff --git a/zabbix/frontends/php/include/views/experiments.files.php 
b/zabbix/frontends/php/include/views/experiments.files.php
+new file mode 100644
+index 0000000..1fd1203
+--- /dev/null
++++ b/zabbix/frontends/php/include/views/experiments.files.php
+@@ -0,0 +1,30 @@
++<?php
++
++$files = $this->get('files');
++
++$fWidget = new CWidget();
++
++$uploadForm = new CForm('post', null, 'multipart/form-data');
++$uploadForm->addItem(new CInput('file', 'file'));
++$uploadForm->addItem(new CSubmit('upload', 'Upload file'));
++//add maximum size note
++
++$fWidget->addPageHeader('USER FILES', $uploadForm);
++
++$files_tbl = new CTableInfo('No files added yet.');
++$files_tbl->setHeader(array('File name', ''));
++foreach($files as $f)
++{
++    //download link
++    $download_lnk = new CLink($f, '?download='.$f);
++    
++    //delete link
++    $delete_lnk = new CLink('delete', '?delete='.$f);
++    
++    $files_tbl->addRow(array($download_lnk, $delete_lnk));
++    //TODO: add delete, download
++}
++
++$fWidget->addItem($files_tbl);
++
++return $fWidget;
+diff --git a/zabbix/frontends/php/include/views/experiments.results.php 
b/zabbix/frontends/php/include/views/experiments.results.php
+new file mode 100644
+index 0000000..2591b41
+--- /dev/null
++++ b/zabbix/frontends/php/include/views/experiments.results.php
+@@ -0,0 +1,63 @@
++<?php
++
++//Main table
++$main_table = new CTableInfo();
++
++$results = $this->get('results');
++$runid = $this->get('runid'); //if set, one of the runs is selected
++
++$main_table->setHeader(array('', 'Status', 'Started On', 'Target', 
'Percentage completed', '', ''));
++
++foreach($results as $r)
++{
++    $div_actions = new CDiv();
++    if($r['status'] == 'Running')
++        $div_actions->addItem(new CLink('interrupt', 
'results.php?interrupt='.$r['runid']));
++    else
++    {
++        $div_actions->addItem(new CLink('delete', 
'results.php?delete='.$r['runid']));
++        //$div_actions->addItem(new CButtonDelete('Are you sure you want to 
delete?', $r['runid']));
++        $div_actions->addItem(' | ');
++        $div_actions->addItem(new CLink('re-run', 
'results.php?rerun='.$r['runid']));
++    }
++    
++    //nodes table
++    $nodes_table = new CTableInfo();
++    foreach($r['nodes'] as $n)
++    {
++        $nodes_table->addRow(new CRow(array(
++            $n['interface'],
++            $n['status'],
++            $n['percentage'].'%',
++            new CLink('log', 
'results.php?runid='.$r['runid'].'&hostid='.$n['hostid'])
++        )));
++    }
++    
++    $main_row = array(
++        new CButton(null, '+/-', 
"javascript:jQuery('#".$r['runid']."').toggle();"),
++        $r['status'],
++        $r['startedon'],
++        $r['target'],
++        $r['percentage'].'%',
++        new CLink('log', 'results.php?runid='.$r['runid']),
++        $div_actions
++        );
++    $main_table->addRow(new CRow($main_row));
++    $hidden_col = new CCol($nodes_table, null, count($main_row));
++    $hidden_col->attr('id', $r['runid']);
++    if(empty($runid) || $runid != $r['runid'])
++        $hidden_col->attr('style', 'display:none;');
++    $main_table->addRow(new CRow($hidden_col));
++}
++
++$log = $this->get('log');
++
++if(!empty($log))
++{
++    $res_txt = new CTextArea(null, $log, array('rows' => substr_count($log, 
"\n") + 1, 'readonly' => 1));
++    $res_txt->attr('style', 'width:100%;font-size:15px;');
++    
++    return new CDiv(array($main_table, 'RESULT:', $res_txt));
++}
++else
++    return $main_table;
+diff --git a/zabbix/frontends/php/include/views/experiments.targets.php 
b/zabbix/frontends/php/include/views/experiments.targets.php
+new file mode 100644
+index 0000000..af46fba
+--- /dev/null
++++ b/zabbix/frontends/php/include/views/experiments.targets.php
+@@ -0,0 +1,90 @@
++<?php
++$targetlist = $this->get('targetlist');
++$default_target = reset($targetlist);
++$selected_target = $this->get('selected_target');
++if(!$selected_target) $selected_target = $default_target;
++
++//Main form
++$main_frm = new CForm();
++$main_frm->setName('web.experiment.targets.php.');
++$main_frm->attr('id', 'mainfrm');
++
++//Main table
++$main_table = new CTable();
++
++//Row 1 - Targets
++$targets_cmb = new CComboBox('target');
++foreach($targetlist as $k => $v)
++    $targets_cmb->addItem($v, $k, ($v == $selected_target)?'yes':null);
++$targets_cmb->attr('onchange', "jQuery('#mainfrm').submit();");
++$main_table->addRow(array('Target:', $targets_cmb));
++
++//Row 2 - Target edit
++switch($selected_target)
++{
++    case 'ssh':
++        $ssh_lst = new CListBox('sshhosts[]', null, 12);
++        $sshhosts = $this->get('sshhosts');
++        foreach($sshhosts as $sh)
++            $ssh_lst->addItem($sh['hostid'], $sh['host']);
++        
++        $del_btn = new CButton('delsshhost', 'Remove', 
"jQuery('select[name=\"sshhosts[]\"]').find(':selected').remove()");
++        
++        $add_txt = new CTextBox('newsshhost', null, 30);
++        $add_btn =  new CButton('addsshhost', 'Add', 
"jQuery('select[name=\"sshhosts[]\"]').append('<option>'+jQuery('input[name=newsshhost]').val()+'</option>');jQuery('input[name=newsshhost]').val('')");
++        
++        $submit_btn = new CSubmit('apply', 'Apply');
++        $submit_btn->attr('onclick', "jQuery('select[name=\"sshhosts[]\"] 
option').attr('selected', 'yes')");
++        
++        $main_table->addRow(array('SSH:', array($ssh_lst, $del_btn)));
++        $main_table->addRow(array('', array($add_txt, $add_btn)));
++        $main_table->addRow(array('', $submit_btn));
++        
++        break;
++    
++    case 'planetlab':
++        $pagesize = 20;
++        $pageoffset = intval($this->get('ploffset'));
++        if(!$pageoffset || $pageoffset < 0) $pageoffset = 0;
++        $hostfilter = $this->get('plfilter');
++        if(!$hostfilter) $hostfilter = null;
++        $slicename = exppl_getslicename();
++        $slicenodes = exppl_getSliceNodes();
++        $availnodes = exppl_getAvailableNodes($pageoffset, $pagesize, 
$hostfilter);
++    
++        $pl_tb = new CTweenBox($main_frm, 'plnodes');
++        foreach($slicenodes as $sn)
++            $pl_tb->addItem($sn['node_id'], $sn['hostname'], true);
++        foreach($availnodes as $an)
++            $pl_tb->addItem($an['node_id'], $an['hostname']);
++        
++        $filter_frm = new CForm('get');
++        $filter_frm->attr('id', 'filterfrm');
++        $filter_tb = new CTextBox('plfilter', $hostfilter);
++        $filter_tb->attr('id', 'plfilter');
++        $filter_btn = new CSubmit('filter', 'Filter', 
'jQuery("#ploffset").val(0)');
++        $page_tb = new CTextBox('ploffset', $pageoffset, 2);
++        $page_tb->attr('id', 'ploffset');
++        $prev_btn = new CSubmit('plprev', '<<', 
'jQuery("#ploffset").val(parseInt(jQuery("#ploffset").val(), 10) - 
1);jQuery("#filterfrm").submit();');
++        $next_btn = new CSubmit('plnext', '>>', 
'jQuery("#ploffset").val(parseInt(jQuery("#ploffset").val(), 10) + 
1);jQuery("#filterfrm").submit();');
++        $clear_btn = new CSubmit('plclear', 'Clear', 
'jQuery("#ploffset").val(0);jQuery("#plfilter").val("")');
++        $filter_tbl = new CTable();
++        $filter_tbl->addRow(array(array($prev_btn, $page_tb, $next_btn)));
++        $filter_tbl->addRow(array(array('Filter:', $filter_tb, $filter_btn)));
++        $filter_tbl->addRow(array($clear_btn));
++        $filter_frm->addItem($filter_tbl);
++        
++        $pl_tbl = new CTable();
++        $pl_tbl->addRow(array($pl_tb->get($slicename, 'Available'), 
$filter_frm));
++        
++        $submit_btn = new CSubmit('apply', 'Apply');
++        
++        $main_table->addRow(array('Planetlab', $pl_tbl));
++        $main_table->addRow(array('', $submit_btn));
++        
++        break;
++}
++
++$main_frm->addItem($main_table);
++
++return $main_frm;
+diff --git a/zabbix/frontends/php/include/views/experiments.tasklist.edit.php 
b/zabbix/frontends/php/include/views/experiments.tasklist.edit.php
+new file mode 100644
+index 0000000..152cf29
+--- /dev/null
++++ b/zabbix/frontends/php/include/views/experiments.tasklist.edit.php
+@@ -0,0 +1,318 @@
++<?php
++
++$new = $this->get('new');
++
++if($new)
++    $xml = new SimpleXMLElement('<?xml version="1.0" 
encoding="UTF-8"?><tasklist></tasklist>');
++else
++    $xml = $this->get('xml');
++
++//$targets = $this->get('targets');
++$tid = $this->get('tid');
++if($new)
++    $meta = array();
++else
++    $meta = $this->get('meta');
++$exptasklist_defaults = $this->get('exptasklist_defaults');
++
++function tlview_parseseq($xml, $postfix)
++{
++    $seq_tbl = new CTableInfo('');
++    $seq_tbl->attr('id', "table$postfix");
++    
++    //Top Row:
++    $btns_div = new CDiv();
++    //Delete button
++    $del_btn = new CButton('delete', 'delete', 'javascript: 
jQuery("#row'.$postfix.'").remove()');
++    //Type (hidden)
++    $type_hdn = new CInput('hidden', 'type'.$postfix, 'sequence');
++    $btns_div->addItem($type_hdn);
++    //Add runs
++    $run_cmb = new CComboBox('run');
++    $run_cmb->attr('id', "runs$postfix");
++    $run_cmb->addItem('run', 'run');
++    $run_cmb->addItem('run_per_host', 'run_per_host');
++    $run_cmb->addItem('put', 'put');
++    $run_cmb->addItem('get', 'get');
++    $btns_div->addItem($run_cmb);
++    $js = 'javascript: '; //javascript used to add runs under this sequence
++    $js .= 'if (typeof window.counter'.$postfix.' === "undefined") 
window.counter'.$postfix.' = '.(count($xml->children())+1).';';
++    $js .= 'new_node(jQuery("#runs'.$postfix.'").val(), 
"'.$postfix.'_"+counter'.$postfix.', "table'.$postfix.'", 
counter'.$postfix.'%2);';
++    $js .= 'counter'.$postfix.'++;';
++    $add_btn = new CButton('add', 'Add', $js);
++    $btns_div->addItem($add_btn);
++    //Move up
++    $mvup_btn = new CButton('mvup', 'Move UP', 'javascript: 
p=jQuery("#row'.$postfix.'").prev(); if(p.attr("id")) 
jQuery("#row'.$postfix.'").insertBefore(p);');
++    $btns_div->addItem($mvup_btn);
++    //Move down
++    $mvdown_btn = new CButton('mvdown', 'Move DOWN', 'javascript: 
n=jQuery("#row'.$postfix.'").next(); if(n.attr("id")) 
jQuery("#row'.$postfix.'").insertAfter(n);');
++    $btns_div->addItem($mvdown_btn);
++    
++    $seq_tbl->addRow(array($del_btn, $btns_div));
++    
++    //Sequence attributes
++    
++    //Name attribute
++    $name_tb = new CInput('text', 'name'.$postfix, (string)$xml['name']);
++    $name_tb->addStyle('width: 50em;');
++    $seq_tbl->addRow(array('Name:', $name_tb));
++    
++    //Enabled attribute
++    $enabled_chb = new CCheckBox('enabled'.$postfix, 
(((string)$xml['enabled']) == 'false')?'no':'yes');
++    $seq_tbl->addRow(array('Enabled:', $enabled_chb));
++    
++    
++    $counter = 1;
++    foreach($xml->children() as $c)
++    {
++        $name = trim($c->getName());
++        $row_postfix = $postfix.'_'.$counter;
++        $seq_tbl->addRow(tlview_parserun($name, $c, $row_postfix));
++        $counter++;
++    }
++    
++    //print "<script>var counter$postfix = $counter</script>";
++    
++    return new CRow(array('Sequence:', $seq_tbl), null, "row$postfix");
++}
++function tlview_parserun($type, $xml, $postfix)
++{
++    $run_tbl = new CTableInfo('');
++    
++    //common elements
++    
++    //Top Row:
++    $btns_div = new CDiv();
++    //Delete button
++    $del_btn = new CButton('delete', 'delete', 'javascript: 
jQuery("#row'.$postfix.'").remove()');
++    //Type (hidden)
++    $type_hdn = new CInput('hidden', 'type'.$postfix, $type);
++    $btns_div->addItem($type_hdn);
++    //Move up
++    $mvup_btn = new CButton('mvup', 'Move UP', 'javascript: 
p=jQuery("#row'.$postfix.'").prev(); if(p.attr("id")) 
jQuery("#row'.$postfix.'").insertBefore(p);');
++    $btns_div->addItem($mvup_btn);
++    //Move down
++    $mvdown_btn = new CButton('mvdown', 'Move DOWN', 'javascript: 
n=jQuery("#row'.$postfix.'").next(); if(n.attr("id")) 
jQuery("#row'.$postfix.'").insertAfter(n);');
++    $btns_div->addItem($mvdown_btn);
++    
++    $run_tbl->addRow(array($del_btn, $btns_div));
++    
++    //Name attribute
++    $name_tb = new CInput('text', 'name'.$postfix, (string)$xml['name']);
++    $name_tb->addStyle('width: 50em;');
++    $run_tbl->addRow(array('Name:', $name_tb));
++    
++    //Enabled attribute
++    $enabled_chb = new CCheckBox('enabled'.$postfix, 
(((string)$xml['enabled']) == 'false')?'no':'yes');
++    $run_tbl->addRow(array('Enabled:', $enabled_chb));
++    
++    switch($type)
++    {
++        case 'run':
++            //command
++            $cmd_tb = new CInput('text', 'command'.$postfix, 
(string)$xml->command);
++            $cmd_tb->addStyle('width: 50em;');
++            $run_tbl->addRow(array('Command:', $cmd_tb));
++            
++            //arguments
++            $args_tb = new CInput('text', 'arguments'.$postfix, 
(string)$xml->arguments);
++            $args_tb->addStyle('width: 50em;');
++            $run_tbl->addRow(array('Arguments:', $args_tb));
++            
++            //timeout
++            $timeout_tb = new CInput('text', 'timeout'.$postfix, 
(string)$xml->timeout);
++            $run_tbl->addRow(array('Timeout:', $timeout_tb));
++            
++            //expected_return_code
++            $expected_return_code_tb = new CInput('text', 
'expected$return$code'.$postfix, (string)$xml->expected_return_code);
++            $run_tbl->addRow(array('Expected Return Code:', 
$expected_return_code_tb));
++            
++            //expected_output
++            $expected_output_tb = new CInput('text', 
'expected$output'.$postfix, (string)$xml->expected_output);
++            $expected_output_tb->addStyle('width: 50em;');
++            $run_tbl->addRow(array('Expected Output:', $expected_output_tb));
++            
++            break;
++        case 'run_per_host':
++            //command_file
++            $command_file_tb = new CInput('text', 'command$file'.$postfix, 
(string)$xml->command_file);
++            $command_file_tb->addStyle('width: 50em;');
++            $run_tbl->addRow(array('Command File:', $command_file_tb));
++            
++            //output_prefix
++            $output_prefix_tb = new CInput('text', 'output$prefix'.$postfix, 
(string)$xml->output_prefix);
++            $output_prefix_tb->addStyle('width: 50em;');
++            $run_tbl->addRow(array('Output Prefix:', $output_prefix_tb));
++            
++            //timeout
++            $timeout_tb = new CInput('text', 'timeout'.$postfix, 
(string)$xml->timeout);
++            $run_tbl->addRow(array('Timeout:', $timeout_tb));
++            
++            //expected_return_code
++            $expected_return_code_tb = new CInput('text', 
'expected$return$code'.$postfix, (string)$xml->expected_return_code);
++            $run_tbl->addRow(array('Expected Return Code:', 
$expected_return_code_tb));
++            
++            //expected_output
++            $expected_output_tb = new CInput('text', 
'expected$output'.$postfix, (string)$xml->expected_output);
++            $expected_output_tb->addStyle('width: 50em;');
++            $run_tbl->addRow(array('Expected Output:', $expected_output_tb));
++        
++            break;
++        case 'put':
++            //source
++            $userfiles = expfiles_getuserfiles();
++            $selectedfile = '';
++            if(!empty($xml->source)) $selectedfile = 
basename((string)$xml->source);
++            $source_cmb = new CComboBox('source'.$postfix);
++            foreach($userfiles as $uf)
++                $source_cmb->addItem($uf, $uf, ($selectedfile == 
$uf)?'yes':null);
++            $run_tbl->addRow(array('Source:', $source_cmb));
++            
++            //destination
++            $destination_tb = new CInput('text', 'destination'.$postfix, 
(string)$xml->destination);
++            $destination_tb->addStyle('width: 50em;');
++            $run_tbl->addRow(array('Destination:', $destination_tb));
++        
++            break;
++        case 'get':
++            //source
++            $source_tb = new CInput('text', 'source'.$postfix, 
(string)$xml->source);
++            $source_tb->addStyle('width: 50em;');
++            $run_tbl->addRow(array('Source:', $source_tb));
++            
++            //destination (removed because now all files should go to the 
user specific folder)
++            /*$destination_tb = new CInput('text', 'destination'.$postfix, 
(string)$xml->destination);
++            $destination_tb->addStyle('width: 50em;');
++            $run_tbl->addRow(array('Destination:', $destination_tb));*/
++            break;
++    }
++    
++    //Stop on fail
++    $stop_on_fail_chb = new CCheckBox('stop$on$fail'.$postfix, 
(((string)$xml->stop_on_fail) == 'false')?'no':'yes');
++    $run_tbl->addRow(array('Stop on fail:', $stop_on_fail_chb));
++    
++    return new CRow(array("$type:", $run_tbl), null, "row$postfix");
++    return $run_tbl;
++}
++
++//print_r($xml);
++
++if($new)
++    $main_frm = new CForm('post', 'tasklist.php?new=new');
++else
++    $main_frm = new CForm('post', 'tasklist.php?tid='.$tid);
++$main_tbl = new CTableInfo('');
++$main_tbl->attr('id', 'table_main');
++
++//Top Row:
++$btns_div = new CDiv();
++//'Add run' (all types)
++$run_cmb = new CComboBox('run');
++$run_cmb->attr('id', 'runs_main');
++$run_cmb->addItem('sequence', 'sequence');
++$run_cmb->addItem('run', 'run');
++$run_cmb->addItem('run_per_host', 'run_per_host');
++$run_cmb->addItem('put', 'put');
++$run_cmb->addItem('get', 'get');
++$btns_div->addItem($run_cmb);
++$add_btn = new CButton('add', 'Add', "javascript: 
new_node(jQuery('#runs_main').val(), '_'+counter, 'table_main', counter%2); 
counter++;");
++$btns_div->addItem($add_btn);
++
++$main_tbl->addRow(array('', $btns_div));
++
++//name attribute
++$name_tb = new CInput('text', 'name', (string)$xml['name']);
++$name_tb->addStyle('width: 50em;');
++$main_tbl->addRow(array('Name:', $name_tb));
++
++//description
++$desc_ta = new CTextArea('description', 
(empty($meta['description']))?'':$meta['description']);
++$main_tbl->addRow(array('Description:', $desc_ta));
++
++//shared
++$shared_chb = new CCheckBox('shared', (empty($meta['shared']))?'no':'yes');
++$main_tbl->addRow(array('Shared:', $shared_chb));
++
++//option 1 - Target
++/*$selected_target = 
isset($xml->options->target)?trim((string)$xml->options->target):'remote_ssh';
++$target_cmb = new CComboBox('target');
++foreach($targets as $t)
++    $target_cmb->addItem($t, $t, ($selected_target == $t)?'yes':null);
++$main_tbl->addRow(array('Target:', $target_cmb));*/
++
++//option 2 - Log dir
++$log_dir = 
isset($xml->options->log_dir)?trim((string)$xml->options->log_dir):'';
++$log_dir_tb = new CInput('text', 'log$dir', $log_dir);
++$log_dir_tb->addStyle('width: 50em;');
++$main_tbl->addRow(array('Log Dir:', $log_dir_tb));
++
++$counter = 1;
++foreach($xml->children() as $c)
++{
++    $name = trim($c->getName());
++    if($name == 'sequence')
++    {
++        $main_tbl->addRow(tlview_parseseq($c, '_'.$counter));
++        $counter++;
++    }
++    elseif($name == 'run' || $name == 'run_per_host' || $name == 'put' || 
$name == 'get')
++    {
++        $main_tbl->addRow(tlview_parserun($name, $c, '_'.$counter));
++        $counter++;
++    }
++}
++
++$main_frm->addItem($main_tbl);
++
++//$main_frm->addItem(new CInput('hidden', 'tid', $tid));
++if($new)
++    $main_frm->addItem(new CSubmit('add', 'Add'));
++else
++    $main_frm->addItem(new CSubmit('update', 'Update'));
++
++/*print "TESTING:<br/>";
++$tmp = tlview_parserun('run', $default_run, '_100');
++print $tmp->toString();
++print "END TESTING";*/
++
++
++?>
++
++<script>
++var counter = <?=$counter?>;
++
++function new_node(type, postfix, table_id, parity)
++{
++var html = '';
++switch(type)
++{
++case 'sequence':
++html = '<?php print tlview_parseseq($exptasklist_defaults["sequence"], 
"%placeholder%"); ?>';
++break;
++case 'run':
++html = '<?php print tlview_parserun("run", $exptasklist_defaults["run"], 
"%placeholder%"); ?>';
++break;
++case 'run_per_host':
++html = '<?php print tlview_parserun("run_per_host", 
$exptasklist_defaults["run_per_host"], "%placeholder%"); ?>';
++break;
++case 'put':
++html = '<?php print tlview_parserun("put", $exptasklist_defaults["put"], 
"%placeholder%"); ?>';
++break;
++case 'get':
++html = '<?php print tlview_parserun("get", $exptasklist_defaults["get"], 
"%placeholder%"); ?>';
++break;
++}
++
++html = html.replace(/%placeholder%/g, postfix);
++jQuery('#'+table_id).append(html);
++var cl = (parity == 0)?'even_row':'odd_row';
++jQuery('#row'+postfix).addClass(cl);
++jQuery('#row'+postfix).attr('origclass', cl);
++jQuery('#name'+postfix).focus();
++}
++
++</script>
++
++<?php
++
++return $main_frm;
+diff --git a/zabbix/frontends/php/include/views/experiments.tasklist.php 
b/zabbix/frontends/php/include/views/experiments.tasklist.php
+new file mode 100644
+index 0000000..e6e0ed8
+--- /dev/null
++++ b/zabbix/frontends/php/include/views/experiments.tasklist.php
+@@ -0,0 +1,41 @@
++<?php
++
++$tasklists = $this->get('tasklists');
++
++$tlWidget = new CWidget();
++
++$createForm = new CForm('get');
++$createForm->addItem(new CSubmit('new', 'Create tasklist'));
++
++$tlWidget->addPageHeader('CONFIGURATION OF TASKLISTS', $createForm);
++
++//main form
++$tlForm = new CForm('get');
++$tlForm->setName('tasklistForm');
++
++//main table
++$tlTable = new CTableInfo('No tasklists defined.');
++$tlTable->setHeader(array('Name', 'Description', 'User', 'Shared', ''));
++
++foreach($tasklists as $tl)
++{
++    //Name link
++    $name_lnk = new CLink($tl['name'], '?tid='.$tl['tasklistid']);
++    
++    //Delete link
++    $del_btn = new CButtonDelete('Are you sure you want to delete this 
tasklist?', $tl['tasklistid']);
++    
++    $tlTable->addRow(array(
++        $name_lnk,
++        ($tl['description'])?$tl['description']:'',
++        $tl['username'],
++        ($tl['shared'])?'Yes':'No',
++        $del_btn
++        ));
++}
++
++$tlForm->addItem($tlTable);
++
++$tlWidget->addItem($tlForm);
++
++return $tlWidget;
+diff --git 
a/zabbix/frontends/php/include/views/general.script.execute-parallel.php 
b/zabbix/frontends/php/include/views/general.script.execute-parallel.php
+new file mode 100644
+index 0000000..4bc5aca
+--- /dev/null
++++ b/zabbix/frontends/php/include/views/general.script.execute-parallel.php
+@@ -0,0 +1,54 @@
++<?php
++/*
++** Zabbix
++** Copyright (C) 2000-2011 Zabbix SIA
++**
++** This program is free software; you can redistribute it and/or modify
++** it under the terms of the GNU General Public License as published by
++** the Free Software Foundation; either version 2 of the License, or
++** (at your option) any later version.
++**
++** This program is distributed in the hope that it will be useful,
++** but WITHOUT ANY WARRANTY; without even the implied warranty of
++** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++** GNU General Public License for more details.
++**
++** You should have received a copy of the GNU General Public License
++** along with this program; if not, write to the Free Software
++** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA.
++**/
++
++
++//javascript item
++$js = new CJSscript();
++
++$numHosts = count($this->data['hosts']);
++
++$js->addItem("<div id=\"counter\" 
style=\"font-size:20px;padding:5px;\">0/$numHosts</div>");
++$js->addItem("<div id=\"content\"></div>");
++$js->addItem("<script type=\"text/javascript\" 
src=\"js/jquery/jquery.js\"></script>");
++$js->addItem("<script type=\"text/javascript\">");
++$js->addItem("var hosts = new Array();");
++$js->addItem("var ctr = 0;");
++
++for($i = 0; $i < $numHosts; $i++)
++{
++    $host = $this->data['hosts'][$i];
++    $js->addItem("hosts[$i] = ".$host['hostid'].";");
++}
++
++$sid = $this->data['sid'];
++$scriptid = $this->data['scriptid'];
++$js->addItem("for(var i=0;i<$numHosts;i++){
++    $.ajax({
++    url: 
\"scripts_exec.php?sid=$sid&execute=1&scriptid=$scriptid&strip=1&hostid=\"+hosts[i],
++    async: true,
++    success: function(data) { $('#content').append(data); ctr++; 
$('#counter').html(ctr+'/$numHosts') }
++    });
++}");
++
++
++//$js->addItem();
++$js->addItem("</script>");
++
++return $js;
+diff --git a/zabbix/frontends/php/include/views/general.script.execute.php 
b/zabbix/frontends/php/include/views/general.script.execute.php
+index 5f8d2f6..19eaec8 100644
+--- a/zabbix/frontends/php/include/views/general.script.execute.php
++++ b/zabbix/frontends/php/include/views/general.script.execute.php
+@@ -27,8 +27,17 @@ $scriptForm->setName('scriptForm');
+ 
+ // append tabs to form
+ $scriptTab = new CTabView();
+-$scriptTab->addTab('scriptTab', _s('Result of "%s"', 
$this->data['info']['name']), new CSpan($this->data['message'], 'pre 
fixedfont'));
++$body = new CSpan($this->data['message'],'pre fixedfont');
++if(isset($this->data['error']))
++{
++    $body = new CList(null, "messages");
++    $body->addItem(new CListItem($this->data['error'], "error"));
++}
++
++//    $scriptTab->addTab('errorTab', _s('ERROR'), new 
CSpan($this->data['error'], 'pre fixedfont'));
++$scriptTab->addTab('scriptTab', _s('Result of "%s" ON 
'.$this->data['host']['name'], $this->data['info']['name']), $body);
+ $scriptForm->addItem($scriptTab);
+ 
+ $scriptWidget->addItem($scriptForm);
++$scriptWidget->addItem(BR());
+ return $scriptWidget;
+diff --git a/zabbix/frontends/php/js/main.js b/zabbix/frontends/php/js/main.js
+index 4f14d4d..2bceabb 100644
+--- a/zabbix/frontends/php/js/main.js
++++ b/zabbix/frontends/php/js/main.js
+@@ -103,7 +103,7 @@ var PageRefresh = {
+  * Main menu
+  */
+ var MMenu = {
+-      menus:                  {'empty': 0, 'view': 0, 'cm': 0, 'reports': 0, 
'config': 0, 'admin': 0},
++      menus:                  {'empty': 0, 'view': 0, 'cm': 0, 'reports': 0, 
'config': 0, 'admin': 0, 'experiment':0},
+       def_label:              null,
+       sub_active:     false,
+       timeout_reset:  null,
+diff --git a/zabbix/frontends/php/manage_monitoring.php 
b/zabbix/frontends/php/manage_monitoring.php
+new file mode 100644
+index 0000000..a01bbfa
+--- /dev/null
++++ b/zabbix/frontends/php/manage_monitoring.php
+@@ -0,0 +1,61 @@
++<?php
++/*
++** Zabbix
++** Copyright (C) 2000-2011 Zabbix SIA
++**
++** This program is free software; you can redistribute it and/or modify
++** it under the terms of the GNU General Public License as published by
++** the Free Software Foundation; either version 2 of the License, or
++** (at your option) any later version.
++**
++** This program is distributed in the hope that it will be useful,
++** but WITHOUT ANY WARRANTY; without even the implied warranty of
++** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++** GNU General Public License for more details.
++**
++** You should have received a copy of the GNU General Public License
++** along with this program; if not, write to the Free Software
++** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA.
++**/
++
++require_once 'include/config.inc.php';
++require_once 'include/hosts.inc.php';
++require_once 'include/items.inc.php';
++require_once 'include/forms.inc.php';
++
++$page['title'] = _('Manage Monitoring');
++$page['file'] = 'manage_monitoring.php';
++
++define('ZBX_PAGE_NO_MENU', 1);
++
++// VAR        TYPE    OPTIONAL        FLAGS   VALIDATION      EXCEPTION
++$fields = array(
++      'template'      =>      array(T_ZBX_INT,        O_OPT,  P_SYS,          
DB_ID,  true),
++      'action'                =>      array(T_ZBX_STR,        O_OPT,  
NOT_EMPTY,      null,   true),
++);
++check_fields($fields);
++
++$templates = array_keys($_REQUEST['template']);
++
++//fetch template
++$options = array(
++      'templateids' => $templates,
++      'selectItems' => array(),
++      'output' => array('name')
++);
++$templates = API::Template()->get($options);
++
++//pull all item ids in array
++$all_items = array();
++foreach($templates as $temp)
++{
++      foreach($temp['items'] as $item)
++              $all_items[] = $item['itemid'];
++}
++
++//perform action
++DBstart();
++$go_result = ($_REQUEST['action'] == 
'disable')?disable_item($all_items):activate_item($all_items);
++$go_result = DBend($go_result);
++
++jsRedirect('dashboard.php');
+diff --git a/zabbix/frontends/php/results.php 
b/zabbix/frontends/php/results.php
+new file mode 100644
+index 0000000..6cf8a87
+--- /dev/null
++++ b/zabbix/frontends/php/results.php
+@@ -0,0 +1,101 @@
++<?php
++
++require_once dirname(__FILE__).'/include/config.inc.php';
++require_once dirname(__FILE__).'/include/experiments/inc.php';
++
++$page['title'] = _('Experiment Results');
++$page['file'] = 'results.php';
++$page['hist_arg'] = array('resid');
++
++require_once dirname(__FILE__).'/include/page_header.php';
++
++// VAR        TYPE    OPTIONAL        FLAGS   VALIDATION      EXCEPTION
++$fields = array(
++    'runid' =>   array(T_ZBX_INT, O_OPT, P_SYS|P_ACT, null, null),
++    'hostid' =>   array(T_ZBX_INT, O_OPT, P_SYS|P_ACT, null, null),
++    'delete' =>    array(T_ZBX_INT, O_OPT, P_SYS|P_ACT, null, null),
++    'interrupt' =>    array(T_ZBX_INT, O_OPT, P_SYS|P_ACT, null, null),
++    'rerun' =>    array(T_ZBX_INT, O_OPT, P_SYS|P_ACT, null, null)
++);
++check_fields($fields);
++
++/*
++ * Actions
++ */
++
++if(isset($_REQUEST['delete']))
++{
++    if(exprun_checkpermission($_REQUEST['delete']))
++    {
++        exprun_delete($_REQUEST['delete']);    
++        jsRedirect('results.php');
++    }
++    else
++        error("No permission to delete.");
++}
++
++if(isset($_REQUEST['interrupt']))
++{
++    if(exprun_checkpermission($_REQUEST['interrupt']))
++    {
++        exprun_interrupt($_REQUEST['interrupt']);
++        jsRedirect('results.php');
++    }
++    else
++        error("No permission to interrupt.");
++}
++
++if(isset($_REQUEST['rerun']))
++{
++    if(exprun_checkpermission($_REQUEST['rerun']))
++    {
++        exprun_rerun($_REQUEST['rerun']);
++        jsRedirect('results.php');
++    }
++    else
++        error("No permission to rerun.");
++}
++
++/*
++ * Display
++ */
++$resView = new CView('experiments.results');
++
++$results = exprun_getall(true);
++$resView->set('results', $results);
++
++if(isset($_REQUEST['runid']))
++{
++    if(exprun_verifyid($_REQUEST['runid']))
++    {
++        foreach($results as $r) //get the specific run that we want to 
display the log for
++        {
++            if($r['runid'] == $_REQUEST['runid'])
++            {
++                $run = $r;
++                break;
++            }
++        }
++        
++        $sep = 
"\n=================================================================\n";
++        $log = '';
++        foreach($run['nodes'] as $n)
++        {
++            if(isset($_REQUEST['hostid']) && $n['hostid'] == 
$_REQUEST['hostid']) //print the log of only a specific host
++            {
++                $log = $n['log'];
++                break;
++            }
++            else
++                $log .= $n['log'].$sep;
++        }
++        
++        $resView->set('log', $log);
++        $resView->set('runid', $run['runid']);
++    }
++}
++
++$resView->render();
++$resView->show();
++
++require_once dirname(__FILE__).'/include/page_footer.php';
+diff --git a/zabbix/frontends/php/scripts_exec.php 
b/zabbix/frontends/php/scripts_exec.php
+index d40b5a0..94775ee 100644
+--- a/zabbix/frontends/php/scripts_exec.php
++++ b/zabbix/frontends/php/scripts_exec.php
+@@ -27,23 +27,28 @@ $page['file'] = 'scripts_exec.php';
+ 
+ define('ZBX_PAGE_NO_MENU', 1);
+ 
+-require_once ('include/page_header.php');
++$strip = isset($_REQUEST['strip']);
++if(!$strip)
++    require_once ('include/page_header.php');
+ 
+ // VAR        TYPE    OPTIONAL        FLAGS   VALIDATION      EXCEPTION
+ $fields = array(
+-      'hostid' =>             array(T_ZBX_INT, O_OPT, P_SYS, DB_ID,           
'isset({execute})'),
++      'hostid' =>             array(T_ZBX_INT, O_OPT, P_SYS, DB_ID,           
'!isset({groupid})&&!isset({hosts})'),
+       'scriptid' =>   array(T_ZBX_INT, O_OPT, P_SYS, DB_ID,           
'isset({execute})'),
++      'groupid' =>    array(T_ZBX_INT, O_OPT, P_SYS, DB_ID,       
'!isset({hostid})&&!isset({hosts})'),
++      'hosts' =>              array(T_ZBX_INT, O_OPT, P_SYS, DB_ID,       
'!isset({hostid})&&!isset({groupid})'),
+       'execute' =>    array(T_ZBX_INT, O_OPT, P_ACT, IN('0,1'),       null)
+ );
+ check_fields($fields);
+ 
+-if (isset($_REQUEST['execute'])) {
+-      $scriptid = get_request('scriptid');
+-      $hostid = get_request('hostid');
+-
+-      $data = array(
++function execute_script($scriptid, $hostid)
++{
++    global $strip;
++    
++    $data = array(
+               'message' => '',
+-              'info' => DBfetch(DBselect('SELECT s.name FROM scripts s WHERE 
s.scriptid='.$scriptid))
++              'info' => DBfetch(DBselect('SELECT s.name FROM scripts s WHERE 
s.scriptid='.$scriptid)),
++              'host' => DBfetch(DBselect('SELECT h.name FROM hosts h WHERE 
h.hostid='.$hostid))
+       );
+ 
+       $result = API::Script()->execute(array('hostid' => $hostid, 'scriptid' 
=> $scriptid));
+@@ -53,8 +58,10 @@ if (isset($_REQUEST['execute'])) {
+               $isErrorExist = true;
+       }
+       elseif ($result['response'] == 'failed') {
+-              error($result['value']);
+-              $isErrorExist = true;
++          if($strip) $data['error'] = $result['value'];
++              else
++                  error($result['value']);
++          $isErrorExist = true;
+       }
+       else {
+               $data['message'] = $result['value'];
+@@ -70,4 +77,46 @@ if (isset($_REQUEST['execute'])) {
+       $scriptView->show();
+ }
+ 
+-require_once 'include/page_footer.php';
++if (isset($_REQUEST['execute'])) {
++      $scriptid = get_request('scriptid');
++      
++      if(isset($_REQUEST['groupid']) || isset($_REQUEST['hosts']))
++      {
++              if(isset($_REQUEST['groupid']))
++              {
++                      $groupid = get_request('groupid');
++                      
++                      $hosts = API::Host()->get(array(
++                              'groupids' => array($groupid),
++                              'editable' => 1,
++                              'output' => API_OUTPUT_EXTEND
++                      ));
++              }
++              else
++              {
++                      $hosts = API::Host()->get(array(
++                              'hostids' => get_request('hosts'),
++                              'editable' => 1,
++                              'output' => API_OUTPUT_EXTEND
++                      ));
++              }
++              
++              $data = array();
++              $data['hosts'] = $hosts;
++              $data['scriptid'] = $scriptid;
++              $data['sid'] = get_request('sid');
++              
++              $scriptView = new CView('general.script.execute-parallel', 
$data);
++      $scriptView->render();
++      $scriptView->show();
++              
++      }
++      elseif(isset($_REQUEST['hostid']))
++      {
++          $hostid = get_request('hostid');
++      execute_script($scriptid, $hostid);
++      }
++}
++
++if(!$strip)
++    require_once 'include/page_footer.php';
+diff --git a/zabbix/frontends/php/targets.php 
b/zabbix/frontends/php/targets.php
+new file mode 100644
+index 0000000..0d5e121
+--- /dev/null
++++ b/zabbix/frontends/php/targets.php
+@@ -0,0 +1,50 @@
++<?php
++
++error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT);
++
++require_once dirname(__FILE__).'/include/config.inc.php';
++require_once dirname(__FILE__).'/include/experiments/inc.php';
++
++$page['title'] = _('Target Configuration');
++$page['file'] = 'targets.php';
++$page['hist_arg'] = array('targetid');
++
++require_once dirname(__FILE__).'/include/page_header.php';
++
++/*
++ * Actions
++ */
++//print_r($_REQUEST);
++
++if(isset($_REQUEST['target']) && isset($_REQUEST['apply']))
++{
++    switch($_REQUEST['target'])
++    {
++        case 'ssh':
++            if(isset($_REQUEST['sshhosts']))
++                expssh_updatehosts($_REQUEST['sshhosts']);
++        
++            break;
++        
++        case 'planetlab':
++            if(isset($_REQUEST['plnodes']) && is_array($_REQUEST['plnodes']))
++                exppl_updateSliceNodes($_REQUEST['plnodes']);
++            break;
++    }
++}
++
++/*
++ * Display
++ */
++$targetsView = new CView('experiments.targets');
++
++$targetsView->set('targetlist', $exp_targetlist);
++if(isset($_REQUEST['target'])) $targetsView->set('selected_target', 
$_REQUEST['target']);
++$targetsView->set('sshhosts', expnodes_gethosts('ssh'));
++if(isset($_REQUEST['ploffset'])) $targetsView->set('ploffset', 
$_REQUEST['ploffset']);
++if(isset($_REQUEST['plfilter']) && trim($_REQUEST['plfilter']) != '') 
$targetsView->set('plfilter', $_REQUEST['plfilter']);
++
++$targetsView->render();
++$targetsView->show();
++
++require_once dirname(__FILE__).'/include/page_footer.php';
+diff --git a/zabbix/frontends/php/tasklist.php 
b/zabbix/frontends/php/tasklist.php
+new file mode 100644
+index 0000000..fa43c0d
+--- /dev/null
++++ b/zabbix/frontends/php/tasklist.php
+@@ -0,0 +1,104 @@
++<?php
++
++require_once dirname(__FILE__).'/include/config.inc.php';
++require_once dirname(__FILE__).'/include/experiments/inc.php';
++
++$page['title'] = _('Tasklists');
++$page['file'] = 'tasklist.php';
++$page['hist_arg'] = array('taskid');
++
++require_once dirname(__FILE__).'/include/page_header.php';
++
++// VAR        TYPE    OPTIONAL        FLAGS   VALIDATION      EXCEPTION
++/*$fields = array(
++      'tid' =>                array(T_ZBX_INT, O_OPT, P_SYS, null, null),
++);
++check_fields($fields);*/
++
++
++/*
++ * Actions
++ */
++if(isset($_REQUEST['tid']) && isset($_REQUEST['update']))
++{
++    $tid = intval($_REQUEST['tid']);
++    if(exptasklist_allowed($tid) == 2) //check user permission (read/write)
++        exptasklist_update($tid, $_REQUEST);
++    else
++        error("Permission denied!");
++}
++if(isset($_REQUEST['add']))
++{
++    if(exptasklist_add($_REQUEST))
++        jsRedirect('tasklist.php');
++}
++if(isset($_REQUEST['delete']))
++{
++    $tid = intval(substr($_REQUEST['delete'], 1));
++    
++    if(exptasklist_allowed($tid) == 2)
++    {
++        if(exptasklist_delete($tid))
++            jsRedirect('tasklist.php');
++    }
++    else
++        error("Permission denied!");
++}
++
++
++/*
++ * Display
++ */
++if(isset($_REQUEST['tid']))
++{
++    $tid = intval($_REQUEST['tid']);
++    if(exptasklist_allowed($tid) > 0) //check user permission (read or 
read/write)
++    {
++        //Get tasklist metadata
++        $meta = exptasklist_getbyid($tid);
++        //Get tasklist XML content
++        $xml = exptasklist_getcontent($tid);
++        if($xml)
++        {
++            $tlView = new CView('experiments.tasklist.edit');
++
++            $tlView->set('tid', $tid);
++            $tlView->set('xml', simplexml_load_string($xml));
++            //$tlView->set('targets', exp_gettargets());
++            $tlView->set('meta', $meta);
++            $tlView->set('exptasklist_defaults', $exptasklist_defaults);
++            $tlView->set('userfiles', expfiles_getuserfiles());
++
++            $tlView->render();
++            $tlView->show();
++
++        }
++        else
++            error("Error while loading tasklist!");
++    }
++    else
++        error("Permission denied!");
++}
++elseif(isset($_REQUEST['new']))
++{
++    $tlView = new CView('experiments.tasklist.edit');
++    
++    $tlView->set('new', true);
++    //$tlView->set('targets', exp_gettargets());
++    $tlView->set('exptasklist_defaults', $exptasklist_defaults);
++    $tlView->set('userfiles', expfiles_getuserfiles());
++    
++    $tlView->render();
++    $tlView->show();
++}
++else
++{
++    $tlView = new CView('experiments.tasklist');
++    
++    $tlView->set('tasklists', exptasklist_getall(true));
++    
++    $tlView->render();
++    $tlView->show();
++}
++
++require_once dirname(__FILE__).'/include/page_footer.php';
+diff --git a/zabbix/zabbix.sql b/zabbix/zabbix.sql
+new file mode 100644
+index 0000000..7e43628
+--- /dev/null
++++ b/zabbix/zabbix.sql
+@@ -0,0 +1,139 @@
++-- phpMyAdmin SQL Dump
++-- version 3.4.11.1deb2
++-- http://www.phpmyadmin.net
++--
++-- Host: localhost
++-- Generation Time: Sep 26, 2013 at 04:39 PM
++-- Server version: 5.5.31
++-- PHP Version: 5.4.4-14+deb7u4
++
++SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
++SET time_zone = "+00:00";
++
++
++/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
++/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
++/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
++/*!40101 SET NAMES utf8 */;
++
++--
++-- Database: `zabbix`
++--
++
++-- --------------------------------------------------------
++
++--
++-- Table structure for table `exp_config`
++--
++
++CREATE TABLE IF NOT EXISTS `exp_config` (
++  `configid` int(11) NOT NULL AUTO_INCREMENT,
++  `section` varchar(100) COLLATE utf8_bin NOT NULL,
++  `name` varchar(200) COLLATE utf8_bin NOT NULL,
++  `label` varchar(100) COLLATE utf8_bin NOT NULL,
++  `description` text COLLATE utf8_bin,
++  `type` varchar(100) COLLATE utf8_bin NOT NULL,
++  `default_value` varchar(500) COLLATE utf8_bin NOT NULL,
++  `user_editable` tinyint(1) NOT NULL,
++  PRIMARY KEY (`configid`)
++) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=29 ;
++
++-- --------------------------------------------------------
++
++--
++-- Table structure for table `exp_configenum`
++--
++
++CREATE TABLE IF NOT EXISTS `exp_configenum` (
++  `id` int(11) NOT NULL AUTO_INCREMENT,
++  `configid` int(11) NOT NULL,
++  `label` text COLLATE utf8_bin NOT NULL,
++  `value` text COLLATE utf8_bin NOT NULL,
++  PRIMARY KEY (`id`)
++) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=3 ;
++
++-- --------------------------------------------------------
++
++--
++-- Table structure for table `exp_host`
++--
++
++CREATE TABLE IF NOT EXISTS `exp_host` (
++  `hostid` int(11) NOT NULL AUTO_INCREMENT,
++  `target` varchar(200) COLLATE utf8_bin NOT NULL,
++  `userid` int(11) NOT NULL,
++  `host` text COLLATE utf8_bin NOT NULL,
++  `pl_nodeid` int(11) DEFAULT NULL,
++  PRIMARY KEY (`hostid`,`target`)
++) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=1580 ;
++
++-- --------------------------------------------------------
++
++--
++-- Table structure for table `exp_run`
++--
++
++CREATE TABLE IF NOT EXISTS `exp_run` (
++  `runid` int(11) NOT NULL AUTO_INCREMENT,
++  `startedon` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
++  `usetasklist` tinyint(1) NOT NULL DEFAULT '1',
++  `tasklistid` int(11) DEFAULT NULL,
++  `command` varchar(200) COLLATE utf8_bin DEFAULT NULL,
++  `target` varchar(200) COLLATE utf8_bin NOT NULL,
++  `pid` int(11) DEFAULT NULL,
++  `userid` int(11) NOT NULL,
++  `status` int(11) NOT NULL DEFAULT '0',
++  `percentage` double NOT NULL DEFAULT '0',
++  `fullcommand` text COLLATE utf8_bin,
++  PRIMARY KEY (`runid`)
++) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=75 ;
++
++-- --------------------------------------------------------
++
++--
++-- Table structure for table `exp_runnode`
++--
++
++CREATE TABLE IF NOT EXISTS `exp_runnode` (
++  `runid` int(11) NOT NULL,
++  `hostid` int(11) NOT NULL,
++  `target` varchar(200) COLLATE utf8_bin NOT NULL,
++  `status` int(11) NOT NULL DEFAULT '0',
++  `percentage` double NOT NULL DEFAULT '0',
++  `log` text COLLATE utf8_bin NOT NULL,
++  PRIMARY KEY (`runid`,`hostid`,`target`)
++) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
++
++-- --------------------------------------------------------
++
++--
++-- Table structure for table `exp_tasklist`
++--
++
++CREATE TABLE IF NOT EXISTS `exp_tasklist` (
++  `tasklistid` int(11) NOT NULL AUTO_INCREMENT,
++  `name` varchar(100) COLLATE utf8_bin NOT NULL,
++  `description` text COLLATE utf8_bin,
++  `fsname` varchar(100) COLLATE utf8_bin NOT NULL,
++  `userid` int(11) NOT NULL,
++  `shared` tinyint(1) NOT NULL,
++  PRIMARY KEY (`tasklistid`)
++) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=24 ;
++
++-- --------------------------------------------------------
++
++--
++-- Table structure for table `exp_userconfig`
++--
++
++CREATE TABLE IF NOT EXISTS `exp_userconfig` (
++  `configid` int(11) NOT NULL,
++  `userid` int(11) NOT NULL,
++  `value` varchar(500) COLLATE utf8_bin NOT NULL,
++  `enabled` tinyint(1) NOT NULL,
++  PRIMARY KEY (`configid`,`userid`)
++) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
++
++/*!40101 SET address@hidden */;
++/*!40101 SET address@hidden */;
++/*!40101 SET address@hidden */;




reply via email to

[Prev in Thread] Current Thread [Next in Thread]