diff -crB --new-file neutron-9.4.2.dev21-backup/neutron/db/l3_dvr_db.py neutron-9.4.2.dev21/neutron/db/l3_dvr_db.py
*** neutron-9.4.2.dev21-backup/neutron/db/l3_dvr_db.py	2019-01-28 10:37:08.229026630 -0800
--- neutron-9.4.2.dev21/neutron/db/l3_dvr_db.py	2019-01-28 14:38:19.211746835 -0800
***************
*** 80,115 ****
              return router_db
  
      def _validate_router_migration(self, context, router_db, router_res):
!         """Allow centralized -> distributed state transition only."""
!         if (router_db.extra_attributes.distributed and
!             router_res.get('distributed') is False):
!             LOG.info(_LI("Centralizing distributed router %s "
!                          "is not supported"), router_db['id'])
!             raise n_exc.BadRequest(
!                 resource='router',
!                 msg=_("Migration from distributed router to centralized is "
!                       "not supported"))
!         elif (not router_db.extra_attributes.distributed and
!               router_res.get('distributed')):
!             # router should be disabled in order for upgrade
!             if router_db.admin_state_up:
!                 msg = _('Cannot upgrade active router to distributed. Please '
!                         'set router admin_state_up to False prior to upgrade.')
!                 raise n_exc.BadRequest(resource='router', msg=msg)
  
!             # Notify advanced services of the imminent state transition
!             # for the router.
!             try:
!                 kwargs = {'context': context, 'router': router_db}
!                 registry.notify(
!                     resources.ROUTER, events.BEFORE_UPDATE, self, **kwargs)
!             except exceptions.CallbackFailure as e:
!                 with excutils.save_and_reraise_exception():
!                     # NOTE(armax): preserve old check's behavior
!                     if len(e.errors) == 1:
!                         raise e.errors[0].error
!                     raise l3.RouterInUse(router_id=router_db['id'],
!                                          reason=e)
  
      def _update_router_db(self, context, router_id, data):
          with context.session.begin(subtransactions=True):
--- 80,114 ----
              return router_db
  
      def _validate_router_migration(self, context, router_db, router_res):
!         """Allow transition only when admin_state_up=False."""
!         original_distributed_state = router_db.extra_attributes.distributed
!         requested_distributed_state = router_res.get('distributed', None)
  
!         distributed_changed = (
!             requested_distributed_state is not None and
!             requested_distributed_state != original_distributed_state)
!         if not distributed_changed:
!             return False
!         if router_db.admin_state_up:
!             msg = _("Cannot change the 'distributed' attribute of active "
!                     "routers. Please set router admin_state_up to False "
!                     "prior to upgrade")
!             raise n_exc.BadRequest(resource='router', msg=msg)
! 
!         # Notify advanced services of the imminent state transition
!         # for the router.
!         try:
!             kwargs = {'context': context, 'router': router_db}
!             registry.notify(
!                 resources.ROUTER, events.BEFORE_UPDATE, self, **kwargs)
!         except exceptions.CallbackFailure as e:
!             with excutils.save_and_reraise_exception():
!                 # NOTE(armax): preserve old check's behavior
!                 if len(e.errors) == 1:
!                     raise e.errors[0].error
!                 raise l3.RouterInUse(router_id=router_db['id'],
!                                      reason=e)
!         return True
  
      def _update_router_db(self, context, router_id, data):
          with context.session.begin(subtransactions=True):
***************
*** 119,131 ****
              migrating_to_distributed = (
                  not router_db.extra_attributes.distributed and
                  data.get('distributed') is True)
!             self._validate_router_migration(context, router_db, data)
!             router_db.extra_attributes.update(data)
!             if data.get('distributed'):
                  self._migrate_router_ports(
                      context, router_db,
                      old_owner=const.DEVICE_OWNER_ROUTER_INTF,
                      new_owner=const.DEVICE_OWNER_DVR_INTERFACE)
              if migrating_to_distributed:
                  if router_db['gw_port_id']:
                      # If the Legacy router is getting migrated to a DVR
