Exemplo n.º 1
0
        def _func():
            root = db.get_db().getRoot()
            now = datetime.datetime.utcnow()

            f = open(constants.BOOT_UUID, 'rb')
            uuid = f.read().strip()
            f.close()
            root.setS(ns.bootUuid, rdf.String, uuid)
Exemplo n.º 2
0
        def _open_db(res):
            _log.debug("WebUiMaster/start(): opening db")

            if self.is_live_cd() and self.is_lowmem():
                _log.info("live cd and lowmem, not starting db connection")
                self.db = None
            else:
                _log.debug("opening database connection")
                self.db = db.get_db()
                self.db.open()
Exemplo n.º 3
0
def db_flush(dbase=None):
    """Force RDF database flush."""
    if dbase is None:
        dbase = db.get_db().getModel()

    @db.untransact(database=dbase)
    def _dummy():
        _log.info('flushing database')

    _dummy()
Exemplo n.º 4
0
def db_flush(dbase=None):
    """Force RDF database flush."""
    if dbase is None:
        dbase = db.get_db().getModel()

    @db.untransact(database=dbase)
    def _dummy():
        _log.info('flushing database')

    _dummy()
Exemplo n.º 5
0
        def _postops():
            model = db.get_db().getModel()
            root = model.getNodeByUri(ns.l2tpGlobalRoot, rdf.Type(ns.L2tpGlobalRoot))

            # attempt to set keymap
            try:
                from codebay.l2tpserver import gnomeconfig
                cfg_ui = root.getS(ns_ui.uiConfig, rdf.Type(ns_ui.UiConfig))
                gnomeconfig.set_keymap_settings(cfg_ui.getS(ns_ui.keymap, rdf.String))
            except:
                _log.exception('setting keymap failed in import, ignoring')
Exemplo n.º 6
0
def _rdf_database_recover_from_known_good(_log):
    database_filename = constants.PRODUCT_DATABASE_FILENAME
    exported_filename = constants.EXPORTED_RDF_DATABASE_FILE
    res = False
    
    if not os.path.exists(exported_filename):
        _log.info('exported known good file %s does not exist, skipping recover from known good' % exported_filename)
        return False

    try:
        try:
            from codebay.common import rdf
            from codebay.l2tpserver import db
    
            # remove old database
            rdf.Database.delete(database_filename)

            # re-create database, read back from pruned file
            dbase = rdf.Database.create(database_filename)
            @db.transact(database=dbase)
            def _f():
                dbase.loadFile(exported_filename)
            _f()
            dbase.close()
            dbase = None

            # post ops - reset keymap (might have changed, e.g. in recovery)
            try:
                from codebay.l2tpserver.rdfconfig import ns, ns_ui
                from codebay.l2tpserver import gnomeconfig

                model = db.get_db().getModel()
                root = model.getNodeByUri(ns.l2tpGlobalRoot, rdf.Type(ns.L2tpGlobalRoot))
                cfg_ui = root.getS(ns_ui.uiConfig, rdf.Type(ns_ui.UiConfig))
                gnomeconfig.set_keymap_settings(cfg_ui.getS(ns_ui.keymap, rdf.String))
            except:
                _log.exception('setting keymap failed in recovery from known good, ignoring')

            res = True
        except:
            _log.exception('_rdf_database_recover_from_known_good: recovery from known good failed')
    finally:
        try:
            if dbase is not None:
                dbase.close()
                dbase = None
        except:
            _log.exception('_rdf_database_recover_from_known_good: failed to close hanging db')
        
    return res
Exemplo n.º 7
0
 def create_debug_group(self, form, ctx):
     debug_group = formalutils.CollapsibleGroup("debug_group", label="Debug")
     debug_group.setCollapsed(False)
     debug_group.add(
         formal.Field(
             "debug",
             formal.Integer(required=True, validators=[formal.RangeValidator(min=0, max=2)]),
             label="Debug mode (0=normal, 1=light, 2=heavy)",
         )
     )
     ui_root = db.get_db().getRoot().getS(ns_ui.uiConfig, rdf.Type(ns_ui.UiConfig))
     # Default false if no entry found from the database.
     debug_fda = formalutils.FormDataAccessor(form, ["debug_group"], ctx)
     if ui_root.hasS(ns_ui.debug):
         debug_fda["debug"] = ui_root.getS(ns_ui.debug, rdf.Integer)
     else:
         debug_fda["debug"] = 0
     return debug_group
