Example #1
0
def register(extschema, ovsschema, ovsremote):
    """Register interest in all configuration and index
    columns for all tables in ovsschema.

    Args:
        extschema (opslib.RestSchema): This is the
            parsed extended-schema (vswitch.extschema) object.
        ovsschema: OVSDB schema file
        ovsremote: OVSDB remote socket

    Returns:
        ovs.db.idl.Idl instance
    """

    schema_helper = SchemaHelper(ovsschema)

    for tablename, tableschema in extschema.ovs_tables.iteritems():

        register_columns = []

        # configuration columns
        config_columns = [str(key) for key in tableschema.config.keys()]
        # reference columns
        reference_columns = [str(key) for key in tableschema.references.keys()]

        # index columns
        for item in tableschema.index_columns:
            if not item in config_columns:
                register_columns.append(str(item))

        register_columns += config_columns
        register_columns += reference_columns

        # dynamic columns
        if tableschema.dynamic:
            for key in tableschema.dynamic.keys():
                if key not in register_columns:
                    register_columns.append(key)

        # NOTE: remove this when we have a proper
        # solution for TG-1116
        if str(tablename) == 'VLAN':
            register_columns.append('internal_usage')

        schema_helper.register_columns(str(tablename), register_columns)

    idl = ops.opsidl.OpsIdl(ovsremote, schema_helper)
    return idl
Example #2
0
    def start(self):
        # reset all connections
        try:
            app_log.info("Starting Connection Manager!")
            if self.idl is not None:
                self.idl.close()

            # set up the schema and register all tables
            self.schema_helper = SchemaHelper(self.schema)
            self.schema_helper.register_all()
            self.idl = Idl(self.remote, self.schema_helper)
            self.curr_seqno = self.idl.change_seqno

            #  we do not reset transactions when the DB connection goes down
            if self.transactions is None:
                self.transactions = OvsdbTransactionList()

            self.idl_run()
            self.monitor_connection()

        except Exception as e:
            # TODO: log this exception
            # attempt again in the next IOLoop iteration
            app_log.info("Connection Manager failed! Reason: %s" % e)
            IOLoop.current().add_timeout(time.time() + self.timeout,
                                         self.start)
Example #3
0
    def find(self, columns, table, cond=None):
        """ which only works in main thread, depends on signal """
        schema_file = "%s/vswitch.ovsschema" % ovs.dirs.PKGDATADIR
        try:
            from ovs.db.idl import SchemaHelper
            schema_helper = SchemaHelper(schema_file)
            schema_helper.register_all()
            schema = schema_helper.get_idl_schema()
            self._check_column(schema, columns, table, cond)
            idl = ovs.db.idl.Idl(self.sock, schema_helper)
        except ImportError:
            schema = ovs.db.schema.DbSchema.from_json(
                ovs.json.from_file(schema_file))
            # check schema
            self._check_column(schema, columns, table, cond)
            idl = ovs.db.idl.Idl(self.sock, schema)

        seqno = idl.change_seqno
        while True:
            idl.run()
            if seqno == idl.change_seqno:
                poller = ovs.poller.Poller()
                idl.wait(poller)
                poller.block()
                continue
            break
        results = list()

        def __append_row(results, row):
            result = dict()
            for column_name in columns:
                result[column_name] = self._get_row_val(row, column_name)
            results.append(result)
            return

        for row in idl.tables[table].rows.itervalues():
            match = True
            if cond:
                for k, v in cond.iteritems():
                    if self._get_row_val(row, k) != v:
                        match = False
                        break
            if match:
                __append_row(results, row)
        idl.close()
        return results
Example #4
0
def connect():
    ovsschema = settings.get('cfg_db_schema')
    ovsremote = settings.get('ovs_remote')
    schema_helper = SchemaHelper(ovsschema)
    schema_helper.register_all()
    idl = Idl(ovsremote, schema_helper)

    change_seqno = idl.change_seqno
    while True:
        idl.run()
        if change_seqno != idl.change_seqno:
            break
        poller = ovs.poller.Poller()
        idl.wait(poller)
        poller.block()

    return idl
