]> scripts.mit.edu Git - wizard.git/commitdiff
Fix web verification in MediaWiki and improve handling.
authorEdward Z. Yang <ezyang@mit.edu>
Sun, 4 Oct 2009 01:32:16 +0000 (21:32 -0400)
committerEdward Z. Yang <ezyang@mit.edu>
Sun, 4 Oct 2009 01:32:16 +0000 (21:32 -0400)
Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
wizard/app/__init__.py
wizard/app/mediawiki.py
wizard/command/__init__.py
wizard/command/mass_upgrade.py
wizard/command/upgrade.py
wizard/deploy.py

index cc6bacf6ef85505540af2214d37cae75ec060207..8a4789f3eb78d94a400bdb77470db8bfac743d48 100644 (file)
@@ -99,6 +99,19 @@ ERROR: Upgrade script failed, details:
 
 %s""" % self.details
 
+class UpgradeVerificationFailure(Error):
+    """Upgrade script passed, but website wasn't accessible afterwards"""
+    #: String details of failure (possibly stdout or stderr output)
+    details = None
+    def __init__(self, details):
+        self.details = details
+    def __str__(self):
+        return """
+
+ERROR: Upgrade script passed, but website wasn't accessible afterwards. Details:
+
+%s""" % self.details
+
 class BackupFailure(Error):
     """Backup script failed."""
     #: String details of failure
index a1a1eec56908f32700aa3bee89c824b8ef9152d6..d07b1e7f13576fbb474a9c585f13f5d10526c0d9 100644 (file)
@@ -54,9 +54,11 @@ class Application(deploy.Application):
         match = regex.search(contents)
         if not match: return None
         return distutils.version.LooseVersion(match.group(2)[1:-1])
-    def checkWeb(self, d):
-        page = d.fetch("index.php")
-        return page.find("<!-- Served by") != -1
+    def checkWeb(self, d, out=None):
+        page = d.fetch("/index.php?title=Main_Page")
+        if type(out) is list:
+            out.append(page)
+        return page.find("<!-- Served") != -1
     def install(self, version, options):
         try:
             os.unlink("LocalSettings.php")
@@ -79,7 +81,7 @@ class Application(deploy.Application):
             'SysopPass': options.admin_password,
             'SysopPass2': options.admin_password,
             }
-        result = install.fetch(options, 'config/index.php', post=postdata)
+        result = install.fetch(options, '/config/index.php', post=postdata)
         if options.verbose: print result
         if result.find("Installation successful") == -1:
             raise install.Failure()