Exemplo n.º 8
0
 def create_debug_group(self, form, ctx):
     debug_group = formalutils.CollapsibleGroup('debug_group',
                                                label='Debug')
     debug_group.setCollapsed(False)
     debug_group.add(
         formal.Field('debug',
                      formal.Integer(
                          required=True,
                          validators=[formal.RangeValidator(min=0, max=2)]),
                      label='Debug mode (0=normal, 1=light, 2=heavy)'))
     ui_root = db.get_db().getRoot().getS(ns_ui.uiConfig,
                                          rdf.Type(ns_ui.UiConfig))
     # Default false if no entry found from the database.
     debug_fda = formalutils.FormDataAccessor(form, ['debug_group'], ctx)
     if ui_root.hasS(ns_ui.debug):
         debug_fda['debug'] = ui_root.getS(ns_ui.debug, rdf.Integer)
     else:
         debug_fda['debug'] = 0
     return debug_group
Exemplo n.º 9
0
def _rdf_database_stats():
    """Log useful statistics about RDF database to syslog."""

    try:
        root = db.get_db().getRoot()
        model = root.model  # XXX: cleaner?
        count, reachable = model.getPruneStatistics(root)
        unreachable = count - reachable
        
        db_size = os.stat(constants.PRODUCT_DATABASE_FILENAME).st_size

        # XXX: division by zero is not a real concern, and we're in try-except anyway

        _log.info('DATABASEINFO: ' \
                  'filesize=%.1f MiB (%d), ' \
                  'total stmts %d, reachable stmts %d (%.1f%%), unreachable stmts %d (%.1f%%), ' \
                  'bytes per reachable stmt avg %.1f, bytes per any stmt avg %.1f' % \
                  (db_size/(1024.0*1024.0), db_size,
                   count, reachable, float(reachable)/float(count)*100.0, unreachable, float(unreachable)/float(count)*100.0,
                   float(db_size)/float(reachable), float(db_size)/float(count)))
    except:
        _log.exception('failed to get rdf database stats')
Exemplo n.º 10
0
            def _func():
                now = datetime.datetime.utcnow()

                # Global root
                model = db.get_db().getModel()
                root = rdf.Node.make(model, rdf.Type(ns.L2tpGlobalRoot), ns.l2tpGlobalRoot)

                # Global status root
                global_status = root.setS(ns.globalStatus, rdf.Type(ns.GlobalStatus))
                global_status.setS(ns.watchdogReboots, rdf.Integer, 0)
                global_status.setS(ns.periodicReboots, rdf.Integer, 0)
                global_status.setS(ns.uncleanRunnerExits, rdf.Integer, 0)
                retiredpppdevs = global_status.setS(ns.retiredPppDevices, rdf.Type(ns.RetiredPppDevices))

                # Update info
                update_info = root.setS(ns_ui.updateInfo, rdf.Type(ns_ui.UpdateInfo))
                update_info.setS(ns_ui.changeLog, rdf.String, '')
                update_info.setS(ns_ui.latestKnownVersion, rdf.String, '')
        
                # License parameters
                license_info = root.setS(ns_ui.licenseInfo, rdf.Type(ns_ui.LicenseInfo))
                license_info.setS(ns_ui.maxNormalConnections, rdf.Integer, 0)
                license_info.setS(ns_ui.maxSiteToSiteConnections, rdf.Integer, 0)
                license_info.setS(ns_ui.validityStart, rdf.Datetime, now)
                license_info.setS(ns_ui.validityEnd, rdf.Datetime, now)
                license_info.setS(ns_ui.validityRecheckLatest, rdf.Datetime, now)
                license_info.setS(ns_ui.licenseString, rdf.String, '')
                license_info.setS(ns_ui.isDemoLicense, rdf.Boolean, False)
                license_info.setS(ns_ui.demoValidityStart, rdf.Datetime, now)
                license_info.setS(ns_ui.demoValidityEnd, rdf.Datetime, now)
                
                # XXX: what other roots should we add here?

                f = open(constants.INSTALLATION_UUID, 'rb')
                uuid = f.read().strip()
                f.close()
                root.setS(ns.installationUuid, rdf.String, uuid)
