def test_bump_revision(self): db_rev.create_initial_revision(self.net['id'], constants.TYPE_NETWORKS, self.session) self.net['revision_number'] = 123 db_rev.bump_revision(self.net, constants.TYPE_NETWORKS) row = self.get_revision_row(self.net['id']) self.assertEqual(123, row.revision_number)
def test_bump_revision_row_not_found(self, mock_log): self.net['revision_number'] = 123 db_rev.bump_revision(self.net, constants.TYPE_NETWORKS) # Assert the revision number wasn't bumped row = self.get_revision_row(self.net['id']) self.assertEqual(123, row.revision_number) self.assertIn('No revision row found for', mock_log.call_args[0][0])
def remove_router_interface(self, context, router_id, interface_info): router_interface_info = \ super(OVNL3RouterPlugin, self).remove_router_interface( context, router_id, interface_info) router = self.get_router(context, router_id) port_id = router_interface_info['port_id'] multi_prefix = False port_removed = False try: port = self._plugin.get_port(context, port_id) # The router interface port still exists, call ovn to update it. self._ovn_client.update_router_port(port, bump_db_rev=False) multi_prefix = True except n_exc.PortNotFound: # The router interface port doesn't exist any more, # we will call ovn to delete it once we remove the snat # rules in the router itself if we have to port_removed = True if not router.get(l3.EXTERNAL_GW_INFO): if port_removed: self._ovn_client.delete_router_port(port_id, router_id) return router_interface_info try: cidr = None if multi_prefix: subnet = self._plugin.get_subnet(context, interface_info['subnet_id']) if subnet['ip_version'] == 4: cidr = subnet['cidr'] else: subnet_ids = router_interface_info.get('subnet_ids') for subnet_id in subnet_ids: subnet = self._plugin.get_subnet(context, subnet_id) if subnet['ip_version'] == 4: cidr = subnet['cidr'] break if utils.is_snat_enabled(router) and cidr: self._ovn_client.update_nat_rules(router, networks=[cidr], enable_snat=False) except Exception: with excutils.save_and_reraise_exception(): super(OVNL3RouterPlugin, self).add_router_interface(context, router_id, interface_info) LOG.error('Error is deleting snat') # NOTE(mangelajo): If the port doesn't exist anymore, we delete the # router port as the last operation and update the revision database # to ensure consistency if port_removed: self._ovn_client.delete_router_port(port_id, router_id) else: # otherwise, we just update the revision database db_rev.bump_revision(port, ovn_const.TYPE_ROUTER_PORTS) return router_interface_info
def test_bump_older_revision(self): db_rev.create_initial_revision(self.net['id'], constants.TYPE_NETWORKS, self.session, revision_number=123) self.net['revision_number'] = 1 db_rev.bump_revision(self.net, constants.TYPE_NETWORKS) # Assert the revision number wasn't bumped row = db_rev.get_revision_row(self.net['id']) self.assertEqual(123, row.revision_number)
def add_router_interface(self, context, router_id, interface_info): router_interface_info = \ super(OVNL3RouterPlugin, self).add_router_interface( context, router_id, interface_info) port = self._plugin.get_port(context, router_interface_info['port_id']) multi_prefix = False if (len(router_interface_info['subnet_ids']) == 1 and len(port['fixed_ips']) > 1): # NOTE(lizk) It's adding a subnet onto an already existing router # interface port, try to update lrouter port 'networks' column. self._ovn_client.update_router_port(port, bump_db_rev=False) multi_prefix = True else: self._ovn_client.create_router_port(router_id, port) router = self.get_router(context, router_id) if not router.get(l3.EXTERNAL_GW_INFO): db_rev.bump_revision(port, ovn_const.TYPE_ROUTER_PORTS) return router_interface_info cidr = None for fixed_ip in port['fixed_ips']: subnet = self._plugin.get_subnet(context, fixed_ip['subnet_id']) if multi_prefix: if 'subnet_id' in interface_info: if subnet['id'] is not interface_info['subnet_id']: continue if subnet['ip_version'] == 4: cidr = subnet['cidr'] if utils.is_snat_enabled(router) and cidr: try: self._ovn_client.update_nat_rules(router, networks=[cidr], enable_snat=True) except Exception: with excutils.save_and_reraise_exception(): self._ovn.delete_lrouter_port( utils.ovn_lrouter_port_name(port['id']), utils.ovn_name(router_id)).execute(check_error=True) super(OVNL3RouterPlugin, self).remove_router_interface( context, router_id, router_interface_info) LOG.error( 'Error updating snat for subnet %(subnet)s in ' 'router %(router)s', { 'subnet': router_interface_info['subnet_id'], 'router': router_id }) db_rev.bump_revision(port, ovn_const.TYPE_ROUTER_PORTS) return router_interface_info
def _fix_create_update(self, row): res_map = self._resources_func_map[row.resource_type] admin_context = n_context.get_admin_context() try: # Get the latest version of the resource in Neutron DB n_obj = res_map['neutron_get'](admin_context, row.resource_uuid) except n_exc.NotFound: LOG.warning( 'Skip fixing resource %(res_uuid)s (type: ' '%(res_type)s). Resource does not exist in Neutron ' 'database anymore', { 'res_uuid': row.resource_uuid, 'res_type': row.resource_type }) return ovn_obj = res_map['ovn_get'](row.resource_uuid) if not ovn_obj: res_map['ovn_create'](n_obj) else: if row.resource_type == ovn_const.TYPE_SECURITY_GROUP_RULES: LOG.error( "SG rule %s found with a revision number while " "this resource doesn't support updates", row.resource_uuid) elif row.resource_type == ovn_const.TYPE_SECURITY_GROUPS: # In OVN, we don't care about updates to security groups, # so just bump the revision number to whatever it's # supposed to be. db_rev.bump_revision(n_obj, row.resource_type) else: ext_ids = getattr(ovn_obj, 'external_ids', {}) ovn_revision = int( ext_ids.get(ovn_const.OVN_REV_NUM_EXT_ID_KEY, -1)) # If the resource exist in the OVN DB but the revision # number is different from Neutron DB, updated it. if ovn_revision != n_obj['revision_number']: res_map['ovn_update'](n_obj) else: # If the resource exist and the revision number # is equal on both databases just bump the revision on # the cache table. db_rev.bump_revision(n_obj, row.resource_type)
def _fix_create_update_network(self, row): # Get the latest version of the resource in Neutron DB admin_context = n_context.get_admin_context() n_db_obj = self._ovn_client._plugin.get_network( admin_context, row.resource_uuid) ovn_net = self._nb_idl.get_lswitch(utils.ovn_name(row.resource_uuid)) if not ovn_net: # If the resource doesn't exist in the OVN DB, create it. self._ovn_client.create_network(n_db_obj) else: ext_ids = getattr(ovn_net, 'external_ids', {}) ovn_revision = int( ext_ids.get(ovn_const.OVN_REV_NUM_EXT_ID_KEY, -1)) # If the resource exist in the OVN DB but the revision # number is different from Neutron DB, updated it. if ovn_revision != n_db_obj['revision_number']: self._ovn_client.update_network(n_db_obj) else: # If the resource exist and the revision number # is equal on both databases just bump the revision on # the cache table. db_rev.bump_revision(n_db_obj, ovn_const.TYPE_NETWORKS)
def _update_security_group(self, resource, event, trigger, security_group, **kwargs): # OVN doesn't care about updates to security groups, only if they # exist or not. We are bumping the revision number here so it # doesn't show as inconsistent to the maintenance periodic task db_rev.bump_revision(security_group, ovn_const.TYPE_SECURITY_GROUPS)