r1823 + now fix URLs...
[racktables] / inc / ophandlers.php
index 226e096..9607f99 100644 (file)
-<?
+<?php
 /*
 *
 *  This file is a library of operation handlers for RackTables.
 *
 */
 
+// This function assures that specified argument was passed
+// and is a number greater than zero.
+function assertUIntArg ($argname, $allow_zero = FALSE)
+{
+       if (!isset ($_REQUEST[$argname]))
+       {
+               showError ("Parameter '${argname}' is missing.", __FUNCTION__);
+               die();
+       }
+       if (!is_numeric ($_REQUEST[$argname]))
+       {
+               showError ("Parameter '${argname}' is not a number.", __FUNCTION__);
+               die();
+       }
+       if ($_REQUEST[$argname] < 0)
+       {
+               showError ("Parameter '${argname}' is less than zero.", __FUNCTION__);
+               die();
+       }
+       if (!$allow_zero and $_REQUEST[$argname] == 0)
+       {
+               showError ("Parameter '${argname}' is equal to zero.", __FUNCTION__);
+               die();
+       }
+}
+
+// This function assures that specified argument was passed
+// and is a non-empty string.
+function assertStringArg ($argname, $ok_if_empty = FALSE)
+{
+       if (!isset ($_REQUEST[$argname]))
+       {
+               showError ("Parameter '${argname}' is missing.", __FUNCTION__);
+               die();
+       }
+       if (!is_string ($_REQUEST[$argname]))
+       {
+               showError ("Parameter '${argname}' is not a string.", __FUNCTION__);
+               die();
+       }
+       if (!$ok_if_empty and empty ($_REQUEST[$argname]))
+       {
+               showError ("Parameter '${argname}' is an empty string.", __FUNCTION__);
+               die();
+       }
+}
+
+function assertBoolArg ($argname, $ok_if_empty = FALSE)
+{
+       if (!isset ($_REQUEST[$argname]))
+       {
+               showError ("Parameter '${argname}' is missing.", __FUNCTION__);
+               die();
+       }
+       if (!is_string ($_REQUEST[$argname]) or $_REQUEST[$argname] != 'on')
+       {
+               showError ("Parameter '${argname}' is not a string.", __FUNCTION__);
+               die();
+       }
+       if (!$ok_if_empty and empty ($_REQUEST[$argname]))
+       {
+               showError ("Parameter '${argname}' is an empty string.", __FUNCTION__);
+               die();
+       }
+}
+
+function assertIPv4Arg ($argname, $ok_if_empty = FALSE)
+{
+       assertStringArg ($argname, $ok_if_empty);
+       if (!empty ($_REQUEST[$argname]) and long2ip (ip2long ($_REQUEST[$argname])) !== $_REQUEST[$argname])
+       {
+               showError ("IPv4 address validation failed for value '" . $_REQUEST[$argname] . "'", __FUNCTION__);
+               die();
+       }
+}
+
 function addPortForwarding ()
 {
        global $root, $pageno, $tabno;
 
+       assertUIntArg ('object_id');
+       assertIPv4Arg ('localip');
+       assertIPv4Arg ('remoteip');
+       assertUIntArg ('localport');
+       assertUIntArg ('proto');
+       assertStringArg ('description', TRUE);
        $object_id = $_REQUEST['object_id'];
        $localip = $_REQUEST['localip'];
        $remoteip = $_REQUEST['remoteip'];
        $localport = $_REQUEST['localport'];
        $remoteport = $_REQUEST['remoteport'];
        $proto = $_REQUEST['proto'];
-       $mode = $_REQUEST['mode'];
        $description = $_REQUEST['description'];
+       if (empty ($remoteport))
+               $remoteport = $localport;
 
        $retpage="${root}?page=${pageno}&tab=${tabno}&object_id=$object_id";
 
@@ -42,7 +125,6 @@ function delPortForwarding ()
        $localport = $_REQUEST['localport'];
        $remoteport = $_REQUEST['remoteport'];
        $proto = $_REQUEST['proto'];
-       $mode = $_REQUEST['mode'];
 
        $retpage="${root}?page=${pageno}&tab=${tabno}&object_id=$object_id";
 
@@ -80,8 +162,6 @@ function updPortForwarding ()
        
 }
 
