Hello community,

here is the log from the commit of package python-ovsdbapp for openSUSE:Factory 
checked in at 2020-02-18 10:41:55
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-ovsdbapp (Old)
 and      /work/SRC/openSUSE:Factory/.python-ovsdbapp.new.26092 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-ovsdbapp"

Tue Feb 18 10:41:55 2020 rev:4 rq:774926 version:0.17.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-ovsdbapp/python-ovsdbapp.changes  
2019-05-03 22:43:06.799328217 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-ovsdbapp.new.26092/python-ovsdbapp.changes   
    2020-02-18 10:42:19.521179545 +0100
@@ -1,0 +2,31 @@
+Wed Oct  9 12:47:14 UTC 2019 - [email protected]
+
+- update to version 0.17.0
+  - modify RowEvent hash key
+  - Mock Thread for both connection tests
+  - Add missing tox environment "functional-py36"
+  - TrivialFix: Fix the chassis_del comment in Southbound API
+  - Add mock.patch.stopall cleanup handler to base test class
+  - Make Event logging more useful by default
+  - Make event debug log more useful
+  - Switch functional and tempest jobs to python3
+  - Allow match_ip in LrNatDelCommand to be IP network
+  - Add db_create_row method
+  - Break out match_fn from matches
+  - Sync Sphinx requirement
+  - Remove vtep-related code from venv testing
+  - Add Python 3 Train unit tests
+  - OpenDev Migration Patch
+  - Make it possible to opt out of nested transactions
+  - Add HA Chassis Group related commands
+  - Add commands to set and get LRP options
+  - Pass kwargs from execute to transaction()
+  - Replace openstack repository by opendev
+  - Bump appdirs lower constraint
+  - Update the UPPER_CONSTRAINTS_FILE for tox
+  - Update master for stable/stein
+  - Move WaitForPortBindingEvent out from testing code
+  - add an option to let the user choose the right time to start connection
+  - Change the order of parameters for lsp_bind method
+
+-------------------------------------------------------------------

Old:
----
  ovsdbapp-0.15.0.tar.gz

New:
----
  ovsdbapp-0.17.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-ovsdbapp.spec ++++++
--- /var/tmp/diff_new_pack.MhOE0O/_old  2020-02-18 10:42:20.413181365 +0100
+++ /var/tmp/diff_new_pack.MhOE0O/_new  2020-02-18 10:42:20.417181373 +0100
@@ -18,13 +18,13 @@
 
 %define with_tests 0
 Name:           python-ovsdbapp
-Version:        0.15.0
+Version:        0.17.0
 Release:        0
 Summary:        A library for creating OVSDB applications
 License:        Apache-2.0
 Group:          Development/Languages/Python
 URL:            https://launchpad.net/ovsdbapp
-Source0:        
https://files.pythonhosted.org/packages/source/o/ovsdbapp/ovsdbapp-0.15.0.tar.gz
+Source0:        
https://files.pythonhosted.org/packages/source/o/ovsdbapp/ovsdbapp-0.17.0.tar.gz
 BuildRequires:  openstack-macros
 BuildRequires:  python2-fixtures >= 3.0.0
 BuildRequires:  python2-oslotest
@@ -70,7 +70,7 @@
 %{python_build}
 
 # generate html docs
-PBR_VERSION=0.15.0 PYTHONPATH=. \
+PBR_VERSION=0.17.0 PYTHONPATH=. \
     sphinx-build -b html doc/source doc/build/html
 rm -rf doc/build/html/.{doctrees,buildinfo}
 

++++++ _service ++++++
--- /var/tmp/diff_new_pack.MhOE0O/_old  2020-02-18 10:42:20.445181430 +0100
+++ /var/tmp/diff_new_pack.MhOE0O/_new  2020-02-18 10:42:20.449181438 +0100
@@ -1,8 +1,8 @@
 <services>
   <service mode="disabled" name="renderspec">
-    <param 
name="input-template">https://raw.githubusercontent.com/openstack/rpm-packaging/stable/stein/openstack/ovsdbapp/ovsdbapp.spec.j2</param>
+    <param 
name="input-template">https://raw.githubusercontent.com/openstack/rpm-packaging/stable/train/openstack/ovsdbapp/ovsdbapp.spec.j2</param>
     <param name="output-name">python-ovsdbapp.spec</param>
-    <param 
name="requirements">https://raw.githubusercontent.com/openstack/ovsdbapp/stable/stein/requirements.txt</param>
+    <param 
name="requirements">https://raw.githubusercontent.com/openstack/ovsdbapp/stable/train/requirements.txt</param>
     <param name="changelog-email">[email protected]</param>
     <param name="changelog-provider">gh,openstack,ovsdbapp</param>
   </service>

++++++ ovsdbapp-0.15.0.tar.gz -> ovsdbapp-0.17.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ovsdbapp-0.15.0/AUTHORS new/ovsdbapp-0.17.0/AUTHORS
--- old/ovsdbapp-0.15.0/AUTHORS 2019-01-30 17:05:56.000000000 +0100
+++ new/ovsdbapp-0.17.0/AUTHORS 2019-08-29 11:53:59.000000000 +0200
@@ -1,4 +1,5 @@
 Aaron Rosen <[email protected]>
+Abhiram Sangana <[email protected]>
 Adelina Tuvenie <[email protected]>
 Akihiro Motoki <[email protected]>
 Akihiro Motoki <[email protected]>
@@ -10,6 +11,7 @@
 Bo Wang <[email protected]>
 Boden R <[email protected]>
 Chuck Short <[email protected]>
+Corey Bryant <[email protected]>
 Cyril Roelandt <[email protected]>
 Daniel Alvarez <[email protected]>
 Davanum Srinivas <[email protected]>
@@ -17,6 +19,7 @@
 Doug Hellmann <[email protected]>
 Doug Wiegley <[email protected]>
 Emma Foley <[email protected]>
+Frank Wang <[email protected]>
 Gal Sagie <[email protected]>
 Gary Kotton <[email protected]>
 Guoshuai Li <[email protected]>
@@ -34,11 +37,13 @@
 Marcin Mirecki <[email protected]>
 Martin Hickey <[email protected]>
 Miguel Duarte Barroso <[email protected]>
+Nate Johnston <[email protected]>
 Numan Siddique <[email protected]>
 Omer Anson <[email protected]>
 OpenStack Release Bot <[email protected]>
 Petr Horáček <[email protected]>
 Richard Theis <[email protected]>
+Rodolfo Alonso Hernandez <[email protected]>
 Sean Mooney <[email protected]>
 Ted Elhourani <[email protected]>
 Terry Wilson <[email protected]>
@@ -47,13 +52,17 @@
 YAMAMOTO Takashi <[email protected]>
 Yalei Wang <[email protected]>
 Yi Zhao <[email protected]>
+Yunxiang Tao <[email protected]>
+caoyuan <[email protected]>
 chenxing <[email protected]>
 gengchc2 <[email protected]>
 hgangwx <[email protected]>
 huang.zhiping <[email protected]>
+ljhuang <[email protected]>
 lzklibj <[email protected]>
 melissaml <[email protected]>
 qingszhao <[email protected]>
+reedip <[email protected]>
 rossella <[email protected]>
 yan.haifeng <[email protected]>
 zhangzs <[email protected]>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ovsdbapp-0.15.0/CONTRIBUTING.rst 
new/ovsdbapp-0.17.0/CONTRIBUTING.rst
--- old/ovsdbapp-0.15.0/CONTRIBUTING.rst        2019-01-30 17:05:07.000000000 
+0100
+++ new/ovsdbapp-0.17.0/CONTRIBUTING.rst        2019-08-29 11:53:03.000000000 
+0200
@@ -1,14 +1,14 @@
 If you would like to contribute to the development of OpenStack, you must
 follow the steps in this page:
 
-   http://docs.openstack.org/infra/manual/developers.html
+   https://docs.openstack.org/infra/manual/developers.html
 
 If you already have a good understanding of how the system works and your
 OpenStack accounts are set up, you can skip to the development workflow
 section of this documentation to learn how changes to OpenStack should be
 submitted for review via the Gerrit tool:
 
-   http://docs.openstack.org/infra/manual/developers.html#development-workflow
+   https://docs.openstack.org/infra/manual/developers.html#development-workflow
 
 Pull requests submitted through GitHub will be ignored.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ovsdbapp-0.15.0/ChangeLog 