--- 118,143 ----
              migrating_to_distributed = (
                  not router_db.extra_attributes.distributed and
                  data.get('distributed') is True)
!             if not self._validate_router_migration(context, router_db, data):
!                 return router_db
!             if migrating_to_distributed:
                  self._migrate_router_ports(
                      context, router_db,
                      old_owner=const.DEVICE_OWNER_ROUTER_INTF,
                      new_owner=const.DEVICE_OWNER_DVR_INTERFACE)
+                 router_db.extra_attributes.update(data)
+             else:
+                 self._migrate_router_ports(
+                     context, router_db,
+                     old_owner=const.DEVICE_OWNER_DVR_INTERFACE,
+                     new_owner=const.DEVICE_OWNER_ROUTER_INTF)
+                 router_db.extra_attributes.update(data)
+                 if router_db['gw_port_id']:
+                     # If converted to Legacy router then delete
+                     # the csnat ports.
+                     setattr(context, 'GUARD_TRANSACTION', False)
+                     self.delete_csnat_router_interface_ports(
+                         context.elevated(), router_db)
              if migrating_to_distributed:
                  if router_db['gw_port_id']:
                      # If the Legacy router is getting migrated to a DVR
***************
*** 138,148 ****
                          context.elevated(), router_db):
                          LOG.debug("SNAT interface ports not created: %s",
                                    router_db['id'])
!                 cur_agents = self.list_l3_agents_hosting_router(
!                     context, router_db['id'])['agents']
!                 for agent in cur_agents:
!                     self._unbind_router(context, router_db['id'],
!                                         agent['id'])
              return router_db
  
      def _delete_current_gw_port(self, context, router_id, router, new_network):
--- 150,160 ----
                          context.elevated(), router_db):
                          LOG.debug("SNAT interface ports not created: %s",
                                    router_db['id'])
!             cur_agents = self.list_l3_agents_hosting_router(
!                 context, router_db['id'])['agents']
!             for agent in cur_agents:
!                 self._unbind_router(context, router_db['id'],
!                                     agent['id'])
              return router_db
  
      def _delete_current_gw_port(self, context, router_id, router, new_network):
diff -crB --new-file neutron-9.4.2.dev21-backup/neutron/db/l3_hamode_db.py neutron-9.4.2.dev21/neutron/db/l3_hamode_db.py
*** neutron-9.4.2.dev21-backup/neutron/db/l3_hamode_db.py	2019-01-28 10:37:08.237026634 -0800
--- neutron-9.4.2.dev21/neutron/db/l3_hamode_db.py	2019-01-28 14:38:19.211746835 -0800
***************
*** 501,542 ****
      @db_api.retry_if_session_inactive()
      def _update_router_db(self, context, router_id, data):
          router_db = self._get_router(context, router_id)
- 
-         original_distributed_state = router_db.extra_attributes.distributed
          original_ha_state = router_db.extra_attributes.ha
- 
          requested_ha_state = data.pop('ha', None)
-         requested_distributed_state = data.get('distributed', None)
-         # cvr to dvrha
-         if not original_distributed_state and not original_ha_state:
-             if (requested_ha_state is True and
-                     requested_distributed_state is True):
-                 raise l3_ha.UpdateToDvrHamodeNotSupported()
- 
-         # cvrha to any dvr...
-         elif not original_distributed_state and original_ha_state:
-             if requested_distributed_state is True:
-                 raise l3_ha.DVRmodeUpdateOfHaNotSupported()
- 
-         # dvr to any ha...
-         elif original_distributed_state and not original_ha_state:
-             if requested_ha_state is True:
-                 raise l3_ha.HAmodeUpdateOfDvrNotSupported()
- 
-         #dvrha to any cvr...
-         elif original_distributed_state and original_ha_state:
-             if requested_distributed_state is False:
-                 raise l3_ha.DVRmodeUpdateOfDvrHaNotSupported()
-             #elif dvrha to dvr
-             if requested_ha_state is False:
-                 raise l3_ha.HAmodeUpdateOfDvrHaNotSupported()
- 
          ha_changed = (requested_ha_state is not None and
                        requested_ha_state != original_ha_state)
          if ha_changed:
              if router_db.admin_state_up:
                  msg = _('Cannot change HA attribute of active routers. Please '
!                         'set router admin_state_up to False prior to upgrade.')
                  raise n_exc.BadRequest(resource='router', msg=msg)
              # set status to ALLOCATING so this router is no longer
              # provided to agents while its interfaces are being re-configured.
