def update_from_ini(ini_file, app, commit):
    """ Pull in the relavant database and model parameters from pylons .INI
    
    This makes use of the ConfigParser embedded in paste.deploy.loadwsgi.
    
    It looks for a section called [app] 
     -- the typical value is [app:main]
    
    The database URL is found from ``sqlalchemy.url`` 
     -- eg:  ``sqlalchemy.url = sqlite:///%(here)s/development.db``
    
    The metadata for SQLalchemy is taken from a new entry : ``migrate.metadata`` 
     -- eg: ``migrate.metadata = MYPROJ.model.meta:metadata``
     
     
    Where the file model/meta.py contains the following : 
    
    ``
    from sqlalchemy import schema
    metadata = schema.MetaData()
    
    # The declarative DataBase base Object
    Base = declarative_base(metadata=metadata)
    ``
    """
    global _debug_messages
    
    ini_file = os.path.abspath(ini_file)
    if not os.path.exists(ini_file):
        raise OSError("File %s not found" % ini_file)
    config_dir = os.path.dirname(ini_file)

    cp = NicerConfigParser(ini_file)
    cp.read(ini_file)
    global_conf = cp.defaults()
    cp._defaults.setdefault("here", config_dir)
    cp._defaults.setdefault("__file__", ini_file)
    
    app_main = get_config(cp, app, None)
    
    url = app_main['sqlalchemy.url']
    
#    model_egg = app_main['use']
#    model = model_egg.replace('egg:', '') + '.model.meta:metadata'
    
    model_metadata = app_main['migrate.metadata']
    
    if _debug_messages:
        print "url   = '%s'" % url
        print "model = '%s'" % model_metadata
    
    update_pylons_db_from_model(url, model_metadata, commit)