new/ovsdbapp-0.17.0/ChangeLog
--- old/ovsdbapp-0.15.0/ChangeLog       2019-01-30 17:05:56.000000000 +0100
+++ new/ovsdbapp-0.17.0/ChangeLog       2019-08-29 11:53:59.000000000 +0200
@@ -1,6 +1,40 @@
 CHANGES
 =======
 
+0.17.0
+------
+
+* Add HA Chassis Group related commands
+* Add commands to set and get LRP options
+* Add Python 3 Train unit tests
+* Sync Sphinx requirement
+* Update the UPPER\_CONSTRAINTS\_FILE for tox
+
+0.16.0
+------
+
+* Replace openstack repository by opendev
+* Move WaitForPortBindingEvent out from testing code
+* Make Event logging more useful by default
+* TrivialFix: Fix the chassis\_del comment in Southbound API
+* Change the order of parameters for lsp\_bind method
+* Allow match\_ip in LrNatDelCommand to be IP network
+* Add missing tox environment "functional-py36"
+* OpenDev Migration Patch
+* add an option to let the user choose the right time to start connection
+* Make it possible to opt out of nested transactions
+* Update master for stable/stein
+* Add db\_create\_row method
+* Add mock.patch.stopall cleanup handler to base test class
+* Mock Thread for both connection tests
+* Remove vtep-related code from venv testing
+* modify RowEvent hash key
+* Make event debug log more useful
+* Pass kwargs from execute to transaction()
+* Switch functional and tempest jobs to python3
+* Bump appdirs lower constraint
+* Break out match\_fn from matches
+
 0.15.0
 ------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ovsdbapp-0.15.0/PKG-INFO new/ovsdbapp-0.17.0/PKG-INFO
--- old/ovsdbapp-0.15.0/PKG-INFO        2019-01-30 17:05:56.000000000 +0100
+++ new/ovsdbapp-0.17.0/PKG-INFO        2019-08-29 11:53:59.000000000 +0200
@@ -1,14 +1,14 @@
 Metadata-Version: 1.1
 Name: ovsdbapp
-Version: 0.15.0
+Version: 0.17.0
 Summary: A library for creating OVSDB applications
 Home-page: https://pypi.org/project/ovsdbapp/
 Author: OpenStack
 Author-email: [email protected]
 License: UNKNOWN
-Description: ===============================
+Description: ========
         ovsdbapp
-        ===============================
+        ========
         
         A library for creating OVSDB applications
         
@@ -17,7 +17,7 @@
         wraps the Python 'ovs' and adds an event loop and friendly 
transactions.
         
         * Free software: Apache license
-        * Source: http://git.openstack.org/cgit/openstack/ovsdbapp
+        * Source: https://opendev.org/openstack/ovsdbapp/
         * Bugs: http://bugs.launchpad.net/ovsdbapp
         
         Features
@@ -38,5 +38,5 @@
 Classifier: Programming Language :: Python :: 2
 Classifier: Programming Language :: Python :: 2.7
 Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.3
-Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ovsdbapp-0.15.0/README.rst 
new/ovsdbapp-0.17.0/README.rst
--- old/ovsdbapp-0.15.0/README.rst      2019-01-30 17:05:07.000000000 +0100
+++ new/ovsdbapp-0.17.0/README.rst      2019-08-29 11:53:03.000000000 +0200
@@ -1,6 +1,6 @@
-===============================
+========
 ovsdbapp
-===============================
+========
 
 A library for creating OVSDB applications
 
@@ -9,7 +9,7 @@
 wraps the Python 'ovs' and adds an event loop and friendly transactions.
 
 * Free software: Apache license
-* Source: http://git.openstack.org/cgit/openstack/ovsdbapp
+* Source: https://opendev.org/openstack/ovsdbapp/
 * Bugs: http://bugs.launchpad.net/ovsdbapp
 
 Features
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ovsdbapp-0.15.0/doc/source/user/index.rst 
new/ovsdbapp-0.17.0/doc/source/user/index.rst
--- old/ovsdbapp-0.15.0/doc/source/user/index.rst       2019-01-30 
17:05:07.000000000 +0100
+++ new/ovsdbapp-0.17.0/doc/source/user/index.rst       2019-08-29 
11:53:03.000000000 +0200
@@ -1,6 +1,6 @@
-========
+=====
 Usage
-========
+=====
 
 To use ovsdbapp in a project::
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ovsdbapp-0.15.0/lower-constraints.txt 
new/ovsdbapp-0.17.0/lower-constraints.txt
--- old/ovsdbapp-0.15.0/lower-constraints.txt   2019-01-30 17:05:07.000000000 
+0100
+++ new/ovsdbapp-0.17.0/lower-constraints.txt   2019-08-29 11:53:03.000000000 
+0200
@@ -1,5 +1,5 @@
 alabaster==0.7.10
-appdirs==1.3.0
+appdirs==1.4.3
 astroid==1.3.8
 Babel==2.3.4
 coverage==4.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ovsdbapp-0.15.0/ovsdbapp/api.py 
new/ovsdbapp-0.17.0/ovsdbapp/api.py
--- old/ovsdbapp-0.15.0/ovsdbapp/api.py 2019-01-30 17:05:07.000000000 +0100
+++ new/ovsdbapp-0.17.0/ovsdbapp/api.py 2019-08-29 11:53:03.000000000 +0200
@@ -71,8 +71,9 @@
 
 @six.add_metaclass(abc.ABCMeta)
 class API(object):
-    def __init__(self):
+    def __init__(self, nested_transactions=True):
         # Mapping between a (green)thread and its transaction.
+        self._nested_txns = nested_transactions
         self._nested_txns_map = {}
 
     @abc.abstractmethod
@@ -88,17 +89,23 @@
         """
 
     @contextlib.contextmanager
-    def transaction(self, check_error=False, log_errors=True, **kwargs):
+    def transaction(self, check_error=False, log_errors=True, nested=True,
+                    **kwargs):
         """Create a transaction context.
 
         :param check_error: Allow the transaction to raise an exception?
         :type check_error:  bool
         :param log_errors:  Log an error if the transaction fails?
         :type log_errors:   bool
+        :param nested:      Allow nested transactions be merged into one txn
+        :type nested:       bool
         :returns: Either a new transaction or an existing one.
         :rtype: :class:`Transaction`
         """
-        cur_thread_id = thread.get_ident()
+        # ojbect() is unique, so if we are not nested, this will always result
+        # in a KeyError on lookup and so a unique Transaction
+        nested = nested and self._nested_txns
+        cur_thread_id = thread.get_ident() if nested else object()
 
         try:
             yield self._nested_txns_map[cur_thread_id]
@@ -120,9 +127,18 @@
         :param col_values: The columns and their associated values
                            to be set after create
         :type col_values:  Dictionary of columns id's and values
-        :returns:          :class:`Command` with no result
+        :returns:          :class:`Command` with uuid result
         """
 
