#!/usr/bin/python # coding: utf-8 # maposmatic, the web front-end of the MapOSMatic city map generation system # Copyright (C) 2010 David Decotigny # Copyright (C) 2010 Frédéric Lehobey # Copyright (C) 2010 David Mentré # Copyright (C) 2010 Maxime Petazzoni # Copyright (C) 2010 Thomas Petazzoni # Copyright (C) 2010 Gaël Utard # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as # published by the Free Software Foundation, either version 3 of the # License, or 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 Affero General Public License for more details. # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . import sys from django import db from www.maposmatic.models import MapRenderingJob from www.settings import RENDERING_RESULT_PATH, RENDERING_RESULT_FORMATS class DbckHandler: pass class DummyDbckHandler(DbckHandler): """ A dummy MapOSMatic Dbck handler for the dry runs. It does nothing but returning a detail message about the job status relevant to each check operation. """ def do_obsolete(self, job): return 'elligible for obsolete status!' def do_admin_bbox(self, job): return 'has both admin and bbox values!' def do_locale(self, job): return 'no locale information!' class RealDbckHandler(DummyDbckHandler): """ The 'real' MapOSMatic Dbck handler that actually fixes jobs. See each check operation details for more information and what's done in each case. """ DEFAULT_LOCALE = 'en_US.UTF-8' def do_obsolete(self, job): """If the job is obsolete, but not marked as such in the database (i.e. its status is 2 'Done', but it doesn't have all its output files present), ask the job to remove all its files and mark itself as obsolete.""" removed, saved = job.remove_all_files() return 'removed %d file(s) and marked obsolete.' % removed def do_admin_bbox(self, job): """If the job has both administrative boundary/osmID information and a bounding box, always prefer the OSM ID, and purge the bounding box information. In the daemon, the OSM ID always takes precedence anyways.""" job.lat_upper_left = None job.lon_upper_left = None job.lat_bottom_right = None job.lon_bottom_right = None job.save() return 'cleared bounding box, keeping osmid %d.' % \ job.administrative_osmid def do_locale(self, job): """If the job has no locale defined, make sure it has one, using the DEFAULT_LOCALE defined in RealDbckHandler.""" job.map_language = self.DEFAULT_LOCALE job.save() return 'missed locale information, fell back to %s.' % \ self.DEFAULT_LOCALE class MapOSMaticDbck: """ A database checker/fixer for MapOSMatic. It runs a series of checks on all jobs from the database, eventually taking action to fix things that are wrong if a capable DbckHandler is provided. To add checks, write a check function that makes use of the correction operation from a handler and add it to the list of checks. """ def __init__(self, handler=None): self.jobs = MapRenderingJob.objects.all().order_by('id') self.handler = handler or DbckHandler() self.checks = [self.__check_obsolete, self.__check_admin_bbox, self.__check_locale, ] print 'Starting MapOSMatic database checker: %d job(s), ' \ '%d check(s) with %s.' % (self.jobs.count(), len(self.checks), self.handler.__class__.__name__) def run(self): for job in self.jobs: messages = [] for check in self.checks: try: messages.append(check(job)) except (NotImplementedError, AttributeError): messages.append("%s not available!" % check.__name__) messages = filter(None, messages) if len(messages): print ' + checking job #%d (%s): ' % (job.id, job.maptitle) for m in messages: print ' `', m print 'Check/repair complete. Database queries performed: %d.' % \ len(db.connection.queries) def __check_obsolete(self, job): """Checks the obsolete status of the given job. If the job is in the done state (status=2) and does not have all its output files, it's obselete and should be cleaned.""" if not job.is_done_ok(): return files = job.output_files() if (len(files['maps']) < len(RENDERING_RESULT_FORMATS)-1 or (len(files['indeces']) > 0 and len(files['indeces']) < len(RENDERING_RESULT_FORMATS))): return self.handler.do_obsolete(job) def __check_admin_bbox(self, job): """Make sure we don't have mutually exclusive admin/bbox data.""" if job.administrative_osmid and (job.lat_upper_left or job.lon_upper_left or job.lat_bottom_right or job.lon_bottom_right): return self.handler.do_admin_bbox(job) def __check_locale(self, job): """Make sure the job declares a map language.""" if not job.map_language: return self.handler.do_locale(job) if __name__ == '__main__': if len(sys.argv) == 2 and sys.argv[1] == '--dry-run': handler = DummyDbckHandler() else: handler = RealDbckHandler() MapOSMaticDbck(handler).run()