--- 501,514 ----
      @db_api.retry_if_session_inactive()
      def _update_router_db(self, context, router_id, data):
          router_db = self._get_router(context, router_id)
          original_ha_state = router_db.extra_attributes.ha
          requested_ha_state = data.pop('ha', None)
          ha_changed = (requested_ha_state is not None and
                        requested_ha_state != original_ha_state)
          if ha_changed:
              if router_db.admin_state_up:
                  msg = _('Cannot change HA attribute of active routers. Please '
!                         'set router admin_state_up to False prior to upgrade')
                  raise n_exc.BadRequest(resource='router', msg=msg)
              # set status to ALLOCATING so this router is no longer
              # provided to agents while its interfaces are being re-configured.
***************
*** 544,549 ****
--- 516,523 ----
              # status cannot be used because agents treat hidden routers as
              # deleted routers.
              data['status'] = n_const.ROUTER_STATUS_ALLOCATING
+         else:
+             data['ha'] = original_ha_state
  
          with context.session.begin(subtransactions=True):
              router_db = super(L3_HA_NAT_db_mixin, self)._update_router_db(
diff -crB --new-file neutron-9.4.2.dev21-backup/neutron/extensions/l3_ext_ha_mode.py neutron-9.4.2.dev21/neutron/extensions/l3_ext_ha_mode.py
*** neutron-9.4.2.dev21-backup/neutron/extensions/l3_ext_ha_mode.py	2017-09-23 11:10:44.000000000 -0700
--- neutron-9.4.2.dev21/neutron/extensions/l3_ext_ha_mode.py	2019-01-28 14:38:19.211746835 -0800
***************
*** 31,65 ****
  }
  
  
- class HAmodeUpdateOfDvrNotSupported(NotImplementedError):
-     message = _("Currently update of HA mode for a distributed router is "
-                 "not supported.")
- 
- 
- class DVRmodeUpdateOfHaNotSupported(NotImplementedError):
-     message = _("Currently update of distributed mode for an HA router is "
-                 "not supported.")
- 
- 
- class HAmodeUpdateOfDvrHaNotSupported(NotImplementedError):
-     message = _("Currently update of HA mode for a DVR/HA router is "
-                 "not supported.")
- 
- 
- class DVRmodeUpdateOfDvrHaNotSupported(NotImplementedError):
-     message = _("Currently update of distributed mode for a DVR/HA router "
-                 "is not supported")
- 
- 
- class UpdateToDvrHamodeNotSupported(NotImplementedError):
-     message = _("Currently updating a router to DVR/HA is not supported.")
- 
- 
- class UpdateToNonDvrHamodeNotSupported(NotImplementedError):
-     message = _("Currently updating a router from DVR/HA to non-DVR "
-                 " non-HA is not supported.")
- 
- 
  class MaxVRIDAllocationTriesReached(exceptions.NeutronException):
      message = _("Failed to allocate a VRID in the network %(network_id)s "
                  "for the router %(router_id)s after %(max_tries)s tries.")