-
-
 function addPortForObject ()
 {
        global $root, $pageno, $tabno;
@@ -278,6 +358,17 @@ http://www.cisco.com/en/US/products/hw/routers/ps274/products_tech_note09186a008
                                        'label' => "${ifnumber}"
                                );
                                break;
+                       case 'ssv1':
+                               $words = explode (' ', $line);
+                               if (empty ($words[0]) or empty ($words[1]))
+                                       continue;
+                               $ports[] = array
+                               (
+                                       'name' => $words[0],
+                                       'l2address' => $words[1],
+                                       'label' => ''
+                               );
+                               break;
                        default:
                                return
                                        "${root}?page=${pageno}&tab=${tabno}&object_id=${object_id}&error=" .
@@ -410,7 +501,8 @@ function addNewRange ()
 
        $range = $_REQUEST['range'];
        $name = $_REQUEST['name'];
-       $error = addRange($range, $name);
+       $is_bcast = $_REQUEST['is_bcast'];
+       $error = addRange($range, $name, $is_bcast == 'on');
        if ($error != '')
        {
                return "${root}?page=${pageno}&tab=${tabno}&error=".urlencode($error);
@@ -482,19 +574,19 @@ function addAddressToObject ()
 {
        global $root, $pageno, $tabno;
 
-       $ip = $_REQUEST['ip'];
+       assertStringArg ('ip');
+       assertUIntArg ('object_id');
+       assertStringArg ('name', TRUE);
+       assertStringArg ('type');
+       // Strip masklen.
+       $ip = ereg_replace ('/[[:digit:]]+$', '', $_REQUEST['ip']);
        $object_id = $_REQUEST['object_id'];
-       $name = $_REQUEST['name'];
-       $type = $_REQUEST['type'];
-       $error = bindIpToObject($ip, $object_id, $name, $type);
+       $error = bindIpToObject($ip, $object_id, $_REQUEST['name'], $_REQUEST['type']);
        if ($error != '')
-       {
-               return "${root}?page=${pageno}&tab=${tabno}&object_id=$object_id&error=".urlencode($error);
-       }
+               return "${root}?page=${pageno}&tab=${tabno}&object_id=${object_id}&error=".urlencode($error);
        else
-       {
-               return "${root}?page=$pageno&tab=${tabno}&object_id=$object_id&message=".urlencode("Interface successfully added");
-       }
+               return "${root}?page=$pageno&tab=${tabno}&object_id=${object_id}&message=".
+                       urlencode("Address ${ip} was added successfully.");
 }
 
 function createUserAccount ()
@@ -526,7 +618,7 @@ function updateUserAccount ()
        $old_hash = getHashByID ($id);
        if ($old_hash == NULL)
        {
-               showError ('getHashByID() failed in updateUserAccount()');
+               showError ('getHashByID() failed', __FUNCTION__);
                return;
        }
        // Update user password only if provided password is not the same as current password hash.
@@ -642,7 +734,7 @@ function savePortMap ()
                                                        $error_count++;
                                                break;
                                        default:
-                                               showError ('oldCompatTable is invalid in savePortMap()');
+                                               showError ('oldCompatTable is invalid', __FUNCTION__);
                                                break;
                                }
        return
@@ -791,19 +883,58 @@ function resetAttrValue ()
                return "${root}?page=${pageno}&tab=${tabno}&object_id=${object_id}&error=" . urlencode ("Reset failed!");
 }
 