+    def db_create_row(self, table, **col_values):
+        """Create a command to create new record
+
+        Identical to db_create, but returns a RowView result
+        :returns: :class:`Command` with RowView result
+        """
+        # vif_plug_ovs has a copy of impl_vsctl that doesn't implement this
+        raise NotImplementedError
+
     @abc.abstractmethod
     def db_destroy(self, table, record):
         """Create a command to destroy a record
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ovsdbapp-0.15.0/ovsdbapp/backend/ovs_idl/__init__.py 
new/ovsdbapp-0.17.0/ovsdbapp/backend/ovs_idl/__init__.py
--- old/ovsdbapp-0.15.0/ovsdbapp/backend/ovs_idl/__init__.py    2019-01-30 
17:05:07.000000000 +0100
+++ new/ovsdbapp-0.17.0/ovsdbapp/backend/ovs_idl/__init__.py    2019-08-29 
11:53:03.000000000 +0200
@@ -26,9 +26,10 @@
     lookup_table = {}
     ovsdb_connection = None
 
-    def __init__(self, connection):
-        super(Backend, self).__init__()
-        self.start_connection(connection)
+    def __init__(self, connection, start=True, **kwargs):
+        super(Backend, self).__init__(**kwargs)
+        if start:
+            self.start_connection(connection)
 
     @classmethod
     def start_connection(cls, connection):
@@ -66,6 +67,9 @@
     def db_create(self, table, **col_values):
         return cmd.DbCreateCommand(self, table, **col_values)
 
+    def db_create_row(self, table, **col_values):
+        return cmd.DbCreateCommand(self, table, _as_row=True, **col_values)
+
     def db_destroy(self, table, record):
         return cmd.DbDestroyCommand(self, table, record)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ovsdbapp-0.15.0/ovsdbapp/backend/ovs_idl/command.py 
new/ovsdbapp-0.17.0/ovsdbapp/backend/ovs_idl/command.py
--- old/ovsdbapp-0.15.0/ovsdbapp/backend/ovs_idl/command.py     2019-01-30 
17:05:07.000000000 +0100
+++ new/ovsdbapp-0.17.0/ovsdbapp/backend/ovs_idl/command.py     2019-08-29 
11:53:03.000000000 +0200
@@ -31,13 +31,13 @@
         self.api = api
         self.result = None
 
-    def execute(self, check_error=False, log_errors=True):
+    def execute(self, check_error=False, log_errors=True, **kwargs):
         try:
             if self.READ_ONLY:
                 self.run_idl(None)
                 return self.result
-            with self.api.transaction(check_error, log_errors) as txn:
-                txn.add(self)
+            with self.api.transaction(check_error, log_errors, **kwargs) as t:
+                t.add(self)
             return self.result
         except Exception:
             if log_errors:
@@ -81,10 +81,11 @@
 
 
 class DbCreateCommand(BaseCommand):
-    def __init__(self, api, table, **columns):
+    def __init__(self, api, table, _as_row=False, **columns):
         super(DbCreateCommand, self).__init__(api)
         self.table = table
         self.columns = columns
+        self.row = _as_row
 
     def run_idl(self, txn):
         row = txn.insert(self.api._tables[self.table])
@@ -94,7 +95,11 @@
 
     def post_commit(self, txn):
         # Replace the temporary row with the post-commit UUID to match vsctl
-        self.result = txn.get_insert_uuid(self.result.uuid)
+        u = txn.get_insert_uuid(self.result.uuid)
+        if self.row:
+            self.result = rowview.RowView(self.api.tables[self.table].rows[u])
+        else:
+            self.result = u
 
 
 class DbDestroyCommand(BaseCommand):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ovsdbapp-0.15.0/ovsdbapp/backend/ovs_idl/event.py 
new/ovsdbapp-0.17.0/ovsdbapp/backend/ovs_idl/event.py
--- old/ovsdbapp-0.15.0/ovsdbapp/backend/ovs_idl/event.py       2019-01-30 
17:05:07.000000000 +0100
+++ new/ovsdbapp-0.17.0/ovsdbapp/backend/ovs_idl/event.py       2019-08-29 
11:53:03.000000000 +0200
@@ -19,11 +19,7 @@
 
 
 class RowEvent(ovsdb_event.RowEvent):  # pylint: disable=abstract-method
-    def matches(self, event, row, old=None):
-        if event not in self.events:
-            return False
-        if row._table.name != self.table:
-            return False
+    def match_fn(self, event, row, old):
         if self.conditions and not idlutils.row_match(row, self.conditions):
             return False
         if self.old_conditions:
@@ -35,9 +31,17 @@
             except (KeyError, AttributeError):
                 # Its possible that old row may not have all columns in it
                 return False
+        return True
 
-        LOG.debug("%s : Matched %s, %s, %s %s", self.event_name, self.table,
-                  self.events, self.conditions, self.old_conditions)
+    def matches(self, event, row, old=None):
+        if event not in self.events:
+            return False
+        if row._table.name != self.table:
+            return False
+        if not self.match_fn(event, row, old):
+            return False
+        LOG.debug("Matched %s: %r to row=%s old=%s", event.upper(), self,
+                  idlutils.row2str(row), idlutils.row2str(old) if old else '')
         return True
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ovsdbapp-0.15.0/ovsdbapp/backend/ovs_idl/idlutils.py 
new/ovsdbapp-0.17.0/ovsdbapp/backend/ovs_idl/idlutils.py
--- old/ovsdbapp-0.15.0/ovsdbapp/backend/ovs_idl/idlutils.py    2019-01-30 
17:05:07.000000000 +0100
+++ new/ovsdbapp-0.17.0/ovsdbapp/backend/ovs_idl/idlutils.py    2019-08-29 
11:53:03.000000000 +0200
@@ -310,3 +310,14 @@
     elif isinstance(obj, api.Command):
         obj = obj.result
     return obj
+
+
+def row2str(row):
+    """Get a string representation of a Row"""
+
+    # This is not a repr, as the Row object takes a dict of Datum objects and
+    # we don't really want to deal with those, just what the Python values are.
+    # Row foreign keys are printed as their UUID
+    return "%s(%s)" % (row._table.name, ", ".join(
+        "%s=%s" % (col, idl._row_to_uuid(getattr(row, col)))
+        for col in row._table.columns if hasattr(row, col)))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ovsdbapp-0.15.0/ovsdbapp/event.py 
new/ovsdbapp-0.17.0/ovsdbapp/event.py
--- old/ovsdbapp-0.15.0/ovsdbapp/event.py       2019-01-30 17:05:07.000000000 
+0100
+++ new/ovsdbapp-0.17.0/ovsdbapp/event.py       2019-08-29 11:53:03.000000000 
+0200
@@ -38,20 +38,26 @@
 
     @property
     def key(self):
-        return (self.__class__, self.table, self.events, self.conditions)
+        return (self.__class__, self.table, tuple(self.events))
 
     def __hash__(self):
         return hash(self.key)
 
     def __eq__(self, other):
         try:
-            return self.key == other.key
+            return (self.key == other.key and
+                    self.conditions == other.conditions)
         except AttributeError:
             return False
 
     def __ne__(self, other):
         return not self == other
 
+    def __repr__(self):
+        return "%s(events=%r, table=%r, conditions=%r, old_conditions=%r)" % (
+            self.__class__.__name__, self.events, self.table, self.conditions,
+            self.old_conditions)
+
     @abc.abstractmethod
     def matches(self, event, row, old=None):
         """Test that `event` on `row` matches watched events
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ovsdbapp-0.15.0/ovsdbapp/schema/ovn_northbound/api.py 
new/ovsdbapp-0.17.0/ovsdbapp/schema/ovn_northbound/api.py
--- old/ovsdbapp-0.15.0/ovsdbapp/schema/ovn_northbound/api.py   2019-01-30 
17:05:07.000000000 +0100
+++ new/ovsdbapp-0.17.0/ovsdbapp/schema/ovn_northbound/api.py   2019-08-29 
11:53:03.000000000 +0200
@@ -543,6 +543,26 @@
         """
 
     @abc.abstractmethod
+    def lrp_set_options(self, port, **options):
+        """Set options related to the type of 'port'
+
+        :param port:    The name or uuid of the port
+        :type port:     string or uuid.UUID
+        :param options: keys and values for the port 'options' dict
+        :type options:  key: string, value: string
+        :returns:       :class:`Command` with no result
+        """
+
+    @abc.abstractmethod
+    def lrp_get_options(self, port):
+        """Get the type-specific options for 'port'
+
+        :param port: The name or uuid of the port
+        :type port:  string or uuid.UUID
+        :returns:    :class:`Command` with dict result
+        """
+
+    @abc.abstractmethod
     def lr_route_add(self, router, prefix, nexthop, port=None,
                      policy='dst-ip', may_exist=False):
         """Add a route to 'router'