Example #5
0
    def start(self, register_tables=None, track_all=False):
        try:
            app_log.info("Starting Connection Manager!")

            # Ensure stopping of any existing connection
            self.stop()
            self.schema_helper = SchemaHelper(self.schema)

            # Store registration and tracking info in case initial
            # connection is unsuccessful. If initial connection is unsuccesful,
            # the timeout callback will cause register_tables and track_all
            # to be None.
            if register_tables is not None:
                self.register_tables = register_tables
            if track_all is not False:
                self.track_all = track_all

            if not self.register_tables:
                self.register_schema_helper_columns(self.schema_helper,
                                                    self.rest_schema)
            else:
                for table in self.register_tables:
                    self.schema_helper.register_table(str(table))

            self.idl = OpsIdl(self.remote, self.schema_helper)
            self.curr_seqno = self.idl.change_seqno

            if self.track_all:
                app_log.debug("Tracking all changes")
                self.idl.track_add_all()

            # We do not reset transactions when the DB connection goes down
            if self.transactions is None:
                self.transactions = OvsdbTransactionList()

            self.idl_init()

        except Exception as e:
            app_log.info("Connection Manager failed! Reason: %s" % e)
            self.timeout_handle = \
                IOLoop.current().add_timeout(time.time() + self.timeout,
                                             self.start)
Example #6
0
    def ovs_run_module():
        module = AnsibleModule(
            argument_spec=argument_spec,
            supports_check_mode=supports_check_mode,
        )
        module._ovs_vars = {}

        state = module.params['state']
        op = ops_with_defaults[state]

        if not HAS_OVS:
            module.fail_json(
                msg='Python Open vSwitch library is not installed')

        try:
            schema_path = '{}/{}'.format(ovs.dirs.PKGDATADIR, schema_file)
            remote = 'unix:{}/{}'.format(ovs.dirs.RUNDIR, ctl)
            schema = SchemaHelper(location=schema_path)
            op['register_interest'](schema)
            idl = Idl(remote, schema)

            try:
                wait_for_db_change(idl)
            except Exception as e:
                module.fail_json(msg=str(e), exception=traceback.format_exc())

            op['prepare'](module, idl)

            if not module.check_mode:
                for i in range(3):
                    txn = Transaction(idl)
                    op['build_txn'](module, idl, txn)
                    status = txn.commit_block()
                    if status == Transaction.SUCCESS:
                        break
                    elif status != Transaction.TRY_AGAIN:
                        break

                if status == Transaction.SUCCESS:
                    changed = True
                elif status == Transaction.UNCHANGED:
                    changed = False
                else:
                    msg = op['txn_failure_msg'](module)
                    module.fail_json(msg='{}: {}'.format(msg, status))
            else:
                changed = True

            module.exit_json(changed=changed)
        except Exception as e:
            module.fail_json(msg=str(e), exception=traceback.format_exc())
        finally:
            if 'idl' in locals():
                idl.close()
Example #7
0
def register(extschema, ovsschema, ovsremote):
    """Register interest in all configuration and index
    columns for all tables in ovsschema.

    Args:
        extschema (opslib.RestSchema): This is the
            parsed extended-schema (vswitch.extschema) object.
        ovsschema: OVSDB schema file
        ovsremote: OVSDB remote socket

    Returns:
        ovs.db.idl.Idl instance
    """

    schema_helper = SchemaHelper(ovsschema)

    for tablename, tableschema in extschema.ovs_tables.iteritems():

        register_columns = []

        # configuration columns
        config_columns = [str(key) for key in tableschema.config.keys()]
        # reference columns
        reference_columns = [str(key) for key in tableschema.references.keys()]


        # index columns
        for item in tableschema.index_columns:
            if not item in config_columns:
                register_columns.append(str(item))

        register_columns += config_columns
        register_columns += reference_columns

        schema_helper.register_columns(str(tablename), register_columns)

    idl = ops.opsidl.OpsIdl(ovsremote, schema_helper)
    return idl
Example #8
0
    def start(self):
        try:
            app_log.info("Starting Connection Manager!")
            if self.idl is not None:
                self.idl.close()
            self.schema_helper = SchemaHelper(self.schema)
            self.schema_helper.register_all()
            self.idl = OpsIdl(self.remote, self.schema_helper)
            self.curr_seqno = self.idl.change_seqno

            # We do not reset transactions when the DB connection goes down
            if self.transactions is None:
                self.transactions = OvsdbTransactionList()

            self.idl_init()

        except Exception as e:
            app_log.info("Connection Manager failed! Reason: %s" % e)
            IOLoop.current().add_timeout(time.time() + self.timeout,
                                         self.start)