--- 31,36 ----
diff -crB --new-file neutron-9.4.2.dev21-backup/neutron/tests/functional/services/l3_router/test_l3_dvr_ha_router_plugin.py neutron-9.4.2.dev21/neutron/tests/functional/services/l3_router/test_l3_dvr_ha_router_plugin.py
*** neutron-9.4.2.dev21-backup/neutron/tests/functional/services/l3_router/test_l3_dvr_ha_router_plugin.py	2017-09-23 11:10:44.000000000 -0700
--- neutron-9.4.2.dev21/neutron/tests/functional/services/l3_router/test_l3_dvr_ha_router_plugin.py	2019-01-28 14:38:19.211746835 -0800
***************
*** 17,23 ****
  
  from neutron.common import topics
  from neutron.extensions import external_net
- from neutron.extensions import l3_ext_ha_mode
  from neutron.extensions import portbindings
  from neutron.tests.common import helpers
  from neutron.tests.functional.services.l3_router import \
--- 17,22 ----
***************
*** 33,120 ****
              host="standby",
              agent_mode=constants.L3_AGENT_MODE_DVR_SNAT)
  
!     def _create_router(self, distributed=True, ha=True):
          return (super(L3DvrHATestCase, self).
!                 _create_router(distributed=distributed, ha=ha))
  
      def test_update_router_db_cvr_to_dvrha(self):
!         router = self._create_router(distributed=False, ha=False)
!         self.assertRaises(
!             l3_ext_ha_mode.UpdateToDvrHamodeNotSupported,
!             self.l3_plugin.update_router,
              self.context,
              router['id'],
!             {'router': {'distributed': True, 'ha': True}}
!         )
          router = self.l3_plugin.get_router(self.context, router['id'])
!         self.assertFalse(router['distributed'])
!         self.assertFalse(router['ha'])
  
      def test_update_router_db_dvrha_to_cvr(self):
!         router = self._create_router(distributed=True, ha=True)
!         self.assertRaises(
!             l3_ext_ha_mode.DVRmodeUpdateOfDvrHaNotSupported,
!             self.l3_plugin.update_router,
              self.context,
              router['id'],
!             {'router': {'distributed': False, 'ha': False}}
!         )
          router = self.l3_plugin.get_router(self.context, router['id'])
!         self.assertTrue(router['distributed'])
!         self.assertTrue(router['ha'])
  
      def test_update_router_db_dvrha_to_dvr(self):
!         router = self._create_router(distributed=True, ha=True)
          self.l3_plugin.update_router(
              self.context, router['id'], {'router': {'admin_state_up': False}})
!         self.assertRaises(
!             l3_ext_ha_mode.HAmodeUpdateOfDvrHaNotSupported,
!             self.l3_plugin.update_router,
              self.context,
              router['id'],
!             {'router': {'distributed': True, 'ha': False}}
!         )
          router = self.l3_plugin.get_router(self.context, router['id'])
          self.assertTrue(router['distributed'])
!         self.assertTrue(router['ha'])
  
      def test_update_router_db_dvrha_to_cvrha(self):
!         router = self._create_router(distributed=True, ha=True)
!         self.assertRaises(
!             l3_ext_ha_mode.DVRmodeUpdateOfDvrHaNotSupported,
!             self.l3_plugin.update_router,
              self.context,
              router['id'],
!             {'router': {'distributed': False, 'ha': True}}
!         )
          router = self.l3_plugin.get_router(self.context, router['id'])
!         self.assertTrue(router['distributed'])
          self.assertTrue(router['ha'])
  
      def test_update_router_db_dvr_to_dvrha(self):
!         router = self._create_router(distributed=True, ha=False)
!         self.assertRaises(
!             l3_ext_ha_mode.HAmodeUpdateOfDvrNotSupported,
!             self.l3_plugin.update_router,
              self.context,
              router['id'],
!             {'router': {'distributed': True, 'ha': True}}
!         )
          router = self.l3_plugin.get_router(self.context, router['id'])
          self.assertTrue(router['distributed'])
!         self.assertFalse(router['ha'])
  
      def test_update_router_db_cvrha_to_dvrha(self):
