Re: [ovs-dev] [PATCH v1] Monitor Database table to manage lifecycle of IDL client.

2019-01-03 Thread Ted Elhourani
Thanks for taking a look. I will send a revised patch that addresses both 
issues you 
pointed to, in particular backward compatibility with _Server-less ovsdbs.

Thanks,
Ted

On 12/27/18, 9:23 AM, "Ben Pfaff"  wrote:

On Tue, Dec 18, 2018 at 12:18:06AM +, Ted Elhourani wrote:
> The Python IDL implementation supports ovsdb cluster connections.
> This patch is a follow up to commit 31e434fc98, it adds the option of
> connecting to the leader in the Raft-based cluster. It mimics the
> exisiting C IDL support for clusters introduced in commit 1b1d2e6daa.
> 
> The server schema is first requested, then a monitor of the Database table
> in the _Server Database. __check_server_db is called to verify the
> eligibility of the server. Unlike the C IDL, if an attempt to obtain a
> monitor of the Server database fails this implementation does not proceed
> to monitor and transact with the database. The reason is connections to
> standalone databases should not be permitted when the intention is to
> connect to a valid cluster node. The change_seqno is not incremented in 
the
> case of Database table updates.
> 
> The run method of Session (jsonrpc) is modified such that the session is
> closed when a stream connection fails, if more than one remote exists.
> Otherwise the session will re-attempt to establish a stream to the same
> cluster node. Method pick_remote must be called before opening a stream
> in __connect (in Session), otherwise a force_reconnect causes the Session
> to re-attempt a connection to the same server. pick_remote is no longer
> necessary in method run of Session.
> 
> Signed-off-by: Ted Elhourani 

I'm pretty sure that this breaks backward compatibility with any
ovsdb-server not new enough to support the _Server table.  The commit
message above conflates that with whether the database is clustered.  I
think your intention is to reject non-clustered databases, but it
doesn't do that; instead, it rejects database servers too old to have a
_Server table and accepts standalone databases served up by new-enough
servers.  It's one thing to avoid connecting to standalone databases
when a cluster is expected, but this goes beyond that to drop support
for all older database servers.  I don't think that's reasonable behavior.

I noticed that the following looks wrong.  EAGAIN indicates that the
connection is not complete yet.  It should not be treated as a
connection failure (unless a timeout has occurred) even if there is more
than one remote:

> @@ -516,9 +516,9 @@ class Session(object):
>  self.reconnect.connected(ovs.timeval.msec())
>  self.rpc = Connection(self.stream)
>  self.stream = None
> -elif error != errno.EAGAIN:
> +elif (error != errno.EAGAIN or
> +  self.get_num_of_remotes() > 1):
>  self.reconnect.connect_failed(ovs.timeval.msec(), error)
> -self.pick_remote()
>  self.stream.close()
>  self.stream = None

Thanks,

Ben.


___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


Re: [ovs-dev] [PATCH v1] Monitor Database table to manage lifecycle of IDL client.

2018-12-27 Thread Ben Pfaff
On Tue, Dec 18, 2018 at 12:18:06AM +, Ted Elhourani wrote:
> The Python IDL implementation supports ovsdb cluster connections.
> This patch is a follow up to commit 31e434fc98, it adds the option of
> connecting to the leader in the Raft-based cluster. It mimics the
> exisiting C IDL support for clusters introduced in commit 1b1d2e6daa.
> 
> The server schema is first requested, then a monitor of the Database table
> in the _Server Database. __check_server_db is called to verify the
> eligibility of the server. Unlike the C IDL, if an attempt to obtain a
> monitor of the Server database fails this implementation does not proceed
> to monitor and transact with the database. The reason is connections to
> standalone databases should not be permitted when the intention is to
> connect to a valid cluster node. The change_seqno is not incremented in the
> case of Database table updates.
> 
> The run method of Session (jsonrpc) is modified such that the session is
> closed when a stream connection fails, if more than one remote exists.
> Otherwise the session will re-attempt to establish a stream to the same
> cluster node. Method pick_remote must be called before opening a stream
> in __connect (in Session), otherwise a force_reconnect causes the Session
> to re-attempt a connection to the same server. pick_remote is no longer
> necessary in method run of Session.
> 
> Signed-off-by: Ted Elhourani 

I'm pretty sure that this breaks backward compatibility with any
ovsdb-server not new enough to support the _Server table.  The commit
message above conflates that with whether the database is clustered.  I
think your intention is to reject non-clustered databases, but it
doesn't do that; instead, it rejects database servers too old to have a
_Server table and accepts standalone databases served up by new-enough
servers.  It's one thing to avoid connecting to standalone databases
when a cluster is expected, but this goes beyond that to drop support
for all older database servers.  I don't think that's reasonable behavior.

I noticed that the following looks wrong.  EAGAIN indicates that the
connection is not complete yet.  It should not be treated as a
connection failure (unless a timeout has occurred) even if there is more
than one remote:

> @@ -516,9 +516,9 @@ class Session(object):
>  self.reconnect.connected(ovs.timeval.msec())
>  self.rpc = Connection(self.stream)
>  self.stream = None
> -elif error != errno.EAGAIN:
> +elif (error != errno.EAGAIN or
> +  self.get_num_of_remotes() > 1):
>  self.reconnect.connect_failed(ovs.timeval.msec(), error)
> -self.pick_remote()
>  self.stream.close()
>  self.stream = None

