r2232 - last mods before RackTables 0.16.3
[racktables] / upgrade.php
index 82c8ab8..282c614 100644 (file)
@@ -22,11 +22,14 @@ function getDBUpgradePath ($v1, $v2)
                '0.15.0',
                '0.15.1',
                '0.16.0',
+               '0.16.1',
+               '0.16.2',
+               '0.16.3',
        );
        if (!in_array ($v1, $versionhistory) || !in_array ($v2, $versionhistory))
        {
                showError ("An upgrade path has been requested for versions '${v1}' and '${v2}', " .
-                 "and at least one of those isn't known to me.");
+                 "and at least one of those isn't known to me.", __FILE__);
                die;
        }
        $skip = TRUE;
@@ -53,11 +56,18 @@ function printReleaseNotes ($batchid)
        switch ($batchid)
        {
                case '0.16.0':
+                       echo "<font color=red><strong>Release notes for ${batchid}</strong></font><br>";
                        echo 'The user permission records of this system have been automatically converted ';
                        echo 'to switch to the new RackCode authorization system. To prevent possible data ';
                        echo 'leak, the second line of the automatically created configuration bans everything ';
                        echo '(and the first allows everything to you, the administrator). The whole config can ';
-                       echo "be reviewed on the Permissions page (under Configuration). Sorry for the inconvenience.\n";
+                       echo "be reviewed on the Permissions page (under Configuration). Sorry for the inconvenience.<br><br>\n";
+                       break;
+               case '0.16.3':
+                       echo "<font color=red><strong>Release notes for ${batchid}</strong></font><br>";
+                       echo 'This release fixes a missing UNIQUE KEY in a table. The upgrade script may find it necessary first to transform some records.<br>';
+                       echo 'Because of this it is normal to see several "update TagStorage ... Duplicate entry" failed queries during the upgrade.<br>';
+                       echo 'Additionally, it is normal to see " Can\'t DROP \'endpoint\'" message during upgrade<br>';
                        break;
                default:
                        break;
@@ -1288,7 +1298,7 @@ CREATE TABLE `TagTree` (
                                die ('<b>Cannot upgrade due to multibyte extension not present. See the README for details.</b>');
                        }
                        $query[] = 'alter table TagStorage modify column tag_id int(10) unsigned not null;';
-                       $query[] = "alter table TagStorage modify column target_realm enum('object','ipv4net','rack','ipv4vs','ipv4rspool','user');";
+                       $query[] = "alter table TagStorage modify column target_realm enum('object','ipv4net','rack','ipv4vs','ipv4rspool','user') NOT NULL default 'object'";
                        $query[] = "create table Script (script_name char(64) not null primary key, script_text text)";
                        // Do the same getUserPermissions() does, but without the function.
                        // We need to generate more specific rules first, otherwise they will
@@ -1298,7 +1308,7 @@ CREATE TABLE `TagTree` (
                                "UserPermission natural left join UserAccount where (user_name is not null) or " .
                                "(user_name is null and UserPermission.user_id = 0) order by user_id desc, page desc, tab desc";
                        $tr = $dbxlink->query ($tq);
-                       $code = "allow {$userid_1}\ndeny true\n";
+                       $code = "allow {\$userid_1}\ndeny true\n";
                        // copied and pasted from fixContext()
                        $pmap = array
                        (
@@ -1313,6 +1323,8 @@ CREATE TABLE `TagTree` (
                        $tmap['objects']['newobj'] = 'addmore';
                        $tmap['object']['switchvlans'] = 'livevlans';
                        $tmap['object']['slb'] = 'editrspvs';
+                       $tmap['object']['portfwrd'] = 'nat4';
+                       $tmap['object']['network'] = 'ipv4';
                        while ($row = $tr->fetch (PDO::FETCH_ASSOC))
                        {
                                // map, if appropriate
@@ -1339,10 +1351,72 @@ CREATE TABLE `TagTree` (
                        }
                        $query[] = "insert into Script (script_name, script_text) values ('RackCode', '${code}')";
                        $query[] = 'drop table UserPermission';
+                       $new_words[791] = array (13 => '[[Linux%GSKIP%openSUSE 11.0 | http://en.opensuse.org/OpenSUSE_11.0]]');
+                       $new_words[] = array (11 => '[[SGI%GPASS%Altix XE250 | http://www.sgi.com/products/servers/altix/xe/configs.html]]');
+                       $new_words[] = array (11 => '[[SGI%GPASS%Altix XE310 | http://www.sgi.com/products/servers/altix/xe/configs.html]]');
+                       $new_words[] = array (11 => '[[SGI%GPASS%Altix XE320 | http://www.sgi.com/products/servers/altix/xe/configs.html]]');
+                       foreach ($new_words as $dict_key => $tmp)
+                               foreach ($tmp as $chapter_no => $dict_value)
+                                       $query[] = 'INSERT INTO `Dictionary` (`chapter_no`, `dict_key`, `dict_value`) ' .
+                                               "VALUES (${chapter_no}, ${dict_key}, '${dict_value}')";
                        $query[] = "update Config set varvalue = '0.16.0' where varname = 'DB_VERSION'";
                        break;
+               case '0.16.1':
+                       $query[] = 'alter table Script modify column script_text longtext';
+                       $query[] = "INSERT INTO `Config` (varname, varvalue, vartype, emptyok, is_hidden, description) VALUES ('SHOW_LAST_TAB','no','string','yes','no','Remember last tab shown for each page')";
+                       $query[] = "INSERT INTO `Config` (varname, varvalue, vartype, emptyok, is_hidden, description) VALUES ('COOKIE_TTL','1209600','uint','yes','no','Cookies lifetime in seconds')";
+                       $query[] = "update Config set varvalue = '0.16.1' where varname = 'DB_VERSION'";
+                       break;
+               case '0.16.2':
+                       $query[] = "alter table IPBonds modify column type enum('regular','shared','virtual','router')";
+                       $query[] = "update Dictionary set dict_value = 'spacer' where dict_key = 11";
+                       $query[] = "INSERT INTO `Config` (varname, varvalue, vartype, emptyok, is_hidden, description) VALUES ('EXT_IPV4_VIEW','yes','string','no','no','Display parent network info for IPv4 addresses')";
+                       $query[] = "ALTER TABLE RackSpace ADD KEY `RackSpace_object_id` (`object_id`)";
+                       $query[] = "update Config set varvalue = '0.16.2' where varname = 'DB_VERSION'";
+                       break;
+               case '0.16.3':
+                       // The network table list used to allow duplicate "prefix-masklen" pairs, which was a bad idea.
+                       // The code, which verified each new network to be "unique", didn't work for "upper" IPv4 space.
+                       // To enable the relevant index now, it is necessary to process all ghost networks, which could
+                       // be accumulated over the time, and move all tags assigned to them to the "master" record, which
+                       // we recognize to be the one with the lowest ID.
+                       $q = 'select ip, mask, count(*) as c from IPRanges group by ip, mask having c > 1';
+                       $r = $dbxlink->query ($q);
+                       // Let's hope there's not many dupes, cause sub-queries won't work.
+                       $dupes = $r->fetchAll (PDO::FETCH_ASSOC);
+                       unset ($r);
+                       foreach ($dupes as $d)
+                       {
+                               $firstid = 0;
+                               $q = "select id from IPRanges where ip = ${d['ip']} and mask = ${d['mask']} order by id";
+                               $r = $dbxlink->query ($q);
+                               while ($row = $r->fetch (PDO::FETCH_ASSOC))
+                               {
+                                       if (!$firstid)
+                                       {
+                                               $firstid = $row['id'];
+                                               continue;
+                                       }
+                                       // Rewrite tags, but don't rebuild the chains. Let regular code sort it out.
+                                       // One of the next two queries will fail.
+                                       $query[] = "update TagStorage set target_id = ${firstid} where target_id = ${row['id']} and target_realm = 'ipv4net'";
+                                       $query[] = "delete from TagStorage where target_id = ${row['id']} and target_realm = 'ipv4net'";
+                                       $query[] = "delete from IPRanges where id = ${row['id']}";
+                               }
+                               unset ($r);
+                       }
+                       $query[] = 'alter table IPRanges add unique `base-len` (`ip`, `mask`)';
+                       $query[] = 'alter table IPVirtualService drop key `endpoint`';
+                       // fix the default value (only seen when upgrading from pre-0.16.0 to pre-0.16.3)
+                       $query[] = "alter table TagStorage modify column target_realm enum('object','ipv4net','rack','ipv4vs','ipv4rspool','user') NOT NULL default 'object'";
+                       $query[] = "INSERT INTO `Config` (varname, varvalue, vartype, emptyok, is_hidden, description) VALUES ('TREE_THRESHOLD','25','uint','yes','no','Tree view auto-collapse threshold')";
+                       $query[] = "INSERT INTO `Config` (varname, varvalue, vartype, emptyok, is_hidden, description) VALUES ('IPV4_JAYWALK','no','string','no','no','Enable IPv4 address allocations w/o covering network')";
+                       $query[] = "INSERT INTO `Config` (varname, varvalue, vartype, emptyok, is_hidden, description) VALUES ('ADDNEW_AT_TOP','yes','string','no','no','Render \"add new\" line at top of the list')";
+                       $query[] = "update Config set description = 'Extended IPv4 view' where varname = 'EXT_IPV4_VIEW'";
+                       $query[] = "update Config set varvalue = '0.16.3' where varname = 'DB_VERSION'";
+                       break;
                default:
-                       showError ("executeUpgradeBatch () failed, because batch '${batchid}' isn't defined");
+                       showError ("executeUpgradeBatch () failed, because batch '${batchid}' isn't defined", __FILE__);
                        die;
                        break;
        }
@@ -1423,8 +1497,24 @@ catch (PDOException $e)
 // will have to dig into the DB for the user accounts.
 require_once 'inc/auth.php';
 
-// This will not fail sanely, because getUserAccounts() depends on showError()
-$accounts = getUserAccounts();
+// 1. This didn't fail sanely, because getUserAccounts() depended on showError()
+// 2. getUserAccounts() doesn't work for old DBs since 0.16.0. Let's have own
+// copy until it breaks too.
+
+function getUserAccounts_local ()
+{
+       global $dbxlink;
+       $query = 'select user_id, user_name, user_password_hash from UserAccount order by user_name';
+       if (($result = $dbxlink->query ($query)) == NULL)
+               die ('SQL query failed in ' . __FUNCTION__);
+       $ret = array();
+       while ($row = $result->fetch (PDO::FETCH_ASSOC))
+               foreach (array ('user_id', 'user_name', 'user_password_hash') as $cname)
+                       $ret[$row['user_name']][$cname] = $row[$cname];
+       return $ret;
+}
+
+$accounts = getUserAccounts_local();
 
 // Only administrator is always authenticated locally, so reject others
 // for authenticate() to succeed.
@@ -1439,7 +1529,7 @@ if
 {
        header ('WWW-Authenticate: Basic realm="RackTables upgrade"');
        header ('HTTP/1.0 401 Unauthorized');
-       showError ('You must be authenticated as an administrator to complete the upgrade.');
+       showError ('You must be authenticated as an administrator to complete the upgrade.', __FILE__);
        die;
 }