@@ -948,3 +968,70 @@
         :type pg_id:  string or uuid.UUID
         :returns:     :class:`Command` with RowView result
         """
+
+    @abc.abstractmethod
+    def ha_chassis_group_add(self, name, may_exist=False, **columns):
+        """Create a HA Chassis Group
+
+        :param name:        The name of the ha chassis group
+        :type name:         string
+        :param may_exist:   If True, don't fail if the ha chassis group
+                            already exists
+        :type may_exist:    bool
+        :param columns:     Additional columns to directly set on the ha
+                            chassis group (e.g external_ids)
+        :type columns:      dictionary
+        :returns:           :class:`Command` with RowView result
+        """
+
+    @abc.abstractmethod
+    def ha_chassis_group_del(self, name, if_exists=False):
+        """Delete a HA Chassis Group
+
+        :param name:        The name of the ha chassis group
+        :type name:         string
+        :param if_exists:   If True, don't fail if the ha chassis group
+                            doesn't exist
+        :type if_exists:    boolean
+        :returns:           :class:`Command` with no result
+        """
+
+    @abc.abstractmethod
+    def ha_chassis_group_get(self, name):
+        """Get HA Chassis Group
+
+        :param name: The name or uuid of the ha chassis group
+        :type name:  string or uuid.UUID
+        :returns:    :class:`Command` with RowView result
+        """
+
+    @abc.abstractmethod
+    def ha_chassis_group_add_chassis(self, hcg_id, chassis, priority,
+                                     **columns):
+        """Add a HA Chassis to a HA Chassis Group
+
+        :param hcg_id:   The name or uuid of the ha chassis group
+        :type hcg_id:    string or uuid.UUID
+        :param chassis:  The name of the ha chassis
+        :type chassis:   string
+        :param priority: The priority of the ha chassis
+        :type priority:  int
+        :param columns:  Additional columns to directly set on the ha
+                         chassis (e.g external_ids)
+        :type columns:   dictionary
+        :returns:        :class:`Command` with RowView result
+        """
+
+    @abc.abstractmethod
+    def ha_chassis_group_del_chassis(self, hcg_id, chassis, if_exists=False):
+        """Delete a HA Chassis from a HA Chassis Group
+
+        :param hcg_id:     The name or uuid of the ha chassis group
+        :type hcg_id:      string or uuid.UUID
+        :param chassis:    The name of the ha chassis
+        :type chassis:     string
+        :param if_exists:  If True, don't fail if the ha chassis
+                           doesn't exist
+        :type if_exists:   boolean
+        :returns:          :class:`Command` with no result
+        """
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ovsdbapp-0.15.0/ovsdbapp/schema/ovn_northbound/commands.py 
new/ovsdbapp-0.17.0/ovsdbapp/schema/ovn_northbound/commands.py
--- old/ovsdbapp-0.15.0/ovsdbapp/schema/ovn_northbound/commands.py      
2019-01-30 17:05:07.000000000 +0100
+++ new/ovsdbapp-0.17.0/ovsdbapp/schema/ovn_northbound/commands.py      
2019-08-29 11:53:03.000000000 +0200
@@ -542,23 +542,27 @@
 
 
 class LspSetOptionsCommand(cmd.BaseCommand):
+    table = 'Logical_Switch_Port'
+
     def __init__(self, api, port, **options):
         super(LspSetOptionsCommand, self).__init__(api)
         self.port = port
         self.options = options
 
     def run_idl(self, txn):
-        lsp = self.api.lookup('Logical_Switch_Port', self.port)
+        lsp = self.api.lookup(self.table, self.port)
         lsp.options = self.options
 
 
 class LspGetOptionsCommand(cmd.ReadOnlyCommand):
+    table = 'Logical_Switch_Port'
+
     def __init__(self, api, port):
         super(LspGetOptionsCommand, self).__init__(api)
         self.port = port
 
     def run_idl(self, txn):
-        lsp = self.api.lookup('Logical_Switch_Port', self.port)
+        lsp = self.api.lookup(self.table, self.port)
         self.result = lsp.options
 
 
@@ -795,6 +799,14 @@
         self.result = next(iter(lrp.enabled), True)
 
 
+class LrpSetOptionsCommand(LspSetOptionsCommand):
+    table = 'Logical_Router_Port'
+
+
+class LrpGetOptionsCommand(LspGetOptionsCommand):
+    table = 'Logical_Router_Port'
+
+
 class LrRouteAddCommand(cmd.BaseCommand):
     def __init__(self, api, router, prefix, nexthop, port=None,
                  policy='dst-ip', may_exist=False):
@@ -948,7 +960,14 @@
                 raise TypeError("nat_type not in %s" % str(const.NAT_TYPES))
             self.conditions += [('type', '=', nat_type)]
             if match_ip:
-                match_ip = str(netaddr.IPAddress(match_ip))
+                try:
+                    match_ip = str(netaddr.IPAddress(match_ip))
+                except ValueError:
+                    # logical_ip can be IPNetwork
+                    if nat_type == const.NAT_SNAT:
+                        match_ip = str(netaddr.IPNetwork(match_ip))
+                    else:
+                        raise
                 self.col = ('logical_ip' if nat_type == const.NAT_SNAT
                             else 'external_ip')
                 self.conditions += [(self.col, '=', match_ip)]
@@ -1325,3 +1344,111 @@
         gwc.priority = self.priority
         self.set_columns(gwc, **self.columns)
         self.result = gwc
+
+
+class HAChassisGroupAddCommand(cmd.AddCommand):
+    table_name = 'HA_Chassis_Group'
+
+    def __init__(self, api, name, may_exist=False, **columns):
+        super(HAChassisGroupAddCommand, self).__init__(api)
+        self.name = name
+        self.may_exist = may_exist
+        self.columns = columns
+
+    def run_idl(self, txn):
+        if self.may_exist:
+            try:
+                hcg = self.api.lookup(self.table_name, self.name)
+                self.result = rowview.RowView(hcg)
+                return
+            except idlutils.RowNotFound:
+                pass
+
+        hcg = txn.insert(self.api._tables[self.table_name])
+        hcg.name = self.name
+        self.set_columns(hcg, **self.columns)
+        self.result = hcg.uuid
+
+
+class HAChassisGroupDelCommand(cmd.BaseCommand):
+    table_name = 'HA_Chassis_Group'
+
+    def __init__(self, api, name, if_exists=False):
+        super(HAChassisGroupDelCommand, self).__init__(api)
+        self.name = name
+        self.if_exists = if_exists
+
+    def run_idl(self, txn):
+        try:
+            hcg = self.api.lookup(self.table_name, self.name)
+            hcg.delete()
+        except idlutils.RowNotFound:
+            if self.if_exists:
+                return
+            raise RuntimeError(
+                'HA Chassis Group %s does not exist' % self.name)
+
+
+class HAChassisGroupGetCommand(cmd.BaseGetRowCommand):
+    table = 'HA_Chassis_Group'
+
+
+class HAChassisGroupAddChassisCommand(cmd.AddCommand):
+    table_name = 'HA_Chassis'
+
+    def __init__(self, api, hcg_id, chassis, priority, **columns):
+        super(HAChassisGroupAddChassisCommand, self).__init__(api)
+        self.hcg_id = hcg_id
+        self.chassis = chassis
+        self.priority = priority
+        self.columns = columns
+
+    def run_idl(self, txn):
+        hc_group = self.api.lookup('HA_Chassis_Group', self.hcg_id)
+        found = False
+        hc = None
+        for hc in hc_group.ha_chassis:
+            if hc.chassis_name != self.chassis:
+                continue
+            found = True
+            break
+        else:
+            hc = txn.insert(self.api.tables[self.table_name])
+            hc.chassis_name = self.chassis
+
+        hc.priority = self.priority
+        self.set_columns(hc, **self.columns)
+        if not found:
+            hc_group.addvalue('ha_chassis', hc)
+
+        self.result = hc.uuid
+
+
+class HAChassisGroupDelChassisCommand(cmd.BaseCommand):
+    table_name = 'HA_Chassis'
+
+    def __init__(self, api, hcg_id, chassis, if_exists=False):
+        super(HAChassisGroupDelChassisCommand, self).__init__(api)
+        self.hcg_id = hcg_id
+        self.chassis = chassis
+        self.if_exists = if_exists
+
+    def run_idl(self, txn):
+        try:
+            hc_group = self.api.lookup('HA_Chassis_Group', self.hcg_id)
+        except idlutils.RowNotFound:
+            if self.if_exists:
+                return
+
+        hc = None
+        for hc in hc_group.ha_chassis:
+            if hc.chassis_name == self.chassis:
+                break
+        else:
+            if self.if_exists:
+                return
+            raise RuntimeError(
+                'HA Chassis %s does not exist' % self.hcg_id)
+
+        hc_group.delvalue('ha_chassis', hc)
+        hc.delete()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ovsdbapp-0.15.0/ovsdbapp/schema/ovn_northbound/impl_idl.py 
new/ovsdbapp-0.17.0/ovsdbapp/schema/ovn_northbound/impl_idl.py
--- old/ovsdbapp-0.15.0/ovsdbapp/schema/ovn_northbound/impl_idl.py      
2019-01-30 17:05:07.000000000 +0100
+++ new/ovsdbapp-0.17.0/ovsdbapp/schema/ovn_northbound/impl_idl.py      
2019-08-29 11:53:03.000000000 +0200
@@ -178,6 +178,12 @@
     def lrp_get_enabled(self, port):
         return cmd.LrpGetEnabledCommand(self, port)
 
+    def lrp_set_options(self, port, **options):
+        return cmd.LrpSetOptionsCommand(self, port, **options)
+
+    def lrp_get_options(self, port):
+        return cmd.LrpGetOptionsCommand(self, port)
+
     def lr_route_add(self, router, prefix, nexthop, port=None,
                      policy='dst-ip', may_exist=False):
         return cmd.LrRouteAddCommand(self, router, prefix, nexthop, port,
@@ -290,3 +296,22 @@
 
     def pg_get(self, pg):
         return cmd.PgGetCommand(self, pg)
+
+    def ha_chassis_group_add(self, name, may_exist=False, **columns):
+        return cmd.HAChassisGroupAddCommand(
+            self, name, may_exist=may_exist, **columns)
+
+    def ha_chassis_group_del(self, name, if_exists=False):
+        return cmd.HAChassisGroupDelCommand(self, name, if_exists=if_exists)
+
+    def ha_chassis_group_get(self, name):
+        return cmd.HAChassisGroupGetCommand(self, name)
+
+    def ha_chassis_group_add_chassis(self, hcg_id, chassis, priority,
+                                     **columns):
+        return cmd.HAChassisGroupAddChassisCommand(
+            self, hcg_id, chassis, priority, **columns)
+
+    def ha_chassis_group_del_chassis(self, hcg_id, chassis, if_exists=False):
+        return cmd.HAChassisGroupDelChassisCommand(
+            self, hcg_id, chassis, if_exists=if_exists)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ovsdbapp-0.15.0/ovsdbapp/schema/ovn_southbound/api.py 
new/ovsdbapp-0.17.0/ovsdbapp/schema/ovn_southbound/api.py
--- old/ovsdbapp-0.15.0/ovsdbapp/schema/ovn_southbound/api.py   2019-01-30 
17:05:07.000000000 +0100
+++ new/ovsdbapp-0.17.0/ovsdbapp/schema/ovn_southbound/api.py   2019-08-29 
11:53:03.000000000 +0200
@@ -48,7 +48,7 @@
     def chassis_del(self, chassis, if_exists=False):
         """Deletes chassis and its encaps and gateway_ports
 