!         router = self._create_router(distributed=False, ha=True)
!         self.assertRaises(
!             l3_ext_ha_mode.DVRmodeUpdateOfHaNotSupported,
!             self.l3_plugin.update_router,
              self.context,
              router['id'],
!             {'router': {'distributed': True, 'ha': True}}
!         )
          router = self.l3_plugin.get_router(self.context, router['id'])
!         self.assertFalse(router['distributed'])
          self.assertTrue(router['ha'])
  
      def _assert_router_is_hosted_on_both_dvr_snat_agents(self, router):
--- 32,108 ----
              host="standby",
              agent_mode=constants.L3_AGENT_MODE_DVR_SNAT)
  
!     def _create_router(self, distributed=True, ha=True, admin_state_up=True):
          return (super(L3DvrHATestCase, self).
!                 _create_router(distributed=distributed, ha=ha,
!                                admin_state_up=admin_state_up))
  
      def test_update_router_db_cvr_to_dvrha(self):
!         router = self._create_router(distributed=False, ha=False,
!                                      admin_state_up=False)
!         self.l3_plugin.update_router(
              self.context,
              router['id'],
!             {'router': {'distributed': True, 'ha': True}})
          router = self.l3_plugin.get_router(self.context, router['id'])
!         self.assertTrue(router['distributed'])
!         self.assertTrue(router['ha'])
  
      def test_update_router_db_dvrha_to_cvr(self):
!         router = self._create_router(distributed=True, ha=True,
!                                      admin_state_up=False)
!         self.l3_plugin.update_router(
              self.context,
              router['id'],
!             {'router': {'distributed': False, 'ha': False}})
          router = self.l3_plugin.get_router(self.context, router['id'])
!         self.assertFalse(router['distributed'])
!         self.assertFalse(router['ha'])
  
      def test_update_router_db_dvrha_to_dvr(self):
!         router = self._create_router(distributed=True, ha=True,
!                                      admin_state_up=False)
          self.l3_plugin.update_router(
              self.context, router['id'], {'router': {'admin_state_up': False}})
!         self.l3_plugin.update_router(
              self.context,
              router['id'],
!             {'router': {'distributed': True, 'ha': False}})
          router = self.l3_plugin.get_router(self.context, router['id'])
          self.assertTrue(router['distributed'])
!         self.assertFalse(router['ha'])
  
      def test_update_router_db_dvrha_to_cvrha(self):
!         router = self._create_router(distributed=True, ha=True,
!                                      admin_state_up=False)
!         self.l3_plugin.update_router(
              self.context,
              router['id'],
!             {'router': {'distributed': False, 'ha': True}})
          router = self.l3_plugin.get_router(self.context, router['id'])
!         self.assertFalse(router['distributed'])
          self.assertTrue(router['ha'])
  
      def test_update_router_db_dvr_to_dvrha(self):
!         router = self._create_router(distributed=True, ha=False,
!                                      admin_state_up=False)
!         self.l3_plugin.update_router(
              self.context,
              router['id'],
!             {'router': {'distributed': True, 'ha': True}})
          router = self.l3_plugin.get_router(self.context, router['id'])
          self.assertTrue(router['distributed'])
!         self.assertTrue(router['ha'])
  
      def test_update_router_db_cvrha_to_dvrha(self):
!         router = self._create_router(distributed=False, ha=True,
!                                      admin_state_up=False)
!         self.l3_plugin.update_router(
              self.context,
              router['id'],
!             {'router': {'distributed': True, 'ha': True}})
          router = self.l3_plugin.get_router(self.context, router['id'])
!         self.assertTrue(router['distributed'])
          self.assertTrue(router['ha'])
  
      def _assert_router_is_hosted_on_both_dvr_snat_agents(self, router):