Exemple #2
0
class Run(object):    
    
    def __init__(self, ini_file=None, nologsetup=False):
        """
        Set up the configuration ready for main and appmain to use.
        
        :params ini_file: None or ini file used to configure the webapp 
        and logging. If this is None then the internal version will be 
        used in the evasion.web.script directory
        
        """
        self.log = logging.getLogger('evasion.web.scripts.runweb.Run')
        config_dir = os.path.dirname(__file__)

        if not ini_file:
            # If nothing was given for the config file use our internal version.
            self.iniFile = os.path.join(config_dir, 'development.ini')
            self.log = logging.getLogger("init: using internal ini file '%s'." % self.iniFile)
            
        else:
            self.iniFile = os.path.abspath(ini_file)
            
        if not nologsetup:
            logging.config.fileConfig(self.iniFile)
        
        self.log.debug("init: config dir:'%s'" % config_dir)
        self.log.debug("init: self.iniFile:'%s'" % self.iniFile)
        
        self.cp = NicerConfigParser(self.iniFile)
        self.cp.read(self.iniFile)
        self.globalConf = self.cp.defaults()
        
        self.cp._defaults.setdefault("here", os.path.abspath(os.curdir))
        self.cp._defaults.setdefault("__file__", self.iniFile)
        self.serverConf = self.getConfig(self.cp, "server:main", "egg:Paste#http")
        self.appConf = self.getConfig(self.cp, "app:main", "egg:evasion-web")
        m = dict(
            state= self.cp.get('Messenger', 'state', 'off'),
            host = self.cp.get('Messenger', 'host', '127.0.0.1'),
            port = self.cp.get('Messenger', 'port', 61613),
            username = self.cp.get('Messenger', 'username', ''),
            password = self.cp.get('Messenger', 'password', ''),
            channel = self.cp.get('Messenger', 'channel', 'evasion'),
        )
        self.messengerConf = m
        
        # Only set up if running as part of the director under the webadminctrl 
        # controller. This runs the evasion.web as a thread instead of a separate
        # process.
        #
        self.directorIntegrationServer = None
        self.directorIntegrationIsRunning = False


    def setupapp(self):
        """
        Run the equivalent paster setup-app
        
        """
        from evasion.web import websetup
        
        class O:
            global_conf = self.globalConf
            local_conf = self.appConf
        
        command='?' # not sure what to do here
        conf = O()
        
        websetup.setup_app(command, conf, vars)
        

    def getConfig(self, cp, section, expected_use_value):
        """Get a section from an INI-style config file as a dict.
        
        ``cp`` -- NicerConfigParser.
        ``section`` -- the section to read.
        ``expected_use_value`` -- expected value of ``use`` option in the section.
        
        Aborts if the value of ``use`` doesn't equal the expected value.  This
        indicates Paster would instantiate a different object than we're expecting.
        
        The ``use`` key is removed from the dict before returning.
        """
        defaults = self.cp.defaults()
        ret = {}
        for option in self.cp.options(section):
            if option.startswith("set "):  # Override a global option.
                option = option[4:]
            elif option in defaults:       # Don't carry over other global options.
                continue
            ret[option] = self.cp.get(section, option)
        use = ret.pop("use", "")
        if use != expected_use_value:
            msg = ("unexpected value for 'use=' in section '%s': "
                   "expected '%s', found '%s'")
            msg %= (section, expected_use_value, use)
            raise EnvironmentError(msg)
        return ret


    def appmainSetup(self):
        """
        Called to create the wsgi app ready for appmain or 
        directorIntegration to use.
        
        """
        app = app_factory(self.globalConf, **self.appConf)
        return app
        

    def appmain(self, isExit):    
        """
        Called to run inside its own thread once twisted has taken over 
        the main loop.
        
        """
        app = self.appmainSetup()
        self.log.info("appmain: Serving webapp")
        server_runner(app, self.globalConf, **self.serverConf)


    def directorIntegrationStart(self):
        """
        Create a server which the director webadminctrl controller
        will use to run the webapp, when start is called. The 
        controller will also be able to stop the webapp via shutdown.
        
        """
        # You don't need this in integration mode as it is part
        # of the director's messaging system. If this is kept in
        # it will cause messages to be resent onto the message
        # bus in error.
        #
        #self.setUpStomp()
        
        self.log.info("directorIntegrationStart: creating wsgi_app")
        wsgi_app = self.appmainSetup()
        
        # Use threadpool to also get access to server_close()
        self.serverConf['use_threadpool'] = True
        
        # Don't start serving straigh away, return so I can
        # store the server handle to close it later.
        self.serverConf['start_loop'] = False
        
        self.log.info("directorIntegrationStart: creating server.")
        self.directorIntegrationServer = serve(wsgi_app, **self.serverConf)
        
        try:
            self.directorIntegrationIsRunning = True
            self.log.info("directorIntegrationStart: serving until stopped.")
            self.directorIntegrationServer.serve_forever()
            
        except KeyboardInterrupt:
            # allow CTRL+C to shutdown
            self.log.warn("directorIntegrationStart: KeyboardInterrupt! Stopping... ")
            
        except:
            self.log.exception("directorIntegrationStart Error - ")
            
        self.directorIntegrationIsRunning = False
        self.log.info("directorIntegrationStart: server stopped.")


    def directorIntegrationIsStarted(self):
        return self.directorIntegrationIsRunning
 

    def directorIntegrationStop(self):
        """Stop the server handling any more requests."""
        if not self.directorIntegrationServer:
            self.log.error("directorIntegrationStop: directorIntegrationStart not called to set up server!")
        else:
            self.log.info("directorIntegrationStop: telling server to close.")
            self.directorIntegrationServer.server_close()
            self.log.info("directorIntegrationStop: server close called ok.")


    def setUpStomp(self):
        """Connect to the broker so we can send/receive messages."""
        # Only import if we use it:
        from evasion import messenger        

        stomp_cfg = dict(
            host = self.cp.get("Messenger", "host"),
            port = int(self.cp.get("Messenger", "port")),
            username = self.cp.get("Messenger", "username"),
            password = self.cp.get("Messenger", "password"),
            channel = self.cp.get("Messenger", "channel"),
        )
        
        self.log.info("appmain: setting up stomp connection")
        messenger.stompprotocol.setup(stomp_cfg)


    def main(self):
        """
        Called to run twisted in the mainloop so messaging will work correctly. 
        The webapp will be run via appmain.
        
        """
        if self.messengerConf['state'] == 'on':
            # Only import if we use it:
            from evasion import messenger        
            self.setUpStomp()
        
            self.log.info("main: running mainloop until done.")
            messenger.run(self.appmain)
            self.log.info("main: Exiting.")
        
        else:
            self.log.info("main: running mainloop (no messenger).")
            self.appmain(None)
            self.log.info("main: Exiting.")