Exemplo n.º 11
0
        def _doimport():
            # Read the import.  Prune at the end, just in case.
            _log.info('configuration import: getting model')
            model = db.get_db().getModel()
            _log.info('configuration import: loading import file %s' % import_file)
            model.loadFile(import_file)
            _log.info('configuration import: in-place prune')
            root = model.getNodeByUri(ns.l2tpGlobalRoot, rdf.Type(ns.L2tpGlobalRoot))
            model.prune(root)
            _log.info('configuration import: prune ok')
            
            # fix configuration version differences
            #
            # Missing values do not have to be fixed here if defaults are ok;
            # caller will use fix_missing_database_values() to set defaults
            # for all missing values.  Caller will also regenerate protocol
            # configuration so that doesn't have to be done here either.

            # reset installation UUID to current system
            _log.info('configuration import: setting installation uuid')
            f = open(constants.INSTALLATION_UUID, 'rb')
            uuid = f.read().strip()
            f.close()
            root.setS(ns.installationUuid, rdf.String, uuid)
Exemplo n.º 12
0
def get_license_info():
    """Get license information node from RDF database."""

    return db.get_db().getRoot().getS(ns_ui.licenseInfo, rdf.Type(ns_ui.LicenseInfo))
Exemplo n.º 13
0
def get_new_ui_config():
    """Get new UI config node from RDF database."""

    return db.get_db().getRoot().getS(ns_ui.newUiConfig, rdf.Type(ns_ui.UiConfig))
Exemplo n.º 14
0
def get_global_status():
    """Get global status root node from RDF database."""
    
    return db.get_db().getRoot().getS(ns.globalStatus, rdf.Type(ns.GlobalStatus))
Exemplo n.º 15
0
def get_status():
    """Get protocol status root node from RDF database."""

    return db.get_db().getRoot().getS(ns.l2tpDeviceStatus,
                                      rdf.Type(ns.L2tpDeviceStatus))
Exemplo n.º 16
0
def get_db_root():
    return db.get_db().getRoot()
Exemplo n.º 17
0
 def save_debug(self, ctx, form, data):
     ui_root = db.get_db().getRoot().getS(ns_ui.uiConfig,
                                          rdf.Type(ns_ui.UiConfig))
     debug_fda = formalutils.FormDataAccessor(form, ['debug_group'], ctx)
     ui_root.setS(ns_ui.debug, rdf.Integer, debug_fda['debug'])
Exemplo n.º 18
0
 def render_dump(self, ctx, data):
     rd = rdfdumper.RdfDumper()
     return rd.dump_resource(db.get_db().getRoot())
Exemplo n.º 19
0
def get_new_ui_config():
    """Get new UI config node from RDF database."""

    return db.get_db().getRoot().getS(ns_ui.newUiConfig,
                                      rdf.Type(ns_ui.UiConfig))
Exemplo n.º 20
0
 def save_debug(self, ctx, form, data):
     ui_root = db.get_db().getRoot().getS(ns_ui.uiConfig, rdf.Type(ns_ui.UiConfig))
     debug_fda = formalutils.FormDataAccessor(form, ["debug_group"], ctx)
     ui_root.setS(ns_ui.debug, rdf.Integer, debug_fda["debug"])
