%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
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")
'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()
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):
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)
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)
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_:
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
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."""
"""
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):
"""
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
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."""