diff -crB --new-file neutron-9.4.2.dev21-backup/neutron/tests/functional/services/l3_router/test_l3_dvr_router_plugin.py neutron-9.4.2.dev21/neutron/tests/functional/services/l3_router/test_l3_dvr_router_plugin.py
*** neutron-9.4.2.dev21-backup/neutron/tests/functional/services/l3_router/test_l3_dvr_router_plugin.py	2019-01-28 10:37:08.233026632 -0800
--- neutron-9.4.2.dev21/neutron/tests/functional/services/l3_router/test_l3_dvr_router_plugin.py	2019-01-28 14:38:19.215746814 -0800
***************
*** 36,44 ****
          self.l3_agent = helpers.register_l3_agent(
              agent_mode=constants.L3_AGENT_MODE_DVR_SNAT)
  
!     def _create_router(self, distributed=True, ha=False):
          return (super(L3DvrTestCase, self).
!                 _create_router(distributed=distributed, ha=ha))
  
      def test_update_router_db_centralized_to_distributed(self):
          router = self._create_router(distributed=False)
--- 36,45 ----
          self.l3_agent = helpers.register_l3_agent(
              agent_mode=constants.L3_AGENT_MODE_DVR_SNAT)
  
!     def _create_router(self, distributed=True, ha=False, admin_state_up=True):
          return (super(L3DvrTestCase, self).
!                 _create_router(distributed=distributed, ha=ha,
!                                admin_state_up=admin_state_up))
  
      def test_update_router_db_centralized_to_distributed(self):
          router = self._create_router(distributed=False)
diff -crB --new-file neutron-9.4.2.dev21-backup/neutron/tests/unit/db/test_l3_dvr_db.py neutron-9.4.2.dev21/neutron/tests/unit/db/test_l3_dvr_db.py
*** neutron-9.4.2.dev21-backup/neutron/tests/unit/db/test_l3_dvr_db.py	2017-09-23 11:10:44.000000000 -0700
--- neutron-9.4.2.dev21/neutron/tests/unit/db/test_l3_dvr_db.py	2019-01-28 14:38:19.215746814 -0800
***************
*** 79,85 ****
              'distributed': True
          }
          router_db = self._create_router(router)
!         self.assertIsNone(self.mixin._validate_router_migration(
              self.ctx, router_db, {'name': 'foo_router_2'}))
  
      def test__validate_router_migration_raise_error(self):
--- 79,85 ----
              'distributed': True
          }
          router_db = self._create_router(router)
!         self.assertFalse(self.mixin._validate_router_migration(
              self.ctx, router_db, {'name': 'foo_router_2'}))
  
      def test__validate_router_migration_raise_error(self):
diff -crB --new-file neutron-9.4.2.dev21-backup/neutron/tests/unit/db/test_l3_hamode_db.py neutron-9.4.2.dev21/neutron/tests/unit/db/test_l3_hamode_db.py
*** neutron-9.4.2.dev21-backup/neutron/tests/unit/db/test_l3_hamode_db.py	2019-01-28 10:37:08.265026647 -0800
--- neutron-9.4.2.dev21/neutron/tests/unit/db/test_l3_hamode_db.py	2019-01-28 14:38:19.215746814 -0800
***************
*** 352,413 ****
          router = self._create_router(ha=True, admin_state_up=False,
                                       distributed=False)
          self.assertTrue(router['ha'])
!         self.assertRaises(l3_ext_ha_mode.DVRmodeUpdateOfHaNotSupported,
!                           self._update_router,
!                           router['id'],
!                           ha=True,
!                           distributed=True)
  
      def test_migrate_ha_router_to_distributed_and_not_ha(self):
          router = self._create_router(ha=True, admin_state_up=False,
                                       distributed=False)
          self.assertTrue(router['ha'])
!         self.assertRaises(l3_ext_ha_mode.DVRmodeUpdateOfHaNotSupported,
!                           self._update_router,
!                           router['id'],
!                           ha=False,
!                           distributed=True)
  
      def test_migrate_dvr_router_to_ha_and_not_dvr(self):
          router = self._create_router(ha=False, admin_state_up=False,
                                       distributed=True)
          self.assertTrue(router['distributed'])