Example #9
0
class OvsdbConnectionManager:
    def __init__(self, remote, schema, *args, **kwargs):
        self.timeout = OVSDB_DEFAULT_CONNECTION_TIMEOUT
        self.remote = remote
        self.schema = schema
        self.schema_helper = None
        self.idl = None
        self.transactions = None
        self.curr_seqno = 0
        self.connected = False

    def start(self):
        try:
            app_log.info("Starting Connection Manager!")
            if self.idl is not None:
                self.idl.close()
            self.schema_helper = SchemaHelper(self.schema)
            self.schema_helper.register_all()
            self.idl = OpsIdl(self.remote, self.schema_helper)
            self.curr_seqno = self.idl.change_seqno

            # We do not reset transactions when the DB connection goes down
            if self.transactions is None:
                self.transactions = OvsdbTransactionList()

            self.idl_init()

        except Exception as e:
            app_log.info("Connection Manager failed! Reason: %s" % e)
            IOLoop.current().add_timeout(time.time() + self.timeout,
                                         self.start)

    def idl_init(self):
        try:
            self.idl.run()
            if not self.idl.has_ever_connected():
                app_log.debug("ovsdb unavailable retrying")
                IOLoop.current().add_timeout(time.time() + self.timeout,
                                             self.idl_init)
            else:
                self.idl_establish_connection()
        except error.Error as e:
            # idl will raise an error exception if cannot connect
            app_log.debug("Failed to connect, retrying. Reason: %s" % e)
            IOLoop.current().add_timeout(time.time() + self.timeout,
                                         self.idl_init)

    def idl_reconnect(self):
        try:
            app_log.debug("Trying to reconnect to ovsdb")
            # Idl run will do the reconnection
            self.idl.run()
            # If the seqno change the ovsdb connection is restablished.
            if self.curr_seqno == self.idl.change_seqno:
                app_log.debug("ovsdb unavailable retrying")
                self.connected = False
                IOLoop.current().add_timeout(time.time() + self.timeout,
                                             self.idl_reconnect)
            else:
                self.idl_establish_connection()
        except error.Error as e:
            # idl will raise an error exception if cannot reconnect
            app_log.debug("Failed to connect, retrying. Reason: %s" % e)
            IOLoop.current().add_timeout(time.time() + self.timeout,
                                         self.idl_reconnect)

    def idl_establish_connection(self):
        app_log.info("ovsdb connection ready")
        self.connected = True
        self.curr_seqno = self.idl.change_seqno
        self.ovs_socket = self.idl._session.rpc.stream.socket
        IOLoop.current().add_handler(self.ovs_socket.fileno(),
                                     self.idl_run,
                                     IOLoop.READ | IOLoop.ERROR)

    def idl_run(self, fd=None, events=None):
        if events & IOLoop.ERROR:
            app_log.debug("Socket fd %s error" % fd)
            if fd is not None:
                IOLoop.current().remove_handler(fd)
                self.idl_reconnect()
        elif events & IOLoop.READ:
            app_log.debug("Updating idl replica")
            self.idl.run()
            if self.curr_seqno != self.idl.change_seqno and \
               len(self.transactions.txn_list):
                self.check_transactions()
            self.curr_seqno = self.idl.change_seqno

    def check_transactions(self):
        for index, tx in enumerate(self.transactions.txn_list):
            tx.commit()
            # TODO: Handle all states
            if tx.status is not INCOMPLETE:
                self.transactions.txn_list.pop(index)
                tx.event.set()

    def get_new_transaction(self):
        return OvsdbTransaction(self.idl)

    def monitor_transaction(self, txn):
        self.transactions.add_txn(txn)