Exemplo n.º 21
0
def _rdf_database_create_initial(_log):
    """Create empty config root.

    This function is called when our current configuration is
    missing or broken.  The initialized configuration has the
    proper structure (contains the mandatory nodes which pass
    sanity check) but is otherwise empty.

    XXX: We should probably add some warning or cause as to
    why the configuration is empty.
    """
        
    dbase = None
    try:
        try:
            from codebay.common import rdf
            from codebay.l2tpserver.rdfconfig import ns, ns_ui
            from codebay.l2tpserver.webui import uidatahelpers
            from codebay.l2tpserver import db
        
            # close database if open; just sanity
            try:
                db.get_db().close()
            except:
                _log.exception('failed to close database before recreating, ignoring')

            # remove old database
            rdf.Database.delete(constants.PRODUCT_DATABASE_FILENAME)

            # create new one
            dbase = rdf.Database.create(constants.PRODUCT_DATABASE_FILENAME)
            dbase.close()
            dbase = None
            
            @db.transact()
            def _func():
                now = datetime.datetime.utcnow()

                # Global root
                model = db.get_db().getModel()
                root = rdf.Node.make(model, rdf.Type(ns.L2tpGlobalRoot), ns.l2tpGlobalRoot)

                # Global status root
                global_status = root.setS(ns.globalStatus, rdf.Type(ns.GlobalStatus))
                global_status.setS(ns.watchdogReboots, rdf.Integer, 0)
                global_status.setS(ns.periodicReboots, rdf.Integer, 0)
                global_status.setS(ns.uncleanRunnerExits, rdf.Integer, 0)
                retiredpppdevs = global_status.setS(ns.retiredPppDevices, rdf.Type(ns.RetiredPppDevices))

                # Update info
                update_info = root.setS(ns_ui.updateInfo, rdf.Type(ns_ui.UpdateInfo))
                update_info.setS(ns_ui.changeLog, rdf.String, '')
                update_info.setS(ns_ui.latestKnownVersion, rdf.String, '')
        
                # License parameters
                license_info = root.setS(ns_ui.licenseInfo, rdf.Type(ns_ui.LicenseInfo))
                license_info.setS(ns_ui.maxNormalConnections, rdf.Integer, 0)
                license_info.setS(ns_ui.maxSiteToSiteConnections, rdf.Integer, 0)
                license_info.setS(ns_ui.validityStart, rdf.Datetime, now)
                license_info.setS(ns_ui.validityEnd, rdf.Datetime, now)
                license_info.setS(ns_ui.validityRecheckLatest, rdf.Datetime, now)
                license_info.setS(ns_ui.licenseString, rdf.String, '')
                license_info.setS(ns_ui.isDemoLicense, rdf.Boolean, False)
                license_info.setS(ns_ui.demoValidityStart, rdf.Datetime, now)
                license_info.setS(ns_ui.demoValidityEnd, rdf.Datetime, now)
                
                # XXX: what other roots should we add here?

                f = open(constants.INSTALLATION_UUID, 'rb')
                uuid = f.read().strip()
                f.close()
                root.setS(ns.installationUuid, rdf.String, uuid)

            _func()

            # UI default database (also creates initial protocol config)
            # (separate transaction)
            @db.transact()
            def _func():
                uidatahelpers.create_default_database()
            _func()
        except:
            _log.exception('_rdf_database_create_initial failed, fatal')
    finally:
        try:
            # this is just for sanity
            if dbase is not None:
                dbase.close()
                dbase = None
        except:
            _log.exception('_rdf_database_create_initial, failed to close db')

    return None
Exemplo n.º 22
0
 def _close_db():
     try:
         from codebay.l2tpserver import db
         db.get_db().close()
     except:
         _log.exception('failed to close l2tpserver db')
Exemplo n.º 23
0
def _check_configuration_import(_log):
    from codebay.l2tpserver import db
    from codebay.common import rdf
    from codebay.l2tpserver.rdfconfig import ns, ns_ui

    import_file = constants.CONFIGURATION_IMPORT_BOOT_FILE

    if os.path.exists(import_file):
        _log.info('configuration import file exists (%s), attempting import' % import_file)

        def _nukeold():
            # Nuke old database
            _log.info('configuration import: creating a fresh database')
            db.get_db().close()
            db.get_db().create()

        @db.transact()
        def _doimport():
            # Read the import.  Prune at the end, just in case.
            _log.info('configuration import: getting model')
            model = db.get_db().getModel()
            _log.info('configuration import: loading import file %s' % import_file)
            model.loadFile(import_file)
            _log.info('configuration import: in-place prune')
            root = model.getNodeByUri(ns.l2tpGlobalRoot, rdf.Type(ns.L2tpGlobalRoot))
            model.prune(root)
            _log.info('configuration import: prune ok')
            
            # fix configuration version differences
            #
            # Missing values do not have to be fixed here if defaults are ok;
            # caller will use fix_missing_database_values() to set defaults
            # for all missing values.  Caller will also regenerate protocol
            # configuration so that doesn't have to be done here either.

            # reset installation UUID to current system
            _log.info('configuration import: setting installation uuid')
            f = open(constants.INSTALLATION_UUID, 'rb')
            uuid = f.read().strip()
            f.close()
            root.setS(ns.installationUuid, rdf.String, uuid)

        @db.transact()
        def _postops():
            model = db.get_db().getModel()
            root = model.getNodeByUri(ns.l2tpGlobalRoot, rdf.Type(ns.L2tpGlobalRoot))

            # attempt to set keymap
            try:
                from codebay.l2tpserver import gnomeconfig
                cfg_ui = root.getS(ns_ui.uiConfig, rdf.Type(ns_ui.UiConfig))
                gnomeconfig.set_keymap_settings(cfg_ui.getS(ns_ui.keymap, rdf.String))
            except:
                _log.exception('setting keymap failed in import, ignoring')
                
            # XXX: root password is not in configuration, so we cannot import it.
            # This is probably best, so we cannot do anything about it here.
            
        try:
            _nukeold()
            _doimport()
            _postops()

            # done
            _log.info('configuration import: all done')
        except:
            # XXX: show import failure somehow to user after boot
            _log.exception('configuration import failed')

        try:
            # close db just in case
            db.get_db().close()
        except:
            _log.exception('db close failed, ignoring')

        # unlink even if failed, file is probably corrupt
        _log.info('deleting import file %s' % import_file)
        os.unlink(import_file)
        _log.info('deleting of import file successful')
    else:
        _log.debug('no import file')