index 62a561b4ae9366154efbee7f8c1d0f68abcfedd3..bc1b718b3ba8f0ad02cebbc2b25682a5a1e56c45 100644 (file)
@@ -83,17 +83,20 @@ def security_check_homedir(location):
     This protects against malicious mountpoints, and is roughly equivalent
     to the suexec checks.
     """
-    uid = util.get_dir_uid(location)
-    real = os.path.realpath(location)
     try:
+        uid = util.get_dir_uid(location)
+        real = os.path.realpath(location)
         if not real.startswith(pwd.getpwuid(uid).pw_dir + "/"):
-            logging.error("Security check failed, owner of deployment and"
-                    "owner of home directory mismatch for %s" % d.location)
+            logging.error("Security check failed, owner of deployment and "
+                    "owner of home directory mismatch for %s" % location)
             return False
     except KeyError:
-        logging.error("Security check failed, could not look up"
+        logging.error("Security check failed, could not look up "
                 "owner of %s (uid %d)" % (location, uid))
         return False
+    except OSError as e:
+        logging.error("OSError: %s" % str(e))
+        return False
     return True
 
 def calculate_log_name(log_dir, i, dir):
index 1edbe5dca870aad0ffed17e5a7ffa1c7337a837a..a2ccd367976fee0d31b645aa1c5a88aa4c7ccb1c 100644 (file)
@@ -9,7 +9,7 @@ import time
 import itertools
 
 import wizard
-from wizard import deploy, util, shell, sset, command
+from wizard import deploy, util, scripts, shell, sset, command
 
 def main(argv, baton):
     options, args = parse_args(argv, baton)
@@ -60,7 +60,17 @@ def main(argv, baton):
                     name = e.name
                     if name not in errors: errors[name] = []
                     errors[name].append(d)
-                    logging.error("%s in [%04d] %s" % (name, i, d.location))
+                    if name == "WebVerificationError":
+                        try:
+                            host, path = scripts.get_web_host_and_path(d.location)
+                            url = "http://%s%s" % (host, path)
+                        except ValueError:
+                            url = d.location
+                        # This should actually be a warning, but
+                        # it's a really common error
+                        logging.info("Could not verify application at %s" % url)
+                    else:
+                        logging.error("%s in [%04d] %s" % (name, i, d.location))
                     errors_log.write("%s\n" % d.location)
             return (on_success, on_error)
         on_success, on_error = make_on_pair(d, i)
index 969404379c57bd8a3e7d61e78507da170560a236..ed8c8ce645632a8b9e4ae7efee5dc5489d3df826 100644 (file)
@@ -18,6 +18,8 @@ def main(argv, baton):
         dir = "."
     shell.drop_priviledges(dir, options.log_file)
     util.chdir(dir)
+    if os.path.exists(".scripts/blacklisted"):
+        raise BlacklistedError()
     sh = shell.Shell()
     util.set_git_env()
     if options.continue_:
@@ -97,10 +99,11 @@ def main(argv, baton):
                 logging.warning("Upgrade failed: rolling back")
                 perform_restore(d, backup)
                 raise
-            except deploy.WebVerificationError:
+            except deploy.WebVerificationError as e:
                 logging.warning("Web verification failed: rolling back")
+                logging.info("Web page that was output was:\n\n%s" % e.contents)
                 perform_restore(d, backup)
-                raise app.UpgradeFailure("Upgrade caused website to become inaccessible; site was rolled back")
+                raise app.UpgradeVerificationFailure("Upgrade caused website to become inaccessible; site was rolled back")
     # XXX: frob .htaccess to make site accessible
     #       to do this, check if .htaccess changed, first.  Upgrade
     #       process might have frobbed it.  Don't be
@@ -233,3 +236,10 @@ The best way to resolve this is probably to attempt an upgrade again,
 with git rerere to remember merge resolutions (XXX: not sure if
 this actually works)."""
 
+class BlacklistedError(Error):
+    def __str__(self):
+        return """
+
+ERROR: This autoinstall was manually blacklisted against errors;
+if the user has not been notified of this, please send them
+mail."""
index 8d2f8ff5318f289b19d31af4e850c5cad7a8ceb0..d67868d3b1e0f6d5efd6acc773a26c10d4474b23 100644 (file)
@@ -217,8 +217,9 @@ class Deployment(object):
         """
         Checks if the autoinstall is viewable from the web.
         """
-        if not self.application.checkWeb(self):
-            raise WebVerificationError
+        out = []
+        if not self.application.checkWeb(self, out):
+            raise WebVerificationError(out[0])
 
     def fetch(self, path, post=None):
         """
@@ -417,9 +418,10 @@ class Application(object):
         Checks source files to determine the version manually.
         """
         return None
-    def checkWeb(self, deployment):
+    def checkWeb(self, deployment, output=None):
         """
-        Checks if the autoinstall is viewable from the web.
+        Checks if the autoinstall is viewable from the web.  Output
+        should be an empty list that will get mutated by this function.
         """
         raise NotImplemented
     @property
@@ -717,13 +719,19 @@ version %s.""" % (self.real_version, self.git_version)
 
 class WebVerificationError(Error):
     """Could not access the application on the web"""
-
+    #: Contents of web page access
+    contents = None
+    def __init__(self, contents):
+        self.contents = contents
     def __str__(self):
         return """
 
 ERROR: We were not able to access the application on the
 web.  This may indicate that the website is behind
-authentication on the htaccess level."""
+authentication on the htaccess level.  The contents
+of the page were:
+
+%s""" % self.contents
 
 class UnknownWebPath(Error):
     """Could not determine application's web path."""