-        :param chassis:   The name of the chassis to create
+        :param chassis:   The name of the chassis to delete
         :type chassis:    string
         :param if_exsits: Don't fail if `chassis` doesn't exist
         :param if_exists: boolean
@@ -67,7 +67,7 @@
         """Bind a logical port to a chassis
 
         :param port:      The name of the logical port to bind
-        :type port:       chassis
+        :type port:       string
         :param chassis:   The name of the chassis
         :type chassis:    string
         :param may_exist: Don't fail if port is already bound to a chassis
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ovsdbapp-0.15.0/ovsdbapp/schema/ovn_southbound/impl_idl.py 
new/ovsdbapp-0.17.0/ovsdbapp/schema/ovn_southbound/impl_idl.py
--- old/ovsdbapp-0.15.0/ovsdbapp/schema/ovn_southbound/impl_idl.py      
2019-01-30 17:05:07.000000000 +0100
+++ new/ovsdbapp-0.17.0/ovsdbapp/schema/ovn_southbound/impl_idl.py      
2019-08-29 11:53:03.000000000 +0200
@@ -36,8 +36,8 @@
     def chassis_list(self):
         return cmd.ChassisListCommand(self)
 
-    def lsp_bind(self, chassis, port, may_exist=False):
-        return cmd.LspBindCommand(self, chassis, port, may_exist)
+    def lsp_bind(self, port, chassis, may_exist=False):
+        return cmd.LspBindCommand(self, port, chassis, may_exist)
 
     def lsp_unbind(self, port, if_exists=False):
         return cmd.LspUnbindCommand(self, port, if_exists)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ovsdbapp-0.15.0/ovsdbapp/tests/base.py 
new/ovsdbapp-0.17.0/ovsdbapp/tests/base.py
--- old/ovsdbapp-0.15.0/ovsdbapp/tests/base.py  2019-01-30 17:05:07.000000000 
+0100
+++ new/ovsdbapp-0.17.0/ovsdbapp/tests/base.py  2019-08-29 11:53:03.000000000 
+0200
@@ -15,9 +15,14 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
+import mock
 from oslotest import base
 
 
 class TestCase(base.BaseTestCase):
 
-    """Test case base class for all unit tests."""
+    """Test case base class for all unit and functional tests."""
+
+    def setUp(self):
+        super(TestCase, self).setUp()
+        self.addCleanup(mock.patch.stopall)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ovsdbapp-0.15.0/ovsdbapp/tests/functional/schema/open_vswitch/test_common_db.py
 
new/ovsdbapp-0.17.0/ovsdbapp/tests/functional/schema/open_vswitch/test_common_db.py
--- 
old/ovsdbapp-0.15.0/ovsdbapp/tests/functional/schema/open_vswitch/test_common_db.py
 2019-01-30 17:05:07.000000000 +0100
+++ 
new/ovsdbapp-0.17.0/ovsdbapp/tests/functional/schema/open_vswitch/test_common_db.py
 2019-08-29 11:53:03.000000000 +0200
@@ -12,7 +12,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import uuid
+
 from ovsdbapp.backend.ovs_idl import idlutils
+from ovsdbapp.backend.ovs_idl import rowview
 from ovsdbapp.schema.open_vswitch import impl_idl
 from ovsdbapp.tests.functional import base
 from ovsdbapp.tests.functional.schema.open_vswitch import fixtures
@@ -98,3 +101,15 @@
         self.assertTrue(
             set(b['name'] for b in self.bridges).issubset(
                 set(b.name for b in res)))
+
+    def test_db_create(self):
+        _uuid = self.api.db_create(
+            'Queue', external_ids={'x': 'x'}).execute(check_error=True)
+        self.assertIsInstance(_uuid, uuid.UUID)
+        self.api.db_destroy('Queue', _uuid).execute(check_error=True)
+
+    def test_db_create_row(self):
+        row = self.api.db_create_row(
+            'Queue', external_ids={'x': 'x'}).execute(check_error=True)
+        self.assertIsInstance(row, rowview.RowView)
+        self.api.db_destroy('Queue', row.uuid).execute(check_error=True)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ovsdbapp-0.15.0/ovsdbapp/tests/functional/schema/ovn_northbound/test_impl_idl.py
 
new/ovsdbapp-0.17.0/ovsdbapp/tests/functional/schema/ovn_northbound/test_impl_idl.py
--- 
old/ovsdbapp-0.15.0/ovsdbapp/tests/functional/schema/ovn_northbound/test_impl_idl.py
        2019-01-30 17:05:07.000000000 +0100
+++ 
new/ovsdbapp-0.17.0/ovsdbapp/tests/functional/schema/ovn_northbound/test_impl_idl.py
        2019-08-29 11:53:03.000000000 +0200
@@ -843,6 +843,32 @@
                               if_exists=True)
         self.assertEqual(len(lr.nat), len(const.NAT_TYPES))
 
+    def test_lr_nat_del_specific_snat_ip_network(self):
+        lr = self._lr_add(utils.get_rand_device_name())
+        self._lr_nat_add(router=lr,
+                         nat_type=const.NAT_SNAT,
+                         logical_ip='10.17.4.0/24',
+                         external_ip='192.0.2.2')
+        # Attempt to delete NAT rule of type const.NAT_SNAT by passing
+        # an IP network (corresponding to logical_ip) as match_ip
+        self.api.lr_nat_del(lr.name,
+                            nat_type=const.NAT_SNAT,
+                            match_ip='10.17.4.0/24').execute(check_error=True)
+        # Assert that the NAT rule of type const.NAT_SNAT is deleted
+        self.assertEqual([], lr.nat)
+
+    def test_lr_nat_del_specific_snat_ip_network_not_found(self):
+        self.assertRaises(idlutils.RowNotFound, self._lr_nat_del,
+                          nat_type=const.NAT_SNAT, match_ip='10.17.4.0/24')
+
+    def test_lr_nat_del_specific_dnat_ip_network(self):
+        self.assertRaises(ValueError, self._lr_nat_del,
+                          nat_type=const.NAT_DNAT, match_ip='192.0.2.1/32')
+
+    def test_lr_nat_del_specific_both_ip_network(self):
+        self.assertRaises(ValueError, self._lr_nat_del,
+                          nat_type=const.NAT_BOTH, match_ip='192.0.2.0/24')
+
     def test_lr_nat_list(self):
         lr = self._three_nats()
         nats = self.api.lr_nat_list(lr.uuid).execute(check_error=True)
@@ -1006,6 +1032,14 @@
         self.assertTrue(self.api.lrp_get_enabled(lrp.name).execute(
             check_error=True))
 
+    def test_lrp_get_set_options(self):
+        options = {'one': 'two', 'three': 'four'}
+        lrp = self._lrp_add(None)
+        self.api.lrp_set_options(lrp.uuid, **options).execute(
+            check_error=True)
+        self.assertEqual(options, self.api.lrp_get_options(lrp.uuid).execute(
+            check_error=True))
+
 
 class TestLoadBalancerOps(OvnNorthboundTest):
 
@@ -1414,3 +1448,101 @@
         # Assert that if if_exists is True it won't raise an error
         self.api.pg_del_ports(self.pg_name, non_existent_res,
                               if_exists=True).execute(check_error=True)
+
+
+class TestHAChassisGroup(OvnNorthboundTest):
+
+    def setUp(self):
+        super(TestHAChassisGroup, self).setUp()
+        self.hcg_name = 'ha-group-%s' % ovsdb_utils.generate_uuid()
+        self.chassis = 'chassis-%s' % ovsdb_utils.generate_uuid()
+
+    def test_ha_chassis_group(self):
+        # Assert the HA Chassis Group was added
+        self.api.ha_chassis_group_add(self.hcg_name).execute(check_error=True)
+        hcg = self.api.ha_chassis_group_get(self.hcg_name).execute(
+            check_error=True)
+        self.assertEqual(self.hcg_name, hcg.name)
+
+        # Assert the HA Chassis Group was deleted
+        self.api.ha_chassis_group_del(self.hcg_name).execute(check_error=True)
+        cmd = self.api.ha_chassis_group_get(self.hcg_name)
+        self.assertRaises(idlutils.RowNotFound, cmd.execute, check_error=True)
+
+    def test_ha_chassis_group_add_delete_chassis(self):
+        self.api.ha_chassis_group_add(self.hcg_name).execute(check_error=True)
+        priority = 20
+        self.api.ha_chassis_group_add_chassis(
+            self.hcg_name, self.chassis, priority).execute(check_error=True)
+
+        # Assert that the HA Chassis entry was created
+        row = self.api.db_find(
+            'HA_Chassis',
+            ('chassis_name', '=', self.chassis)).execute(check_error=True)
+        self.assertEqual(priority, row[0]['priority'])
+
+        # Assert that the HA Chassis entry was associated with
+        # the HA Chassis Group
+        hcg = self.api.ha_chassis_group_get(self.hcg_name).execute(
+            check_error=True)
+        self.assertEqual(self.chassis, hcg.ha_chassis[0].chassis_name)
+
+        # Deletes the HA Chassis entry
+        self.api.ha_chassis_group_del_chassis(
+            self.hcg_name, self.chassis).execute(check_error=True)
+        row = self.api.db_find(
+            'HA_Chassis',
+            ('chassis_name', '=', self.chassis)).execute(check_error=True)
+        self.assertEqual([], row)
+
+        # Assert that the deleted HA Chassis entry was dissociated from
+        # the HA Chassis Group
+        hcg = self.api.ha_chassis_group_get(self.hcg_name).execute(
+            check_error=True)
+        self.assertEqual([], hcg.ha_chassis)
+
+    def test_ha_chassis_group_if_exists(self):
+        self.api.ha_chassis_group_add(self.hcg_name).execute(check_error=True)
+        self.api.ha_chassis_group_add_chassis(
+            self.hcg_name, self.chassis, priority=10).execute(check_error=True)
+
+        # Deletes the HA Chassis entry
+        self.api.ha_chassis_group_del_chassis(
+            self.hcg_name, self.chassis).execute(check_error=True)
+        row = self.api.db_find(
+            'HA_Chassis',
+            ('chassis_name', '=', self.chassis)).execute(check_error=True)
+        self.assertEqual([], row)
+
+        # Tries to delete it again, since if_exists=True it shouldn't raise
+        # any errors
+        self.api.ha_chassis_group_del_chassis(
+            self.hcg_name, self.chassis, if_exists=True).execute(
+            check_error=True)
+
+        # Tries to delete it again with if_exists=False, now it should raise
+        # a RuntimeError
+        cmd = self.api.ha_chassis_group_del_chassis(
+            self.hcg_name, self.chassis, if_exists=False)
+        self.assertRaises(RuntimeError, cmd.execute, check_error=True)
+
+        # Deletes the HA Chassis Group entry
+        self.api.ha_chassis_group_del(self.hcg_name).execute(check_error=True)
+        cmd = self.api.ha_chassis_group_get(self.hcg_name)
+        self.assertRaises(idlutils.RowNotFound, cmd.execute, check_error=True)
+
+        # Tries to delete it again, since if_exists=True it shouldn't raise
+        # any errors
+        self.api.ha_chassis_group_del(
+            self.hcg_name, if_exists=True).execute(check_error=True)
+
+        # Tries to delete it again with if_exists=False, now it should raise
+        # a RuntimeError
+        cmd = self.api.ha_chassis_group_del(self.hcg_name)
+        self.assertRaises(RuntimeError, cmd.execute, check_error=True)
+
+    def test_ha_chassis_group_may_exist(self):
+        cmd = self.api.ha_chassis_group_add(self.hcg_name, may_exist=True)
+        hcg1 = cmd.execute(check_error=True)
+        hcg2 = cmd.execute(check_error=True)
+        self.assertEqual(hcg1, hcg2)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ovsdbapp-0.15.0/ovsdbapp/tests/functional/schema/ovn_southbound/event.py 
new/ovsdbapp-0.17.0/ovsdbapp/tests/functional/schema/ovn_southbound/event.py
--- 
old/ovsdbapp-0.15.0/ovsdbapp/tests/functional/schema/ovn_southbound/event.py    
    1970-01-01 01:00:00.000000000 +0100
+++ 
new/ovsdbapp-0.17.0/ovsdbapp/tests/functional/schema/ovn_southbound/event.py    
    2019-08-29 11:53:03.000000000 +0200
@@ -0,0 +1,22 @@
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from ovsdbapp.backend.ovs_idl import event
+
+
+class WaitForPortBindingEvent(event.WaitEvent):
+    event_name = 'WaitForPortBindingEvent'
+
+    def __init__(self, port, timeout=5):
+        super(WaitForPortBindingEvent, self).__init__(
+            (self.ROW_CREATE,), 'Port_Binding', (('logical_port', '=', port),),
+            timeout=timeout)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ovsdbapp-0.15.0/ovsdbapp/tests/functional/schema/ovn_southbound/test_impl_idl.py
 
new/ovsdbapp-0.17.0/ovsdbapp/tests/functional/schema/ovn_southbound/test_impl_idl.py
--- 
old/ovsdbapp-0.15.0/ovsdbapp/tests/functional/schema/ovn_southbound/test_impl_idl.py
        2019-01-30 17:05:07.000000000 +0100
+++ 
new/ovsdbapp-0.17.0/ovsdbapp/tests/functional/schema/ovn_southbound/test_impl_idl.py
        2019-08-29 11:53:03.000000000 +0200
@@ -10,23 +10,17 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from ovsdbapp.backend.ovs_idl import event
 from ovsdbapp.backend.ovs_idl import idlutils
 from ovsdbapp import event as ovsdb_event
 from ovsdbapp.schema.ovn_northbound import impl_idl as nbidl
 from ovsdbapp.schema.ovn_southbound import impl_idl
 from ovsdbapp.tests.functional import base
+from ovsdbapp.tests.functional.schema.ovn_southbound import event
 from ovsdbapp.tests.functional.schema.ovn_southbound import fixtures
 from ovsdbapp.tests import utils
 
-
-class WaitForPortBindingEvent(event.WaitEvent):
-    event_name = 'WaitForPortBindingEvent'
-
-    def __init__(self, port, timeout=5):
-        super(WaitForPortBindingEvent, self).__init__(
-            (self.ROW_CREATE,), 'Port_Binding', (('logical_port', '=', port),),
-            timeout=timeout)
+# Keep the class here for backward compatiblity
+WaitForPortBindingEvent = event.WaitForPortBindingEvent
 
 
 class OvnSouthboundTest(base.FunctionalTestCase):
@@ -93,7 +87,7 @@
         cname, sname, pname = (utils.get_rand_device_name(prefix=p)
                                for p in ("chassis", "switch", "port"))
         chassis = self._chassis_add(['vxlan'], '192.0.2.1', chassis=cname)
-        row_event = WaitForPortBindingEvent(pname)
+        row_event = event.WaitForPortBindingEvent(pname)
         # We have to wait for ovn-northd to actually create the port binding
         self.handler.watch_event(row_event)
         with self.nbapi.transaction(check_error=True) as txn:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ovsdbapp-0.15.0/ovsdbapp/tests/unit/backend/ovs_idl/test_connection.py 
new/ovsdbapp-0.17.0/ovsdbapp/tests/unit/backend/ovs_idl/test_connection.py
--- old/ovsdbapp-0.15.0/ovsdbapp/tests/unit/backend/ovs_idl/test_connection.py  
2019-01-30 17:05:07.000000000 +0100
+++ new/ovsdbapp-0.17.0/ovsdbapp/tests/unit/backend/ovs_idl/test_connection.py  
2019-08-29 11:53:03.000000000 +0200
@@ -13,7 +13,6 @@
 #    under the License.
 
 import mock
-import threading
 
 from ovs import poller
 
@@ -22,6 +21,7 @@
 from ovsdbapp.tests import base
 
 
[email protected](connection.threading, 'Thread')
 class TestOVSNativeConnection(base.TestCase):
 
     @mock.patch.object(connection, 'TransactionQueue')
@@ -32,7 +32,6 @@
         self.conn = connection.Connection(self.idl, timeout=1)
         self.mock_trans_queue.assert_called_once_with(1)
 
-    @mock.patch.object(threading, 'Thread')
     @mock.patch.object(poller, 'Poller')
     @mock.patch.object(idlutils, 'wait_for_change')
     def test_start(self, mock_wait_for_change, mock_poller, mock_thread):
@@ -46,7 +45,7 @@
         mock_thread.return_value.setDaemon.assert_called_once_with(True)
         mock_thread.return_value.start.assert_called_once_with()
 
-    def test_queue_txn(self):
+    def test_queue_txn(self, mock_thread):
         self.conn.start()
         self.conn.queue_txn('blah')
         self.conn.txns.put.assert_called_once_with('blah',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ovsdbapp-0.15.0/ovsdbapp/tests/unit/schema/open_vswitch/test_impl_idl.py 
new/ovsdbapp-0.17.0/ovsdbapp/tests/unit/schema/open_vswitch/test_impl_idl.py
--- 
old/ovsdbapp-0.15.0/ovsdbapp/tests/unit/schema/open_vswitch/test_impl_idl.py    
    2019-01-30 17:05:07.000000000 +0100
+++ 
new/ovsdbapp-0.17.0/ovsdbapp/tests/unit/schema/open_vswitch/test_impl_idl.py    
    2019-08-29 11:53:03.000000000 +0200
@@ -33,3 +33,19 @@
             transaction = impl_idl.OvsVsctlTransaction(mock.sentinel,
                                                        mock.Mock(), 0)
             transaction.post_commit(mock.Mock())
+
+
+class TestOvsdbIdl(base.TestCase):
+    def setUp(self):
+        super(TestOvsdbIdl, self).setUp()
+        impl_idl.OvsdbIdl.ovsdb_connection = None
+
+    def test_nested_txns(self):
+        conn = mock.MagicMock()
+        api = impl_idl.OvsdbIdl(conn, nested_transactions=False)
+        self.assertFalse(api._nested_txns)
+
+    def test_init_session(self):
+        conn = mock.MagicMock()
+        backend = impl_idl.OvsdbIdl(conn, start=False)
+        self.assertIsNone(backend.ovsdb_connection)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ovsdbapp-0.15.0/ovsdbapp/tests/unit/test_api.py 
new/ovsdbapp-0.17.0/ovsdbapp/tests/unit/test_api.py
--- old/ovsdbapp-0.15.0/ovsdbapp/tests/unit/test_api.py 2019-01-30 
17:05:07.000000000 +0100
+++ new/ovsdbapp-0.17.0/ovsdbapp/tests/unit/test_api.py 2019-08-29 
11:53:03.000000000 +0200
@@ -65,7 +65,9 @@
 
 class TestingAPI(api.API):
     def create_transaction(self, check_error=False, log_errors=True, **kwargs):
-        return FakeTransaction()
+        txn = FakeTransaction()
+        mock.patch.object(txn, 'commit').start()
+        return txn
 
 
 TestingAPI.__abstractmethods__ = set()
@@ -75,7 +77,6 @@
     def setUp(self):
         super(TransactionTestCase, self).setUp()
         self.api = TestingAPI()
-        mock.patch.object(FakeTransaction, 'commit').start()
         self.useFixture(GreenThreadingFixture())
 
     def test_transaction_nested(self):
@@ -84,6 +85,21 @@
                 self.assertIs(txn1, txn2)
         txn1.commit.assert_called_once_with()
 
+    def test_transaction_nested_false(self):
+        with self.api.transaction(nested=False) as txn1:
+            with self.api.transaction() as txn2:
+                self.assertIsNot(txn1, txn2)
+        txn1.commit.assert_called_once_with()
+        txn2.commit.assert_called_once_with()
+
+    def test_api_level_transaction_nested_fales(self):
+        api = TestingAPI(nested_transactions=False)
+        with api.transaction() as txn1:
+            with api.transaction() as txn2:
+                self.assertIsNot(txn1, txn2)
+        txn1.commit.assert_called_once_with()
+        txn2.commit.assert_called_once_with()
+
     def test_transaction_no_nested_transaction_after_error(self):
         class TestException(Exception):
             pass
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ovsdbapp-0.15.0/ovsdbapp/venv.py 
new/ovsdbapp-0.17.0/ovsdbapp/venv.py
--- old/ovsdbapp-0.15.0/ovsdbapp/venv.py        2019-01-30 17:05:07.000000000 
+0100
+++ new/ovsdbapp-0.17.0/ovsdbapp/venv.py        2019-08-29 11:53:03.000000000 
+0200
@@ -130,22 +130,13 @@
 
 class OvsOvnVenvFixture(OvsVenvFixture):
     PATH_VAR_TEMPLATE = OvsVenvFixture.PATH_VAR_TEMPLATE + (
-        ":{0}/vtep"
-        ":{0}/ovn/controller:{0}/ovn/controller-vtep"
-        ":{0}/ovn/northd:{0}/ovn/utilities")
+        ":{0}/ovn/controller:{0}/ovn/northd:{0}/ovn/utilities")
 
     def __init__(self, *args, **kwargs):
         self.add_chassis = kwargs.pop('add_chassis', False)
         super(OvsOvnVenvFixture, self).__init__(*args, **kwargs)
 
     @property
-    def vtep_schema(self):
-        path = os.path.join(self.ovsdir, 'vtep', 'vtep.ovsschema')
-        if os.path.isfile(path):
-            return path
-        return os.path.join(self.ovsdir, 'vtep.ovsschema')
-
-    @property
     def ovnsb_schema(self):
         path = os.path.join(self.ovsdir, 'ovn', 'ovn-sb.ovsschema')
         if os.path.isfile(path):
@@ -169,8 +160,6 @@
 
     def setup_dbs(self):
         super(OvsOvnVenvFixture, self).setup_dbs()
-        self.create_db('vtep.db', self.vtep_schema)
-        self.ovsdb_server_dbs.append('vtep.db')
         self.create_db('ovnsb.db', self.ovnsb_schema)
         self.create_db('ovnnb.db', self.ovnnb_schema)
 
@@ -220,6 +209,3 @@
                    '--ovnnb-db=' + self.ovnnb_connection])
         self.call(['ovn-controller', '--detach', '--no-chdir', '--pidfile',
                    '-vconsole:off', '--log-file'])
-        self.call(['ovn-controller-vtep', '--detach', '--no-chdir',
-                   '--pidfile', '-vconsole:off', '--log-file',
-                   '--ovnsb-db=' + self.ovnsb_connection])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ovsdbapp-0.15.0/ovsdbapp.egg-info/PKG-INFO 
new/ovsdbapp-0.17.0/ovsdbapp.egg-info/PKG-INFO
--- old/ovsdbapp-0.15.0/ovsdbapp.egg-info/PKG-INFO      2019-01-30 
17:05:56.000000000 +0100
+++ new/ovsdbapp-0.17.0/ovsdbapp.egg-info/PKG-INFO      2019-08-29 
11:53:59.000000000 +0200
@@ -1,14 +1,14 @@
 Metadata-Version: 1.1
 Name: ovsdbapp
-Version: 0.15.0
+Version: 0.17.0
 Summary: A library for creating OVSDB applications
 Home-page: https://pypi.org/project/ovsdbapp/
 Author: OpenStack
 Author-email: [email protected]
 License: UNKNOWN
-Description: ===============================
+Description: ========
         ovsdbapp
-        ===============================
+        ========
         
         A library for creating OVSDB applications
         
@@ -17,7 +17,7 @@
         wraps the Python 'ovs' and adds an event loop and friendly 
transactions.
         
         * Free software: Apache license
-        * Source: http://git.openstack.org/cgit/openstack/ovsdbapp
+        * Source: https://opendev.org/openstack/ovsdbapp/
         * Bugs: http://bugs.launchpad.net/ovsdbapp
         
         Features
@@ -38,5 +38,5 @@
 Classifier: Programming Language :: Python :: 2
 Classifier: Programming Language :: Python :: 2.7
 Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.3
-Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ovsdbapp-0.15.0/ovsdbapp.egg-info/SOURCES.txt 
new/ovsdbapp-0.17.0/ovsdbapp.egg-info/SOURCES.txt
--- old/ovsdbapp-0.15.0/ovsdbapp.egg-info/SOURCES.txt   2019-01-30 
17:05:56.000000000 +0100
+++ new/ovsdbapp-0.17.0/ovsdbapp.egg-info/SOURCES.txt   2019-08-29 
11:53:59.000000000 +0200
@@ -81,6 +81,7 @@
 ovsdbapp/tests/functional/schema/ovn_northbound/fixtures.py
 ovsdbapp/tests/functional/schema/ovn_northbound/test_impl_idl.py
 ovsdbapp/tests/functional/schema/ovn_southbound/__init__.py
+ovsdbapp/tests/functional/schema/ovn_southbound/event.py
 ovsdbapp/tests/functional/schema/ovn_southbound/fixtures.py
 ovsdbapp/tests/functional/schema/ovn_southbound/test_impl_idl.py
 ovsdbapp/tests/unit/__init__.py
@@ -104,6 +105,7 @@
 releasenotes/source/pike.rst
 releasenotes/source/queens.rst
 releasenotes/source/rocky.rst
+releasenotes/source/stein.rst
 releasenotes/source/unreleased.rst
 releasenotes/source/_static/.placeholder
 releasenotes/source/_templates/.placeholder
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ovsdbapp-0.15.0/ovsdbapp.egg-info/pbr.json 
new/ovsdbapp-0.17.0/ovsdbapp.egg-info/pbr.json
--- old/ovsdbapp-0.15.0/ovsdbapp.egg-info/pbr.json      2019-01-30 
17:05:56.000000000 +0100
+++ new/ovsdbapp-0.17.0/ovsdbapp.egg-info/pbr.json      2019-08-29 
11:53:59.000000000 +0200
@@ -1 +1 @@
-{"git_version": "bc06517", "is_release": true}
\ No newline at end of file
+{"git_version": "74b52bb", "is_release": true}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ovsdbapp-0.15.0/releasenotes/source/index.rst 
new/ovsdbapp-0.17.0/releasenotes/source/index.rst
--- old/ovsdbapp-0.15.0/releasenotes/source/index.rst   2019-01-30 
17:05:07.000000000 +0100
+++ new/ovsdbapp-0.17.0/releasenotes/source/index.rst   2019-08-29 
11:53:03.000000000 +0200
@@ -6,6 +6,7 @@
    :maxdepth: 1
 
    unreleased
+   stein
    rocky
    queens
    pike
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ovsdbapp-0.15.0/releasenotes/source/stein.rst 
new/ovsdbapp-0.17.0/releasenotes/source/stein.rst
--- old/ovsdbapp-0.15.0/releasenotes/source/stein.rst   1970-01-01 
01:00:00.000000000 +0100
+++ new/ovsdbapp-0.17.0/releasenotes/source/stein.rst   2019-08-29 
11:53:03.000000000 +0200
@@ -0,0 +1,6 @@
+===================================
+ Stein Series Release Notes
+===================================
+
+.. release-notes::
+   :branch: stable/stein
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ovsdbapp-0.15.0/setup.cfg 
new/ovsdbapp-0.17.0/setup.cfg
--- old/ovsdbapp-0.15.0/setup.cfg       2019-01-30 17:05:56.000000000 +0100
+++ new/ovsdbapp-0.17.0/setup.cfg       2019-08-29 11:53:59.000000000 +0200
@@ -16,8 +16,8 @@
        Programming Language :: Python :: 2
        Programming Language :: Python :: 2.7
        Programming Language :: Python :: 3
-       Programming Language :: Python :: 3.3
-       Programming Language :: Python :: 3.5
+       Programming Language :: Python :: 3.6
+       Programming Language :: Python :: 3.7
 
 [files]
 packages = 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ovsdbapp-0.15.0/test-requirements.txt 
new/ovsdbapp-0.17.0/test-requirements.txt
--- old/ovsdbapp-0.15.0/test-requirements.txt   2019-01-30 17:05:07.000000000 
+0100
+++ new/ovsdbapp-0.17.0/test-requirements.txt   2019-08-29 11:53:03.000000000 
+0200
@@ -6,7 +6,8 @@
 
 coverage!=4.4,>=4.0 # Apache-2.0
 python-subunit>=1.0.0 # Apache-2.0/BSD
-sphinx!=1.6.6,!=1.6.7,>=1.6.2 # BSD
+sphinx!=1.6.6,!=1.6.7,>=1.6.2,<2.0.0;python_version=='2.7'  # BSD
+sphinx!=1.6.6,!=1.6.7,>=1.6.2;python_version>='3.4'  # BSD
 openstackdocstheme>=1.18.1 # Apache-2.0
 oslotest>=3.2.0 # Apache-2.0
 os-testr>=1.0.0 # Apache-2.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ovsdbapp-0.15.0/tox.ini new/ovsdbapp-0.17.0/tox.ini
--- old/ovsdbapp-0.15.0/tox.ini 2019-01-30 17:05:07.000000000 +0100
+++ new/ovsdbapp-0.17.0/tox.ini 2019-08-29 11:53:03.000000000 +0200
@@ -1,6 +1,6 @@
 [tox]
 minversion = 2.0
-envlist = py35,py27,pypy,pep8
+envlist = py27,py37,pypy,pep8
 skipsdist = True
 
 [testenv]
@@ -11,7 +11,7 @@
    OS_TEST_PATH=./ovsdbapp/tests/unit
 install_command = pip install {opts} {packages}
 deps =
-  
-c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt}
+  
-c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
   -r{toxinidir}/test-requirements.txt
   -r{toxinidir}/requirements.txt
 commands = stestr run --slowest {posargs}
@@ -51,6 +51,12 @@
          {toxinidir}/tools/setup-ovs.sh
          {[testenv]commands}
 
+[testenv:functional-py36]
+basepython = python3.6
+setenv = {[testenv:functional]setenv}
+passenv = {[testenv:functional]passenv}
+commands = {[testenv:functional]commands}
+
 [flake8]
 # E123, E125 skipped as they are invalid PEP-8.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ovsdbapp-0.15.0/zuul.d/ovsdbapp-jobs.yaml 
new/ovsdbapp-0.17.0/zuul.d/ovsdbapp-jobs.yaml
--- old/ovsdbapp-0.15.0/zuul.d/ovsdbapp-jobs.yaml       2019-01-30 
17:05:07.000000000 +0100
+++ new/ovsdbapp-0.17.0/zuul.d/ovsdbapp-jobs.yaml       2019-08-29 
11:53:03.000000000 +0200
@@ -5,3 +5,4 @@
     vars:
       devstack_localrc:
         LIBS_FROM_GIT: ovsdbapp
+        USE_PYTHON3: true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ovsdbapp-0.15.0/zuul.d/project.yaml 
new/ovsdbapp-0.17.0/zuul.d/project.yaml
--- old/ovsdbapp-0.15.0/zuul.d/project.yaml     2019-01-30 17:05:07.000000000 
+0100
+++ new/ovsdbapp-0.17.0/zuul.d/project.yaml     2019-08-29 11:53:03.000000000 
+0200
@@ -1,16 +1,17 @@
 - project:
     templates:
       - openstack-python-jobs
-      - openstack-python35-jobs
-      - openstack-python36-jobs
+      - openstack-python3-train-jobs
       - check-requirements
     check:
       jobs:
         - openstack-tox-lower-constraints
         - openstack-tox-functional
+        - openstack-tox-functional-py36
         - ovsdbapp-tempest-dsvm-networking-ovn-ovs-release
     gate:
       jobs:
         - openstack-tox-lower-constraints
         - openstack-tox-functional
+        - openstack-tox-functional-py36
         - ovsdbapp-tempest-dsvm-networking-ovn-ovs-release


Reply via email to