Exemplo n.º 24
0
 def render_dump(self, ctx, data):
     rd = rdfdumper.RdfDumper()
     return rd.dump_resource(db.get_db().getRoot().getS(
         ns.l2tpDeviceStatus))
Exemplo n.º 25
0
        res.append(t)
        
        # render string arcs
        for [p,o] in stringarcs:
            res.append(ind2 + '%s = "%s" (%s)' % (self._prettify_uri(p.getUri()), o.getLiteral(), self._prettify_uri(o.getDatatype())))

        # render rdf number _n arcs, regardless of type
        for [n,p,o] in numberedarcs:
            if o.isLiteral():
                res.append(ind2 + '%s = "%s" (%s)' % (self._prettify_uri(p.getUri()), o.getLiteral(), self._prettify_uri(o.getDatatype())))
            else:
                res.append(ind2 + self._prettify_uri(p.getUri()))
                res.extend(self._dump(o, indent+2))

        # render resource arcs (blank or otherwise)
        for [p,o] in resourcearcs:
            res.append(ind2 + self._prettify_uri(p.getUri()))
            res.extend(self._dump(o, indent+2))

        # loop detection
        del self._visiting[unicode(node.getUri())]
        return res
    
if __name__ == '__main__':
    from codebay.l2tpserver import db

    rd = RdfDumper()
    print rd.dump_resource(db.get_db().getRoot())

    
Exemplo n.º 26
0
 def render_dump(self, ctx, data):
     rd = rdfdumper.RdfDumper()
     return rd.dump_resource(db.get_db().getRoot())
Exemplo n.º 27
0
def get_db_root():
    return db.get_db().getRoot()
Exemplo n.º 28
0
 def render_dump(self, ctx, data):
     rd = rdfdumper.RdfDumper()
     return rd.dump_resource(db.get_db().getRoot().getS(ns.l2tpDeviceStatus))
Exemplo n.º 29
0
def get_new_config():
    """Get new protocol configuration root node from RDF database."""

    return db.get_db().getRoot().getS(ns.newL2tpDeviceConfig, rdf.Type(ns.L2tpDeviceConfig))
Exemplo n.º 30
0
def get_new_config():
    """Get new protocol configuration root node from RDF database."""

    return db.get_db().getRoot().getS(ns.newL2tpDeviceConfig,
                                      rdf.Type(ns.L2tpDeviceConfig))
Exemplo n.º 31
0
def get_status():
    """Get protocol status root node from RDF database."""
    
    return db.get_db().getRoot().getS(ns.l2tpDeviceStatus, rdf.Type(ns.L2tpDeviceStatus))
Exemplo n.º 32
0
def get_global_status():
    """Get global status root node from RDF database."""

    return db.get_db().getRoot().getS(ns.globalStatus,
                                      rdf.Type(ns.GlobalStatus))
Exemplo n.º 33
0
 def _nukeold():
     # Nuke old database
     _log.info('configuration import: creating a fresh database')
     db.get_db().close()
     db.get_db().create()
Exemplo n.º 34
0
def get_license_info():
    """Get license information node from RDF database."""

    return db.get_db().getRoot().getS(ns_ui.licenseInfo,
                                      rdf.Type(ns_ui.LicenseInfo))