Thanks,

Ben.
___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


[ovs-dev] [PATCH v1] Monitor Database table to manage lifecycle of IDL client.

2018-12-18 Thread Ted Elhourani
The Python IDL implementation supports ovsdb cluster connections.
This patch is a follow up to commit 31e434fc98, it adds the option of
connecting to the leader in the Raft-based cluster. It mimics the
exisiting C IDL support for clusters introduced in commit 1b1d2e6daa.

The server schema is first requested, then a monitor of the Database table
in the _Server Database. __check_server_db is called to verify the
eligibility of the server. Unlike the C IDL, if an attempt to obtain a
monitor of the Server database fails this implementation does not proceed
to monitor and transact with the database. The reason is connections to
standalone databases should not be permitted when the intention is to
connect to a valid cluster node. The change_seqno is not incremented in the
case of Database table updates.

The run method of Session (jsonrpc) is modified such that the session is
closed when a stream connection fails, if more than one remote exists.
Otherwise the session will re-attempt to establish a stream to the same
cluster node. Method pick_remote must be called before opening a stream
in __connect (in Session), otherwise a force_reconnect causes the Session
to re-attempt a connection to the same server. pick_remote is no longer
necessary in method run of Session.

Signed-off-by: Ted Elhourani 
---
 python/ovs/db/idl.py| 189 
 python/ovs/jsonrpc.py   |  10 +--
 python/ovs/reconnect.py |   3 +
 tests/ovsdb-idl.at  |  62 
 4 files changed, 214 insertions(+), 50 deletions(-)

diff --git a/python/ovs/db/idl.py b/python/ovs/db/idl.py
index 250e897..f5edf5e 100644
--- a/python/ovs/db/idl.py
+++ b/python/ovs/db/idl.py
@@ -38,6 +38,7 @@ ROW_DELETE = "delete"
 OVSDB_UPDATE = 0
 OVSDB_UPDATE2 = 1
 
+CLUSTERED = "clustered"
 
 class Idl(object):
 """Open vSwitch Database Interface Definition Language (OVSDB IDL).
@@ -92,10 +93,12 @@ class Idl(object):
 """
 
 IDL_S_INITIAL = 0
-IDL_S_MONITOR_REQUESTED = 1
-IDL_S_MONITOR_COND_REQUESTED = 2
+IDL_S_SERVER_SCHEMA_REQUESTED = 1
+IDL_S_SERVER_MONITOR_REQUESTED = 2
+IDL_S_DATA_MONITOR_REQUESTED = 3
+IDL_S_DATA_MONITOR_COND_REQUESTED = 4
 
-def __init__(self, remote, schema_helper, probe_interval=None):
+def __init__(self, remote, schema_helper, leader_only=True, 
probe_interval=None):
 """Creates and returns a connection to the database named 'db_name' on
 'remote', which should be in a form acceptable to
 ovs.jsonrpc.session.open().  The connection will maintain an in-memory
@@ -119,6 +122,9 @@ class Idl(object):
 
 The IDL uses and modifies 'schema' directly.
 
+If 'leader_only' is set to True (default value) the IDL will only 
monitor
+and transact with the leader of the cluster.
+
 If "probe_interval" is zero it disables the connection keepalive
 feature. If non-zero the value will be forced to at least 1000
 milliseconds. If None it will just use the default value in OVS.
@@ -137,6 +143,20 @@ class Idl(object):
 self._last_seqno = None
 self.change_seqno = 0
 self.uuid = uuid.uuid1()
+
+# Server monitor.
+self._server_schema_request_id = None
+self._server_monitor_request_id = None
+self._db_change_aware_request_id = None
+self._server_db_name = '_Server'
+self._server_db_table = 'Database'
+self.server_tables = None
+self._server_db = None
+self.server_monitor_uuid = uuid.uuid1()
+self.leader_only = leader_only
+self.cluster_id = None
+self._min_index = 0
+
 self.state = self.IDL_S_INITIAL
 
 # Database locking.
@@ -172,6 +192,10 @@ class Idl(object):
 remotes.append(r)
 return remotes
 
+def set_cluster_id(self, cluster_id):
+"""Set the id of the cluster that this idl must connect to."""
+self.cluster_id = str(cluster_id)
+
 def index_create(self, table, name):
 """Create a named multi-column index on a table"""
 return self.tables[table].rows.index_create(name)
@@ -222,7 +246,7 @@ class Idl(object):
 if seqno != self._last_seqno:
 self._last_seqno = seqno
 self.__txn_abort_all()
-self.__send_monitor_request()
+self.__send_server_schema_request()
 if self.lock_name:
 self.__send_lock_request()
 break
@@ -239,7 +263,14 @@ class Idl(object):
 and msg.method == "update"
 and len(msg.params) == 2):
 # Database contents changed.
-self.__parse_update(msg.params[1], OVSDB_UPDATE)
+if msg.params[0] == str(self.server_monitor_uuid):
+self.__parse_update(msg.params[1], OVSDB_UPDATE, 
tables=self.server_tables)
+self.change_seqno = initial_change_seqno
+