def init(self, db, env): """Initialize the application without loading it into the database. db: a ravel.db.RavelDb instance to be passed to the application's sub-shell env: a ravel.env.Environment instance of the CLI's executing environment to be passed to the application's sub-shell""" if not self.pyfile: return # discover sql components (tables, views, functions) if self.sqlfile is not None: with open(self.sqlfile) as f: self.components = discoverComponents(f.read()) logger.debug("discovered {0} components: {1}" .format(self.name, self.components)) # if needed, add path filepath = os.path.dirname(self.pyfile) ravel.util.append_path(filepath) try: self.module = importlib.import_module(self.name) self.console = self.module.console(db, env, self.components) # force module prompt to app name self.console.prompt = self.name + "> " self.console.doc_header = self.name + \ " commands (type help <topic>):" except BaseException, e: errstr = "{0}: {1}".format(type(e).__name__, str(e)) logger.warning("error loading %s console: %s", self.name, e)
def init(self, db, env): """Initialize the application without loading it into the database. db: a ravel.db.RavelDb instance to be passed to the application's sub-shell env: a ravel.env.Environment instance of the CLI's executing environment to be passed to the application's sub-shell""" if not self.pyfile: return # discover sql components (tables, views, functions) if self.sqlfile is not None: with open(self.sqlfile) as f: self.components = discoverComponents(f.read()) logger.debug("discovered {0} components: {1}".format( self.name, self.components)) # if needed, add path filepath = os.path.dirname(self.pyfile) ravel.util.append_path(filepath) try: self.module = importlib.import_module(self.name) self.console = self.module.console(db, env, self.components) # force module prompt to app name self.console.prompt = self.name + "> " self.console.doc_header = self.name + \ " commands (type help <topic>):" except BaseException, e: errstr = "{0}: {1}".format(type(e).__name__, str(e)) logger.warning("error loading %s console: %s", self.name, e)
def _delFlowByName(self, src, dst): hostnames = self.env.provider.cache_name if src not in hostnames: print "Unknown host", src return if dst not in hostnames: print "Unknown host", dst return src = hostnames[src] dst = hostnames[dst] self.db.cursor.execute("SELECT fid FROM rm WHERE src={0} and dst={1};" .format(src, dst)) result = self.db.cursor.fetchall() if len(result) == 0: logger.warning("no flow installed for hosts {0},{1}".format(src, dst)) return None fids = [res[0] for res in result] for fid in fids: self._delFlowById(fid) return fids
def clear_queue(queue_id): try: mq = sysv_ipc.MessageQueue(queue_id, sysv_ipc.IPC_CREAT, mode=0777) mq.remove() except sysv_ipc.PermissionsError: logger.warning( "could not clear clear message queue {0}".format(queue_id))
def _delFlowByName(self, src, dst): hostnames = self.env.provider.cache_name if src not in hostnames: print "Unknown host", src return if dst not in hostnames: print "Unknown host", dst return src = hostnames[src] dst = hostnames[dst] self.db.cursor.execute("SELECT fid FROM my_rm WHERE src={0} and dst={1};" .format(src, dst)) result = self.db.cursor.fetchall() if len(result) == 0: logger.warning("no flow installed for hosts {0},{1}".format(src, dst)) return None fids = [res[0] for res in result] for fid in fids: self._delFlowById(fid) return fids
def is_profiled(): "Check if profiling is enabled" try: shm = sysv_ipc.SharedMemory(ProfileQueueId) return shm.read().strip("\0") == ProfileOn except sysv_ipc.ExistentialError, e: logger.warning("profile queue doesn't exist: %", e) return False
def load_schema(self, script): """Load the specified schema into the database" script: path to a SQL script""" try: s = open(script, "r").read() logger.debug("loaded schema %s", script) self.cursor.execute(s) except psycopg2.DatabaseError, e: logger.warning("error loading schema: %s", self.fmt_errmsg(e))
def clear_queue(queue_id): try: mq = sysv_ipc.MessageQueue(queue_id, sysv_ipc.IPC_CREAT, mode=0777) mq.remove() except sysv_ipc.PermissionsError: logger.warning("could not clear clear message queue {0}" .format(queue_id))
def RavelCLI(opts): """Start a RavelConsole instance given a list of command line options opts: parsed OptionParser object""" if opts.custom: ravel.mndeps.custom(opts.custom) topo = ravel.mndeps.build(opts.topo) if topo is None: print "Invalid mininet topology", opts.topo return if opts.script is not None and not os.path.isfile(opts.script): print "{0}: no such script file".format(opts.script) return passwd = None if opts.password: passwd = getpass.getpass("Enter password: "******"Pox instance is already running. Please shut down " \ "existing controller first (or run ravel.py --clean)." return controller = PoxInstance("ravel.controller.poxmgr") from ravel.network import MininetProvider, EmptyNetProvider if opts.onlydb: net = EmptyNetProvider(raveldb, topo) else: net = MininetProvider(raveldb, topo, controller) if net is None: print "Cannot start network" env = Environment(raveldb, net, Config.AppDirs, opts) env.start() while True: try: if opts.script is not None: RavelConsole(env).do_exec(opts.script) if opts.exit: break RavelConsole(env, quiet=opts.script).cmdloop() break except Exception, e: logger.warning("console crashed: %s", e)
def load_topo(self, provider): """Load a topology from the specified network provider provider: a ravel.network.NetworkProvider instance""" topo = provider.topo try: node_count = 0 nodes = {} for sw in topo.switches(): node_count += 1 dpid = provider.getNodeByName(sw).dpid ip = provider.getNodeByName(sw).IP() mac = provider.getNodeByName(sw).MAC() nodes[sw] = node_count self.cursor.execute("INSERT INTO switches (sid, dpid, ip, mac, name) " "VALUES ({0}, '{1}', '{2}', '{3}', '{4}');" .format(node_count, dpid, ip, mac, sw)) for host in topo.hosts(): node_count += 1 ip = provider.getNodeByName(host).IP() mac = provider.getNodeByName(host).MAC() nodes[host] = node_count self.cursor.execute("INSERT INTO hosts (hid, ip, mac, name) " "VALUES ({0}, '{1}', '{2}', '{3}');" .format(node_count, ip, mac, host)) for link in topo.links(): h1,h2 = link if h1 in topo.switches() and h2 in topo.switches(): ishost = 0 else: ishost = 1 sid = nodes[h1] nid = nodes[h2] self.cursor.execute("INSERT INTO tp(sid, nid, ishost, isactive) " "VALUES ({0}, {1}, {2}, {3});" .format(sid, nid, ishost, 1)) # bidirectional edges self.cursor.execute("INSERT INTO tp(sid, nid, ishost, isactive) " "VALUES ({1}, {0}, {2}, {3});" .format(sid, nid, ishost, 1)) self.cursor.execute("INSERT INTO ports(sid, nid, port) " "VALUES ({0}, {1}, {2}), ({1}, {0}, {3});" .format(sid, nid, topo.port(h1, h2)[0], topo.port(h1, h2)[1])) except psycopg2.DatabaseError, e: logger.warning("error loading topology: %s", self.fmt_errmsg(e))
def num_connections(self): """Returns the number of existing connections to the database. If there are >1 connections, a new Ravel base implementation cannot be loaded into the database. returns: the number of existing connections to the database""" try: self.cursor.execute("SELECT * FROM pg_stat_activity WHERE " "datname='{0}'".format(self.name)) # ignore cursor connection return len(self.cursor.fetchall()) - 1 except psycopg2.DatabaseError, e: logger.warning("error loading schema: %s", self.fmt_errmsg(e))
def __init__(self, queue_id): "queue_id: the integer id of the queue to be used" self.queue_id = queue_id pc = ravel.profiling.PerfCounter("mq_connect") pc.start() try: self.mq = sysv_ipc.MessageQueue(self.queue_id, mode=0777) except sysv_ipc.ExistentialError, e: logger.warning("queue {0} does not exist: {1}".format( self.queue_id, e)) self.mq = sysv_ipc.MessageQueue(self.queue_id, sysv_ipc.IPC_CREAT, mode=0777)
def truncate(self): """Clean the database of any state Ravel components, except for topology tables. This rolls back the database to the state after the topology is first loaded""" try: tables = ["cf", "clock", "p_spv", "spatial_ref_sys", "spv_tb_del", "spv_tb_ins", "rm", "rm_delta", "urm"] self.cursor.execute("truncate %s;" % ", ".join(tables)) logger.debug("truncated tables") self.cursor.execute("INSERT INTO clock values (0);") except psycopg2.DatabaseError, e: logger.warning("error truncating databases: %s", self.fmt_errmsg(e))
def _delFlowById(self, fid): try: # does the flow exist? self.db.cursor.execute("SELECT fid FROM my_rm WHERE fid={0}".format(fid)) if len(self.db.cursor.fetchall()) == 0: logger.warning("no flow installed with fid %s", fid) return None self.db.cursor.execute("DELETE FROM my_rm WHERE fid={0}".format(fid)) return fid except Exception, e: print e return None
def _delFlowById(self, fid): try: # does the flow exist? self.db.cursor.execute("SELECT fid FROM rm WHERE fid={0}".format(fid)) if len(self.db.cursor.fetchall()) == 0: logger.warning("no flow installed with fid %s", fid) return None self.db.cursor.execute("DELETE FROM rm WHERE fid={0}".format(fid)) return fid except Exception, e: print e return None
def __init__(self, queue_id): "queue_id: the integer id of the queue to be used" self.queue_id = queue_id pc = ravel.profiling.PerfCounter("mq_connect") pc.start() try: self.mq = sysv_ipc.MessageQueue(self.queue_id, mode=0777) except sysv_ipc.ExistentialError, e: logger.warning("queue {0} does not exist: {1}" .format(self.queue_id, e)) self.mq = sysv_ipc.MessageQueue(self.queue_id, sysv_ipc.IPC_CREAT, mode=0777)
def clean(self): """Clean the database of any existing Ravel components""" # close existing connections self.conn.close() conn = None try: conn = psycopg2.connect(database="postgres", user=self.user, password=self.passwd) conn.set_isolation_level(ISOLEVEL) cursor = conn.cursor() cursor.execute("drop database %s" % self.name) except psycopg2.DatabaseError, e: logger.warning("error cleaning database: %s", self.fmt_errmsg(e))
def unload_app(self, appname): """Unload an application from the environment appname: the application to load""" # don't unload coreapps if appname in self.coreapps: logger.warning("cannot unload core apps {0}".format(self.coreapps)) return app = self.apps[appname] app.unload(self.db) if app.name in self.loaded: del self.loaded[app.name] if app.shortcut is not None and app.shortcut in self.loaded: del self.loaded[app.shortcut]
def add_extensions(self): """If not already added, add extensions required by Ravel (plpythonu, postgis, pgrouting)""" try: self.cursor.execute("SELECT 1 FROM pg_catalog.pg_namespace n JOIN " + "pg_catalog.pg_proc p ON pronamespace = n.oid " + "WHERE proname = 'pgr_dijkstra';") fetch = self.cursor.fetchall() if fetch == []: self.cursor.execute("CREATE EXTENSION IF NOT EXISTS plpythonu;") self.cursor.execute("CREATE EXTENSION IF NOT EXISTS postgis;") self.cursor.execute("CREATE EXTENSION IF NOT EXISTS pgrouting;") self.cursor.execute("CREATE EXTENSION plsh;") logger.debug("created extensions") except psycopg2.DatabaseError, e: logger.warning("error loading extensions: %s", self.fmt_errmsg(e))
def update_trigger_path(filename, path): """Update PYTHONPATH within a Python-based trigger implemented within the SQL file specified in filename. filename: the file containing the SQL trigger implementation path: the path to append to PYTHONPATH""" path = os.path.expanduser(path) if not os.path.isfile(filename): logger.warning("cannot find sql file %s", filename) return with open(filename, "r") as f: lines = [] content = f.read() newstr = 'sys.path.append("{0}")'.format(path) pattern = re.compile(r"sys.path.append\(\S+\)") content = re.sub(pattern, newstr, content) open(filename, "w").write(content)
def load_app(self, appname): """Load an application in the environment appname: the application to unload""" if appname in self.loaded: return # look for newly-added applications self.discover() if appname in self.apps: app = self.apps[appname] app.load(self.db) if app.is_loadable(): self.loaded[app.name] = app if app.shortcut is not None and app.shortcut != app.name: if app.shortcut in self.loaded: logger.warning("shortcut {0} for {1} already in use" .format(app.shortcut, app.name)) else: self.loaded[app.shortcut] = app
def create(self): """If not created, create a database with the name specified in the constructor""" conn = None try: conn = psycopg2.connect(database="postgres", user=self.user, password=self.passwd) conn.set_isolation_level(ISOLEVEL) cursor = conn.cursor() cursor.execute("SELECT datname FROM pg_database WHERE " + "datistemplate = false;") fetch = cursor.fetchall() dblist = [fetch[i][0] for i in range(len(fetch))] if self.name not in dblist: cursor.execute("CREATE DATABASE %s;" % self.name) logger.debug("created databse %s", self.name) except psycopg2.DatabaseError, e: logger.warning("error creating database: %s", self.fmt_errmsg(e))
def load_app(self, appname): """Load an application in the environment appname: the application to unload""" if appname in self.loaded: return # look for newly-added applications self.discover() if appname in self.apps: app = self.apps[appname] app.load(self.db) if app.is_loadable(): self.loaded[app.name] = app if app.shortcut is not None and app.shortcut != app.name: if app.shortcut in self.loaded: logger.warning( "shortcut {0} for {1} already in use".format( app.shortcut, app.name)) else: self.loaded[app.shortcut] = app
def __init__(self, name, user, base, passwd=None, reconnect=False): """name: the name of the database to connect to user: the username to use to connect base: a file containing the SQL implementation for Ravel's base passwd: the password to connect to the database reconnect: true to connect to an existing database setup, false to load a new instance of Ravel's base into the database""" self.name = name self.user = user self.passwd = passwd self.base = base self.cleaned = not reconnect self._cursor = None self._conn = None if not reconnect and self.num_connections() > 0: logger.warning("existing connections to database, skipping reinit") self.cleaned = False elif not reconnect: self.init() self.cleaned = True
def cli(self, cmd): "EmptyNetProvider has no CLI, raises warning" logger.warning("no CLI available for db-only mode")
def RavelCLI(opts): """Start a RavelConsole instance given a list of command line options opts: parsed OptionParser object""" if opts.custom: ravel.mndeps.custom(opts.custom) topo = ravel.mndeps.build(opts.topo) if topo is None: print "Invalid mininet topology", opts.topo return if opts.script is not None and not os.path.isfile(opts.script): print "{0}: no such script file".format(opts.script) return passwd = None if opts.password: passwd = getpass.getpass("Enter password: "******"Pox instance is already running. Please shut down " \ "existing controller first (or run ravel.py --clean)." return controller = PoxInstance("ravel.controller.poxmgr") from ravel.network import MininetProvider, EmptyNetProvider if opts.onlydb: net = EmptyNetProvider(raveldb, topo) else: net = MininetProvider(raveldb, topo, controller) if net is None: print "Cannot start network" env = Environment(raveldb, net, Config.AppDirs, opts) env.start() # --------------------------------------------------------------- # Sarah's additions # --------------------------------------------------------------- with open("/home/ravel/ravel/ep/resource_logs/boottime.txt", "a") as bootTimeLog: if opts.restore: RavelConsole(env).do_exec("scripts/wipeSchema.sql") os.system( "sudo -u ravel psql ravel < /home/ravel/ravel/ep/backup.sql") bootMode = "restored" else: bootMode = "launched" # this is the last thing we do before launching the CLI... add time to log bootTimeLog.write("{0} - Ravel {1}. Ready for CLI.\n".format( datetime.datetime.now(), bootMode)) # --------------------------------------------------------------- while True: try: if opts.script is not None: RavelConsole(env).do_exec(opts.script) if opts.exit: break RavelConsole(env, quiet=opts.script).cmdloop() break except Exception, e: logger.warning("console crashed: %s", e)