Exemplo n.º 35
0
    def _do_runner(self):
        """Handle runner command line commands."""

        if len(sys.argv) == 1:
            self.usage_and_exit()
        cmd = sys.argv[1]

        opt = optparse.OptionParser(usage='%prog', version='%prog')
        opt.add_option('-r', '--rdf-file', help='RDF file instead of default database',
                       action='store', dest='rdf_file', type='string', metavar='<file>')
        opt.add_option('-m', '--mode', help='Mode for start',
                       action='store', dest='mode', type='string', metavar='<string>')
        opt.add_option('-i', '--import-path', dest='importpath')
        opt.add_option('-n', '--no-distro-restart', help='Prevent distro networking restart on runner stop',
                       action='store_true', dest='no_distro_restart', default=False)

        opt.set_defaults(rdf_file=None,
                         mode=None,
                         importpath='system')

        (opts, args) = opt.parse_args(sys.argv[2:])
        
        print 'Command = %s, Options: %s' % (cmd, str(opts))

        if opts.rdf_file is not None:
            print 'runner using database file: %s' % opts.rdf_file
            db.replace_database_with_file(opts.rdf_file, constants.RUNNER_TEMPORARY_SQLITE_DATABASE)

        if opts.mode is not None:
            mode = opts.mode
        else:
            mode = 'FULL'
            print 'no mode given, using %s' % mode

        importpath = 'system'
        if opts.importpath is not None:
            importpath = opts.importpath

        nodistrorestart = False
        if opts.no_distro_restart is not None and opts.no_distro_restart:
            nodistrorestart = True

        # XXX: these need rethinking, currently ripped from startstop.py.
        
        # XXX: this should probably be some command name => lambda system, to make command help etc easier

        # XXX: also need transactions here to make things reasonably fast (e.g. for rdf dumps)
        try:
            if mode == 'FULL':
                runner_mode = startstop._mode_full
            elif mode == 'NETWORK-ONLY':
                runner_mode = startstop._mode_network_only
            else:
                raise Exception('unknown mode: %s' % mode)

            _log.debug('starting runner in mode: %s' % runner_mode)
            r = startstop.L2tpRunner(mode=runner_mode, nodistrorestart=nodistrorestart, importpath=importpath)

            if cmd == 'run':
                r.create_pidfile()
                r.run()

            elif cmd == 'resetstate':
                # Set to a fresh node - this orphans all previous state
                return db.get_db().getRoot().setS(ns.l2tpDeviceStatus, rdf.Type(ns.L2tpDeviceStatus))

            elif cmd == 'dumpall':
                rd = rdfdumper.RdfDumper()
                print rd.dump_resource(db.get_db().getRoot(), escaped=True)
            
            elif cmd == 'dumpstatus':
                rd = rdfdumper.RdfDumper()
                print rd.dump_resource(db.get_db().getRoot().getS(ns.l2tpDeviceStatus), escaped=True)

            elif cmd == 'dumpconfig':
                rd = rdfdumper.RdfDumper()
                print rd.dump_resource(db.get_db().getRoot().getS(ns.l2tpDeviceConfig), escaped=True)
            
            elif cmd == 'status':
                st_root = helpers.get_status()

                st_last_str = 'unknown'
                if st_root.hasS(ns.lastStateUpdate):
                    st_last_str = st_root.getS(ns.lastStateUpdate, rdf.Datetime).isoformat()
                
                st_start_str = 'unknown'
                if st_root.hasS(ns.startTime):
                    st_start_str = st_root.getS(ns.startTime, rdf.Datetime).isoformat()

                st_stop_str = 'unknown'
                if st_root.hasS(ns.stopTime):
                    st_stop_str = st_root.getS(ns.stopTime, rdf.Datetime).isoformat()

                st_str = 'unknown'
                st = st_root.getS(ns.state)
                if st.hasType(ns.StateStarting):
                    st_str = 'starting'
                    subst = st.getS(ns.subState)
                    if subst.hasType(ns.StateStartingPreparing):
                        st_str += ' - preparing'
                    if subst.hasType(ns.StateStartingWaitingForDhcp):
                        st_str += ' - waiting for dhcp'
                    if subst.hasType(ns.StateStartingNetwork):
                        st_str += ' - starting network'
                    if subst.hasType(ns.StateStartingDaemons):
                        st_str += ' - starting daemons'
                elif st.hasType(ns.StateRunning):
                    st_str = 'running'
                elif st.hasType(ns.StateStopping):
                    st_str = 'stopping'
                elif st.hasType(ns.StateStopped):
                    st_str = 'stopped'

                st_ppp = 'unknown'
                if st_root.hasS(ns.pppDevices):
                    st_ppp = '%s' % len(helpers.get_ppp_devices())
            
                print 'STATUS: start=%s, stop=%s, last_update=%s, devs=%s, state: %s' % (st_start_str, st_stop_str, st_last_str, st_ppp, st_str)

            elif cmd == 'start':
                r.start()

            elif cmd == 'public-interface-test':
                # XXX
                pass

            elif cmd == 'private-interface-test':
                # XXX
                pass

            elif cmd == 'route-test':
                # XXX
                pass

            elif cmd == 'stop':
                r.stop()

            else:
                raise Exception('unknown command: %s' % cmd)

        except:
            _log.exception('l2tpgw-runner command "%s" failed.' % cmd)
            raise