-function updateAttrValue ()
+function updateAttrValues ()
 {
        global $root, $pageno, $tabno;
-       assertUIntArg ('attr_id');
        assertUIntArg ('object_id');
-       // The value could be uint/float, but we don't know ATM. Let SQL
-       // server check this and complain.
-       assertStringArg ('value');
        $object_id = $_REQUEST['object_id'];
-       if (commitUpdateAttrValue ($object_id, $_REQUEST['attr_id'], $_REQUEST['value']) === TRUE)
-               return "${root}?page=${pageno}&tab=${tabno}&object_id=${object_id}&message=" . urlencode ('Update succeeded.');
-       else
+       $oldvalues = getAttrValues ($object_id);
+
+       assertUIntArg ('num_attrs');
+       $num_attrs = $_REQUEST['num_attrs'];
+       $result = array();
+
+       for ($i = 0; $i < $num_attrs; $i++)
+       {
+               assertUIntArg ("${i}_attr_id");
+               $attr_id = $_REQUEST["${i}_attr_id"];
+
+               // Field is empty, delete attribute and move on.
+               if (empty($_REQUEST["${i}_value"]))
+               {
+                       commitResetAttrValue ($object_id, $attr_id);
+                       continue;
+               }
+
+               // The value could be uint/float, but we don't know ATM. Let SQL
+               // server check this and complain.
+               assertStringArg ("${i}_value");
+               $value = $_REQUEST["${i}_value"];
+               switch ($oldvalues[$attr_id]['type'])
+               {
+                       case 'uint':
+                       case 'float':
+                       case 'string':
+                               $oldvalue = $oldvalues[$attr_id]['value'];
+                               break;
+                       case 'dict':
+                               $oldvalue = $oldvalues[$attr_id]['key'];
+                               break;
+                       default:
+                               showError ('Internal structure error', __FUNCTION__);
+                               die;
+               }
+               if ($value == $oldvalue)
+                       continue;
+
+               // Note if the queries succeed or not, it determines which page they see.
+               $result[] = commitUpdateAttrValue ($object_id, $attr_id, $value);
+       }
+
+       if (in_array(false, $result))
                return "${root}?page=${pageno}&tab=${tabno}&object_id=${object_id}&error=" . urlencode ("Update failed!");
+
+       return "${root}?page=${pageno}&tab=${tabno}&object_id=${object_id}&message=" . urlencode ('Update succeeded.');
 }
 
 function useupPort ()
@@ -818,59 +949,442 @@ function useupPort ()
                return "${root}?page=${pageno}&tab=${tabno}&object_id=${object_id}&error=" . urlencode ("Error removing reservation!");
 }
 