Example #10
0
class OvsdbConnectionManager:
    def __init__(self, remote, schema, *args, **kwargs):
        self.timeout = OVSDB_DEFAULT_CONNECTION_TIMEOUT
        self.remote = remote
        self.schema = schema
        self.schema_helper = None
        self.idl = None
        self.transactions = None

        self.curr_seqno = 0

    def start(self):
        # reset all connections
        try:
            app_log.info("Starting Connection Manager!")
            if self.idl is not None:
                self.idl.close()

            # set up the schema and register all tables
            self.schema_helper = SchemaHelper(self.schema)
            self.schema_helper.register_all()
            self.idl = Idl(self.remote, self.schema_helper)
            self.curr_seqno = self.idl.change_seqno

            #  we do not reset transactions when the DB connection goes down
            if self.transactions is None:
                self.transactions = OvsdbTransactionList()

            self.idl_run()
            self.monitor_connection()

        except Exception as e:
            # TODO: log this exception
            # attempt again in the next IOLoop iteration
            app_log.info("Connection Manager failed! Reason: %s" % e)
            IOLoop.current().add_timeout(time.time() + self.timeout,
                                         self.start)

    def monitor_connection(self):
        try:
            self.poller = Poller()
            self.idl.wait(self.poller)
            self.timeout = self.poller.timeout / 1000.0
            self.add_fd_callbacks()
        except:
            self.idl_run()
            IOLoop.current().add_timeout(time.time() + self.timeout,
                                         self.monitor_connection)

    def add_fd_callbacks(self):
        # add handlers to file descriptors from poll
        if len(self.poller.poll.rlist) is 0:
            self.rlist = []
            self.wlist = []
            self.xlist = []
            raise Exception('ovsdb read unavailable')

        for fd in self.poller.poll.rlist:
            if fd not in self.rlist:
                IOLoop.current().add_handler(fd, self.read_handler,
                                             IOLoop.READ | IOLoop.ERROR)
                self.rlist.append(fd)
                IOLoop.current().add_timeout(time.time() + self.timeout,
                                             self.read_handler)

    def read_handler(self, fd=None, events=None):
        if fd is not None:
            IOLoop.current().remove_handler(fd)
            self.rlist.remove(fd)

        self.idl_run()
        IOLoop.current().add_callback(self.monitor_connection)

    def idl_run(self):
        self.idl.run()
        self.curr_seqno = self.idl.change_seqno
        if len(self.transactions.txn_list):
            self.check_transactions()

    def check_transactions(self):

        for item in self.transactions.txn_list:
            item.commit()

        count = 0
        for item in self.transactions.txn_list:

            # TODO: Handle all states
            if item.status is not INCOMPLETE:
                self.transactions.txn_list.pop(count)
                item.event.set()
            else:
                count += 1

    def get_new_transaction(self):
        return OvsdbTransaction(self.idl)

    def monitor_transaction(self, txn):
        self.transactions.add_txn(txn)