!         self.assertRaises(l3_ext_ha_mode.HAmodeUpdateOfDvrNotSupported,
!                           self._update_router,
!                           router['id'],
!                           ha=True,
!                           distributed=True)
  
      def test_migrate_dvr_router_to_ha_and_dvr(self):
          router = self._create_router(ha=False, admin_state_up=False,
                                       distributed=True)
          self.assertTrue(router['distributed'])
!         self.assertRaises(l3_ext_ha_mode.HAmodeUpdateOfDvrNotSupported,
!                           self._update_router,
!                           router['id'],
!                           ha=True,
!                           distributed=True)
  
      def test_migrate_distributed_router_to_ha(self):
!         router = self._create_router(ha=False, distributed=True)
          self.assertFalse(router['ha'])
          self.assertTrue(router['distributed'])
  
!         self.assertRaises(l3_ext_ha_mode.HAmodeUpdateOfDvrNotSupported,
!                           self._update_router,
!                           router['id'],
!                           ha=True)
  
      def test_migrate_legacy_router_to_distributed_and_ha(self):
!         router = self._create_router(ha=False, distributed=False)
          self.assertFalse(router['ha'])
          self.assertFalse(router['distributed'])
  
!         self.assertRaises(l3_ext_ha_mode.UpdateToDvrHamodeNotSupported,
!                           self._update_router,
!                           router['id'],
!                           ha=True,
!                           distributed=True)
  
      def test_unbind_ha_router(self):
          router = self._create_router()
--- 352,415 ----
          router = self._create_router(ha=True, admin_state_up=False,
                                       distributed=False)
          self.assertTrue(router['ha'])
!         
!         after_update = self._update_router(router['id'],
!                                            ha=True, distributed=True)
!         self.assertTrue(after_update.extra_attributes.ha)
!         self.assertTrue(after_update.extra_attributes.distributed)
  
      def test_migrate_ha_router_to_distributed_and_not_ha(self):
          router = self._create_router(ha=True, admin_state_up=False,
                                       distributed=False)
          self.assertTrue(router['ha'])
!         
!         after_update = self._update_router(router['id'],
!                                            ha=False, distributed=True)
!         self.assertFalse(after_update.extra_attributes.ha)
!         self.assertTrue(after_update.extra_attributes.distributed)
! 
  
      def test_migrate_dvr_router_to_ha_and_not_dvr(self):
          router = self._create_router(ha=False, admin_state_up=False,
                                       distributed=True)
          self.assertTrue(router['distributed'])
!         
!         after_update = self._update_router(router['id'],
!                                            ha=True, distributed=True)
!         self.assertTrue(after_update.extra_attributes.ha)
!         self.assertFalse(after_update.extra_attributes.distributed)
  
      def test_migrate_dvr_router_to_ha_and_dvr(self):
          router = self._create_router(ha=False, admin_state_up=False,
                                       distributed=True)
          self.assertTrue(router['distributed'])
!         
!         after_update = self._update_router(router['id'],
!                                            ha=True, distributed=True)
!         self.assertTrue(after_update.extra_attributes.ha)
!         self.assertTrue(after_update.extra_attributes.distributed)
  
      def test_migrate_distributed_router_to_ha(self):
!         router = self._create_router(ha=False, admin_state_up=False,
!                                      distributed=True)
          self.assertFalse(router['ha'])
          self.assertTrue(router['distributed'])
  
!         after_update = self._update_router(router['id'],
!                                            ha=True, distributed=False)
!         self.assertTrue(after_update.extra_attributes.ha)
!         self.assertFalse(after_update.extra_attributes.distributed)
  
      def test_migrate_legacy_router_to_distributed_and_ha(self):
!         router = self._create_router(ha=False, admin_state_up=False,
!                                      distributed=False)
          self.assertFalse(router['ha'])
          self.assertFalse(router['distributed'])
  
!         after_update = self._update_router(router['id'],
!                                            ha=True, distributed=True)
!         self.assertTrue(after_update.extra_attributes.ha)
!         self.assertTrue(after_update.extra_attributes.distributed)
  
      def test_unbind_ha_router(self):
          router = self._create_router()