-// This function processes a submit from the VLAN configuration form.
-// It doesn't check any data at the moment, relying on a smart gateway.
-// It doesn't even check if the a port already belongs to the VLAN it
-// is being requested to be put into. This behaviour implies having a
-// smart enough gateway, which unconditionally fetches the current
-// configuration and then filters out 'set' requests. The gateway must
-// validate port names and VLAN numbers as well. Ouch.
-function updateVLANMembership ()
+function updateUI ()
 {
-       global $root, $pageno, $tabno, $remote_username;
-       assertUIntArg ('object_id');
-       assertUIntArg ('portcount');
-       $object_id = $_REQUEST['object_id'];
-       $portcount  = $_REQUEST['portcount'];
+       global $root, $pageno, $tabno;
+       $oldvalues = loadConfigCache();
 
-       $endpoints = findAllEndpoints ($object_id);
-       if (count ($endpoints) == 0)
-               return "${root}?page=${pageno}&tab=${tabno}&object_id=${object_id}&error=" .
-                       urlencode ('Can\'t find any mean to reach current object. Please either set FQDN attribute or assign an IP address to the object.');
-       elseif (count ($endpoints) > 1)
-               return "${root}?page=${pageno}&tab=${tabno}&object_id=${object_id}&error=" .
-                       urlencode ('More than one IP address is assigned to this object, please configure FQDN attribute.');
+       assertUIntArg ('num_vars');
+       $num_vars = $_REQUEST['num_vars'];
+       $error = '';
 
-// Just convert the input and feed it into the gateway.
-       $questions = array();
-       for ($i = 0; $i < $portcount; $i++)
+       for ($i = 0; $i < $num_vars; $i++)
        {
-               if (!isset ($_REQUEST["portname_${i}"]))
+               assertStringArg ("${i}_varname");
+               assertStringArg ("${i}_varvalue", TRUE);
+               $varname = $_REQUEST["${i}_varname"];
+               $varvalue = $_REQUEST["${i}_varvalue"];
+
+               // If form value = value in DB, don't bother updating DB
+               if ($varvalue == getConfigVar ($varname))
                        continue;
-               if (!isset ($_REQUEST["vlanid_${i}"]))
+
+               // Note if the queries succeed or not, it determines which page they see.
+               $error = setConfigVar ($varname, $varvalue, TRUE);
+               if (!empty ($error))
+                       break;
+       }
+
+       if ($error != '')
+               return "${root}?page=${pageno}&tab=${tabno}&error=" . urlencode ("Update failed with error: " . $error);
+
+       return "${root}?page=${pageno}&tab=${tabno}&message=" . urlencode ("Update succeeded.");
+}
+
+function resetUIConfig()
+{
+       global $root, $pageno, $tabno;
+       setConfigVar ('default_port_type','24');
+       setConfigVar ('MASSCOUNT','15');
+       setConfigVar ('MAXSELSIZE','30');
+       setConfigVar ('NAMEFUL_OBJTYPES','4,7,8');
+       setConfigVar ('ROW_SCALE','2');
+       setConfigVar ('PORTS_PER_ROW','12');
+       setConfigVar ('IPV4_ADDRS_PER_PAGE','256');
+       setConfigVar ('DEFAULT_RACK_HEIGHT','42');
+       setConfigVar ('REQUIRE_ASSET_TAG_FOR','4,7,8');
+       setConfigVar ('USER_AUTH_SRC','database');
+       setConfigVar ('DEFAULT_SLB_VS_PORT','');
+       setConfigVar ('DEFAULT_SLB_RS_PORT','');
+       setConfigVar ('IPV4_PERFORMERS','1,4,7,8,12,14,445,447');
+       setConfigVar ('NATV4_PERFORMERS','4,7,8');
+       setConfigVar ('DETECT_URLS','no');
+       setConfigVar ('RACK_PRESELECT_THRESHOLD','1');
+       setConfigVar ('DEFAULT_IPV4_RS_INSERVICE','no');
+       setConfigVar ('AUTOPORTS_CONFIG','4 = 1*33*kvm + 2*24*eth%u;15 = 1*446*kvm');
+       setConfigVar ('SHOW_EXPLICIT_TAGS','yes');
+       setConfigVar ('SHOW_IMPLICIT_TAGS','yes');
+       setConfigVar ('SHOW_AUTOMATIC_TAGS','no');
+       setConfigVar ('DEFAULT_OBJECT_TYPE','4');
+       return "${root}?page=${pageno}&tab=default&message=" . urlencode ("Reset complete");
+}
+
+// Add single record.
+function addRealServer ()
+{
+       global $root, $pageno, $tabno;
+
+       assertUIntArg ('id');
+       assertIPv4Arg ('remoteip');
+       assertUIntArg ('rsport');
+       assertStringArg ('rsconfig', TRUE);
+       $pool_id = $_REQUEST['id'];
+       if (!addRStoRSPool ($pool_id, $_REQUEST['remoteip'], $_REQUEST['rsport'], getConfigVar ('DEFAULT_IPV4_RS_INSERVICE'), $_REQUEST['rsconfig']))
+               return "${root}?page=${pageno}&tab=${tabno}&pool_id=${pool_id}&error=" . urlencode ('addRStoRSPool() failed');
+       else
+               return "${root}?page=${pageno}&tab=${tabno}&pool_id=${pool_id}&message=" . urlencode ("Real server was successfully added");
+}
+
+// Parse textarea submitted and try adding a real server for each line.
+function addRealServers ()
+{
+       global $root, $pageno, $tabno;
+
+       assertUIntArg ('id');
+       assertStringArg ('format');
+       assertStringArg ('rawtext');
+       $pool_id = $_REQUEST['id'];
+       $rawtext = str_replace ('\r', '', $_REQUEST['rawtext']);
+       $ngood = $nbad = 0;
+       $rsconfig = '';
+       // Keep in mind, that the text will have HTML entities (namely '>') escaped.
+       foreach (explode ('\n', $rawtext) as $line)
+       {
+               if (empty ($line))
                        continue;
-               $portname = $_REQUEST["portname_${i}"];
-               $vlanid = $_REQUEST["vlanid_${i}"];
-               $questions[] = "set ${portname} ${vlanid}";
+               $match = array ();
+               switch ($_REQUEST['format'])
+               {
+                       case 'ipvs_2': // address and port only
+                               if (!preg_match ('/^  -&gt; ([0-9\.]+):([0-9]+) /', $line, $match))
+                                       continue;
+                               if (addRStoRSPool ($pool_id, $match[1], $match[2], getConfigVar ('DEFAULT_IPV4_RS_INSERVICE'), ''))
+                                       $ngood++;
+                               else
+                                       $nbad++;
+                               break;
+                       case 'ipvs_3': // address, port and weight
+                               if (!preg_match ('/^  -&gt; ([0-9\.]+):([0-9]+) +[a-zA-Z]+ +([0-9]+) /', $line, $match))
+                                       continue;
+                               if (addRStoRSPool ($pool_id, $match[1], $match[2], getConfigVar ('DEFAULT_IPV4_RS_INSERVICE'), 'weight ' . $match[3]))
+                                       $ngood++;
+                               else
+                                       $nbad++;
+                               break;
+                       case 'ssv_2': // IP address and port
+                               if (!preg_match ('/^([0-9\.]+) ([0-9]+)$/', $line, $match))
+                                       continue;
+                               if (addRStoRSPool ($pool_id, $match[1], $match[2], getConfigVar ('DEFAULT_IPV4_RS_INSERVICE'), ''))
+                                       $ngood++;
+                               else
+                                       $nbad++;
+                               break;
+                       default:
+                               return "${root}?page=${pageno}&tab=${tabno}&id=${pool_id}&error=" . urlencode (__FUNCTION__ . ': invalid format requested');
+                               break;
+               }
        }
-       $data = queryGateway
-       (
-               $tabno,
-               array ($endpoints[0], 'hwtype', 'swtype', $remote_username),
-               $questions
-       );
-       $error_count = $success_count = 0;
-       foreach ($data as $reply)
-               if (strncmp ($reply, 'OK!', 3))
-                       $error_count++;
+       if ($nbad == 0 and $ngood > 0)
+               return "${root}?page=${pageno}&tab=${tabno}&pool_id=${pool_id}&message=" . urlencode ("Successfully added ${ngood} real servers");
+       else
+               return "${root}?page=${pageno}&tab=${tabno}&pool_id=${pool_id}&error=" . urlencode ("Added ${ngood} real servers and encountered ${nbad} errors");
+}
+
+function addVService ()
+{
+       global $root, $pageno, $tabno;
+
+       assertIPv4Arg ('vip');
+       assertUIntArg ('vport');
+       assertStringArg ('proto');
+       $proto = $_REQUEST['proto'];
+       if ($proto != 'TCP' and $proto != 'UDP')
+               return "${root}?page=${pageno}&tab=${tabno}&error=" . urlencode (__FUNCTION__ . ': invalid protocol');
+       assertStringArg ('name', TRUE);
+       assertStringArg ('vsconfig', TRUE);
+       assertStringArg ('rsconfig', TRUE);
+       $pool_id = $_REQUEST['id'];
+       if (!commitCreateVS ($_REQUEST['vip'], $_REQUEST['vport'], $proto, $_REQUEST['name'], $_REQUEST['vsconfig'], $_REQUEST['rsconfig']))
+               return "${root}?page=${pageno}&tab=${tabno}&error=" . urlencode ('commitCreateVS() failed');
+       else
+               return "${root}?page=${pageno}&tab=${tabno}&message=" . urlencode ("Virtual service was successfully created");
+}
+
+function deleteRealServer ()
+{
+       global $root, $pageno, $tabno;
+
+       assertUIntArg ('pool_id');
+       assertUIntArg ('id');
+       $pool_id = $_REQUEST['pool_id'];
+       if (!commitDeleteRS ($_REQUEST['id']))
+               return "${root}?page=${pageno}&tab=${tabno}&pool_id=${pool_id}&error=" . urlencode ('commitDeleteRS() failed');
+       else
+               return "${root}?page=${pageno}&tab=${tabno}&pool_id=${pool_id}&message=" . urlencode ("Real server was successfully deleted");
+}
+
+function deleteLoadBalancer ()
+{
+       global $root, $pageno, $tabno;
+
+       assertUIntArg ('object_id');
+       assertUIntArg ('pool_id');
+       assertUIntArg ('vs_id');
+       $pool_id = $_REQUEST['pool_id'];
+       if (!commitDeleteLB ($_REQUEST['object_id'], $pool_id, $_REQUEST['vs_id']))
+               return "${root}?page=${pageno}&tab=${tabno}&pool_id=${pool_id}&error=" . urlencode ('commitDeleteLB() failed');
+       else
+               return "${root}?page=${pageno}&tab=${tabno}&pool_id=${pool_id}&message=" . urlencode ("Load balancer was successfully deleted");
+}
+
+function deleteVService ()
+{
+       global $root, $pageno, $tabno;
+
+       assertUIntArg ('id');
+       if (!commitDeleteVS ($_REQUEST['id']))
+               return "${root}?page=${pageno}&tab=${tabno}&error=" . urlencode ('commitDeleteVS() failed');
+       else
+               return "${root}?page=${pageno}&tab=${tabno}&message=" . urlencode ("Virtual service was successfully deleted");
+}
+
+function updateRealServer ()
+{
+       global $root, $pageno, $tabno;
+
+       assertUIntArg ('id');
+       assertUIntArg ('rs_id');
+       assertIPv4Arg ('rsip');
+       assertUIntArg ('rsport');
+       assertStringArg ('rsconfig', TRUE);
+       // only necessary for generating next URL
+       $pool_id = $_REQUEST['id'];
+       if (!commitUpdateRS ($_REQUEST['rs_id'], $_REQUEST['rsip'], $_REQUEST['rsport'], $_REQUEST['rsconfig']))
+               return "${root}?page=${pageno}&tab=${tabno}&pool_id=${pool_id}&error=" . urlencode ('commitUpdateRS() failed');
+       else
+               return "${root}?page=${pageno}&tab=${tabno}&pool_id=${pool_id}&message=" . urlencode ("Real server was successfully updated");
+}
+
+function updateLoadBalancer ()
+{
+       global $root, $pageno, $tabno;
+
+       assertUIntArg ('object_id');
+       assertUIntArg ('pool_id');
+       assertUIntArg ('vs_id');
+       assertStringArg ('vsconfig', TRUE);
+       assertStringArg ('rsconfig', TRUE);
+       $pool_id = $_REQUEST['pool_id'];
+       if (!commitUpdateLB ($_REQUEST['object_id'], $pool_id, $_REQUEST['vs_id'], $_REQUEST['vsconfig'], $_REQUEST['rsconfig']))
+               return "${root}?page=${pageno}&tab=${tabno}&pool_id=${pool_id}&error=" . urlencode ('commitUpdateLB() failed');
+       else
+               return "${root}?page=${pageno}&tab=${tabno}&pool_id=${pool_id}&message=" . urlencode ("Load balancer info was successfully updated");
+}
+
+function updateVService ()
+{
+       global $root, $pageno, $tabno;
+
+       assertUIntArg ('id');
+       assertIPv4Arg ('vip');
+       assertUIntArg ('vport');
+       assertStringArg ('proto');
+       assertStringArg ('name', TRUE);
+       assertStringArg ('vsconfig', TRUE);
+       assertStringArg ('rsconfig', TRUE);
+       if (!commitUpdateVS ($_REQUEST['id'], $_REQUEST['vip'], $_REQUEST['vport'], $_REQUEST['proto'], $_REQUEST['name'], $_REQUEST['vsconfig'], $_REQUEST['rsconfig']))
+               return "${root}?page=${pageno}&tab=${tabno}&error=" . urlencode ('commitUpdateVS() failed');
+       else
+               return "${root}?page=${pageno}&tab=${tabno}&message=" . urlencode ("Virtual service was successfully updated");
+}
+
+function addLoadBalancer ()
+{
+       global $root, $pageno, $tabno;
+
+       assertUIntArg ('pool_id');
+       assertUIntArg ('object_id');
+       assertUIntArg ('vs_id');
+       assertStringArg ('vsconfig', TRUE);
+       assertStringArg ('rsconfig', TRUE);
+       $pool_id = $_REQUEST['pool_id'];
+       if (!addLBtoRSPool ($pool_id, $_REQUEST['object_id'], $_REQUEST['vs_id'], $_REQUEST['vsconfig'], $_REQUEST['rsconfig']))
+               return "${root}?page=${pageno}&tab=${tabno}&pool_id=${pool_id}&error=" . urlencode ('addLBtoRSPool() failed');
+       else
+               return "${root}?page=${pageno}&tab=${tabno}&pool_id=${pool_id}&message=" . urlencode ("Load balancer was successfully added");
+}
+
+function addRSPool ()
+{
+       global $root, $pageno, $tabno;
+
+       assertStringArg ('name', TRUE);
+       assertStringArg ('vsconfig', TRUE);
+       assertStringArg ('rsconfig', TRUE);
+       if (!commitCreateRSPool ($_REQUEST['name'], $_REQUEST['vsconfig'], $_REQUEST['rsconfig']))
+               return "${root}?page=${pageno}&tab=${tabno}&error=" . urlencode ('commitCreateRSPool() failed');
+       else
+               return "${root}?page=${pageno}&tab=${tabno}&message=" . urlencode ("Real server pool was successfully created");
+}
+
+function deleteRSPool ()
+{
+       global $root, $pageno, $tabno;
+
+       assertUIntArg ('pool_id');
+       if (!commitDeleteRSPool ($_REQUEST['pool_id']))
+               return "${root}?page=${pageno}&tab=${tabno}&error=" . urlencode ('commitDeleteRSPool() failed');
+       else
+               return "${root}?page=${pageno}&tab=${tabno}&message=" . urlencode ("Real server pool was successfully deleted");
+}
+
+function updateRSPool ()
+{
+       global $root, $pageno, $tabno;
+
+       assertUIntArg ('pool_id');
+       assertStringArg ('name', TRUE);
+       assertStringArg ('vsconfig', TRUE);
+       assertStringArg ('rsconfig', TRUE);
+       if (!commitUpdateRSPool ($_REQUEST['pool_id'], $_REQUEST['name'], $_REQUEST['vsconfig'], $_REQUEST['rsconfig']))
+               return "${root}?page=${pageno}&tab=${tabno}&error=" . urlencode ('commitUpdateRSPool() failed');
+       else
+               return "${root}?page=${pageno}&tab=${tabno}&message=" . urlencode ("Real server pool was successfully updated");
+}
+
+function updateRSInService ()
+{
+       global $root, $pageno, $tabno;
+       assertUIntArg ('pool_id');
+       assertUIntArg ('rscount');
+       $pool_id = $_REQUEST['pool_id'];
+       $orig = getRSPoolInfo ($pool_id);
+       $nbad = $ngood = 0;
+       for ($i = 1; $i <= $_REQUEST['rscount']; $i++)
+       {
+               $rs_id = $_REQUEST["rsid_${i}"];
+               if (isset ($_REQUEST["inservice_${i}"]) and $_REQUEST["inservice_${i}"] == 'on')
+                       $newval = 'yes';
                else
-                       $success_count++;
-// Generate a message depending on error counter and redirect.
-       return
-               "${root}?page=${pageno}&tab=${tabno}&object_id=${object_id}&" .
-               ($error_count == 0 ? 'message' : 'error') .
-               "=" . urlencode ("${error_count} failures and ${success_count} successfull changes.");
+                       $newval = 'no';
+               if ($newval != $orig['rslist'][$rs_id]['inservice'])
+               {
+                       if (commitSetInService ($rs_id, $newval))
+                               $ngood++;
+                       else
+                               $nbad++;
+               }
+       }
+       if (!$nbad)
+               return "${root}?page=${pageno}&tab=${tabno}&pool_id=${pool_id}&message=" . urlencode ($ngood . " real server(s) were successfully (de)activated");
+       else
+               return "${root}?page=${pageno}&tab=${tabno}&pool_id=${pool_id}&error=" . urlencode ("Encountered ${nbad} errors, (de)activated ${ngood} real servers");
+}
 