Example #11
0
class OvsdbConnectionManager:
    def __init__(self, remote, schema, rest_schema, *args, **kwargs):
        self.timeout = OVSDB_DEFAULT_CONNECTION_TIMEOUT
        self.remote = remote
        self.schema = schema
        self.rest_schema = rest_schema
        self.schema_helper = None
        self.idl = None
        self.transactions = None
        self.curr_seqno = 0
        self.connected = False
        self._callbacks = {}
        self._callbacks[CHANGES_CB_TYPE] = set()
        self._callbacks[ESTABLISHED_CB_TYPE] = set()
        self.timeout_handle = None
        self.ovs_socket = None
        self.register_tables = None
        self.track_all = False
        self.txn_timeout_handle = None

    def start(self, register_tables=None, track_all=False):
        try:
            app_log.info("Starting Connection Manager!")

            # Ensure stopping of any existing connection
            self.stop()
            self.schema_helper = SchemaHelper(self.schema)

            # Store registration and tracking info in case initial
            # connection is unsuccessful. If initial connection is unsuccesful,
            # the timeout callback will cause register_tables and track_all
            # to be None.
            if register_tables is not None:
                self.register_tables = register_tables
            if track_all is not False:
                self.track_all = track_all

            if not self.register_tables:
                self.register_schema_helper_columns(self.schema_helper,
                                                    self.rest_schema)
            else:
                for table in self.register_tables:
                    self.schema_helper.register_table(str(table))

            self.idl = OpsIdl(self.remote, self.schema_helper)
            self.curr_seqno = self.idl.change_seqno

            if self.track_all:
                app_log.debug("Tracking all changes")
                self.idl.track_add_all()

            # We do not reset transactions when the DB connection goes down
            if self.transactions is None:
                self.transactions = OvsdbTransactionList()

            self.idl_init()

        except Exception as e:
            app_log.info("Connection Manager failed! Reason: %s" % e)
            self.timeout_handle = \
                IOLoop.current().add_timeout(time.time() + self.timeout,
                                             self.start)

    def stop(self):
        if self.ovs_socket:
            IOLoop.current().remove_handler(self.ovs_socket)
            self.ovs_socket = None

        if self.timeout_handle:
            IOLoop.current().remove_timeout(self.timeout_handle)
            self.timeout_handle = None

        self.stop_transaction_timer()

        if self.idl:
            self.idl.close()
            self.idl = None

    def idl_init(self):
        try:
            self.idl.run()
            if not self.idl.has_ever_connected():
                app_log.debug("ovsdb unavailable retrying")
                self.timeout_handle = \
                    IOLoop.current().add_timeout(time.time() + self.timeout,
                                                 self.idl_init)
            else:
                self.idl_establish_connection()
        except error.Error as e:
            # idl will raise an error exception if cannot connect
            app_log.debug("Failed to connect, retrying. Reason: %s" % e)
            self.timeout_handle = \
                IOLoop.current().add_timeout(time.time() + self.timeout,
                                             self.idl_init)

    def idl_reconnect(self):
        try:
            app_log.debug("Trying to reconnect to ovsdb")
            # Idl run will do the reconnection
            self.idl.run()
            # If the seqno change the ovsdb connection is restablished.
            if self.curr_seqno == self.idl.change_seqno:
                app_log.debug("ovsdb unavailable retrying")
                self.connected = False
                self.timeout_handle = \
                    IOLoop.current().add_timeout(time.time() + self.timeout,
                                                 self.idl_reconnect)
            else:
                self.idl_establish_connection()
        except error.Error as e:
            # idl will raise an error exception if cannot reconnect
            app_log.debug("Failed to connect, retrying. Reason: %s" % e)
            self.timeout_handle = \
                IOLoop.current().add_timeout(time.time() + self.timeout,
                                             self.idl_reconnect)

    def idl_establish_connection(self):
        app_log.info("ovsdb connection ready")
        self.connected = True
        self.curr_seqno = self.idl.change_seqno
        self.ovs_socket = self.idl._session.rpc.stream.socket
        IOLoop.current().add_handler(self.ovs_socket.fileno(), self.idl_run,
                                     IOLoop.READ | IOLoop.ERROR)

        self.run_callbacks(ESTABLISHED_CB_TYPE)

    def idl_check_and_update(self):
        self.idl.run()

        if self.curr_seqno != self.idl.change_seqno:
            self.run_callbacks(CHANGES_CB_TYPE)

            if len(self.transactions.txn_list):
                self.check_transactions()

        self.curr_seqno = self.idl.change_seqno

    def idl_run(self, fd=None, events=None):
        if events & IOLoop.ERROR:
            app_log.debug("Socket fd %s error" % fd)
            if fd is not None:
                IOLoop.current().remove_handler(fd)
                self.idl_reconnect()
        elif events & IOLoop.READ:
            self.idl_check_and_update()

    def check_transactions(self):
        self.stop_transaction_timer()
        txn_incomplete = False

        for index, tx in enumerate(self.transactions.txn_list):
            tx.commit()
            # TODO: Handle all states
            if tx.status is not INCOMPLETE:
                self.transactions.txn_list.pop(index)
                tx.event.set()
            else:
                txn_incomplete = True

        if txn_incomplete:
            self.start_transaction_timer()

    def get_new_transaction(self):
        return OvsdbTransaction(self.idl)

    def monitor_transaction(self, txn):
        self.transactions.add_txn(txn)
        self.start_transaction_timer()

    def stop_transaction_timer(self):
        if self.txn_timeout_handle:
            IOLoop.current().remove_timeout(self.txn_timeout_handle)
            self.txn_timeout_handle = None

    def start_transaction_timer(self):
        if not self.txn_timeout_handle:
            self.txn_timeout_handle = \
                IOLoop.current().add_timeout(time.time() + self.timeout,
                                             self.check_transactions)

    def add_callback(self, cb_type, callback):
        if cb_type in self._callbacks:
            self._callbacks[cb_type].add(callback)

    def remove_callback(self, cb_type, callback):
        if cb_type in self._callbacks:
            self._callbacks[cb_type].discard(callback)

    def run_callbacks(self, cb_type):
        if cb_type in self._callbacks:
            for callback in self._callbacks[cb_type]:
                callback(self, self.idl)

            # Clear any change tracking info received for next notifications
            if cb_type == CHANGES_CB_TYPE:
                self.idl.track_clear_all()

    def register_schema_helper_columns(self, schema_helper, ext_schema):
        app_log.debug("Registering schema helper columns..")

        for table_name, table_schema in ext_schema.ovs_tables.iteritems():
            if table_name in ON_DEMAND_FETCHED_TABLES:
                schema_helper.register_columns(str(table_name),
                                               table_schema.columns,
                                               table_schema.readonly_columns)
            else:
                schema_helper.register_table(str(table_name))