+function importPTRData ()
+{
+       global $root, $pageno, $tabno;
+       assertUIntArg ('id');
+       assertUIntArg ('addrcount');
+       $nbad = $ngood = 0;
+       $id = $_REQUEST['id'];
+       for ($i = 0; $i < $_REQUEST['addrcount']; $i++)
+       {
+               $inputname = "import_${i}";
+               if (!isset ($_REQUEST[$inputname]) or $_REQUEST[$inputname] != 'on')
+                       continue;
+               assertIPv4Arg ("addr_${i}");
+               assertStringArg ("descr_${i}", TRUE);
+               assertStringArg ("rsvd_${i}");
+               // Non-existent addresses will not have this argument set in request.
+               $rsvd = 'no';
+               if ($_REQUEST["rsvd_${i}"] == 'yes')
+                       $rsvd = 'yes';
+               if (updateAddress ($_REQUEST["addr_${i}"], $_REQUEST["descr_${i}"], $rsvd) == '')
+                       $ngood++;
+               else
+                       $nbad++;
+       }
+       if (!$nbad)
+               return "${root}?page=${pageno}&tab=${tabno}&id=${id}&message=" . urlencode ($ngood . " IP address(es) were successfully updated");
+       else
+               return "${root}?page=${pageno}&tab=${tabno}&id=${id}&error=" . urlencode ("Encountered ${nbad} errors, updated ${ngood} IP address(es)");
+}
+
+function generateAutoPorts ()
+{
+       global $root, $pageno, $tabno;
+       assertUIntArg ('object_id');
+       $object_id = $_REQUEST['object_id'];
+       $info = getObjectInfo ($object_id);
+       // Navigate away in case of success, stay at the place otherwise.
+       if (executeAutoPorts ($object_id, $info['objtype_id']))
+               return "${root}?page=${pageno}&tab=ports&object_id=${object_id}&message=" . urlencode ('Generation complete');
+       else
+               return "${root}?page=${pageno}&tab=${tabno}&object_id=${object_id}&error=" . urlencode ('executeAutoPorts() failed');
+}
+
+// Filter out implicit tags before storing the new tag set.
+function saveEntityTags ($realm, $bypass)
+{
+       global $root, $pageno, $tabno, $explicit_tags, $implicit_tags;
+       assertUIntArg ($bypass);
+       $entity_id = $_REQUEST[$bypass];
+       // Build a trail from the submitted data, minimize it,
+       // then wipe existing records and store the new set instead.
+       wipeTags ($realm, $entity_id);
+       $newtrail = getExplicitTagsOnly (buildTrailFromIds ($_REQUEST['taglist']));
+       $n_succeeds = $n_errors = 0;
+       foreach ($newtrail as $taginfo)
+       {
+               if (useInsertBlade ('TagStorage', array ('target_realm' => "'${realm}'", 'target_id' => $entity_id, 'tag_id' => $taginfo['id'])))
+                       $n_succeeds++;
+               else
+                       $n_errors++;
+       }
+       if ($n_errors)
+               return "${root}?page=${pageno}&tab=${tabno}&${bypass}=${entity_id}&error=" . urlencode ("Replaced trail with ${n_succeeds} tags, but experienced ${n_errors} errors.");
+       else
+               return "${root}?page=${pageno}&tab=${tabno}&${bypass}=${entity_id}&message=" . urlencode ("New trail is ${n_succeeds} tags long");
+}
+
+function saveObjectTags ()
+{
+       return saveEntityTags ('object', 'object_id');
+}
+
+function saveIPv4PrefixTags ()
+{
+       return saveEntityTags ('ipv4net', 'id');
+}
+
+function saveRackTags ()
+{
+       return saveEntityTags ('rack', 'rack_id');
+}
+
+function saveIPv4VSTags ()
+{
+       return saveEntityTags ('ipv4vs', 'id');
+}
+
+function saveIPv4RSPoolTags ()
+{
+       return saveEntityTags ('ipv4rspool', 'id');
+}
+
+function destroyTag ()
+{
+       global $root, $pageno, $tabno;
+       assertUIntArg ('id');
+       if (($ret = commitDestroyTag ($_REQUEST['id'])) == '')
+               return "${root}?page=${pageno}&tab=${tabno}&message=" . urlencode ("Successfully deleted tag.");
+       else
+               return "${root}?page=${pageno}&tab=${tabno}&error=" . urlencode ("Error deleting tag: '${ret}'");
+}
+
+function createTag ()
+{
+       global $root, $pageno, $tabno;
+       assertStringArg ('tagname');
+       assertUIntArg ('parent_id', TRUE);
+       $tagname = trim ($_REQUEST['tagname']);
+       if (($parent_id = $_REQUEST['parent_id']) <= 0)
+               $parent_id = 'NULL';
+       if (($ret = commitCreateTag ($tagname, $parent_id)) == '')
+               return "${root}?page=${pageno}&tab=${tabno}&message=" . urlencode ("Created tag '${tagname}'.");
+       else
+               return "${root}?page=${pageno}&tab=${tabno}&error=" . urlencode ("Could not create tag '${tagname}' because of error '${ret}'");
 }
 
 ?>