Mark subnet deletion state during subnet deletion

1. What is the problem
As reported in the bug page, local subnet will be recreated
after central subnet is deleted

2. What is the solution for the problem
The reason for the recreation is that DhcpAgentNotifyAPI subscribe
the subnet deletion event and will call get_network during subnet
deletion, get_network will call _ensure_subnet to create the subnet.
So we need a way to distinguish the call from API and callback.

A dict on_subnet_delete is added to local plugin in this patch.
In delete_subnet, before calling real core pluing's delete_subnet
method, we first add a new item (request_id, True) to this dict.
After the calling, this item is removed. So in get_network, we can
check whether the dict contains the request_id, if so, we know
that we are in the subnet deletion stage, then we don't call
_ensure_subnet.

3. What features need to be implemented to the Tricircle to
realize the solution
No new features

Change-Id: Ie79460aa763918be7c522263d9865847fc0da828
Closes-Bug: #1680757
This commit is contained in:
zhiyuan_cai 2017-04-14 11:41:56 +08:00
parent 50067c3b4b
commit af2cce9364
2 changed files with 34 additions and 2 deletions

View File

@ -73,6 +73,7 @@ class TricirclePlugin(plugin.Ml2Plugin):
self.neutron_handle.endpoint_url = \
cfg.CONF.tricircle.central_neutron_url
self.on_trunk_create = {}
self.on_subnet_delete = {}
def start_rpc_listeners(self):
return self.core_plugin.start_rpc_listeners()
@ -86,6 +87,22 @@ class TricirclePlugin(plugin.Ml2Plugin):
def rpc_state_report_workers_supported(self):
return self.core_plugin.rpc_state_report_workers_supported()
def _start_subnet_delete(self, context):
if context.request_id:
LOG.debug('subnet delete start for ' + context.request_id)
self.on_subnet_delete[context.request_id] = True
def _end_subnet_delete(self, context):
if context.request_id:
LOG.debug('subnet delete end for ' + context.request_id)
self.on_subnet_delete.pop(context.request_id, None)
def _in_subnet_delete(self, context):
if context.request_id:
LOG.debug('check subnet delete state for ' + context.request_id)
return context.request_id in self.on_subnet_delete
return False
@staticmethod
def _adapt_network_body(network):
network_type = network.get(provider_net.NETWORK_TYPE)
@ -230,8 +247,13 @@ class TricirclePlugin(plugin.Ml2Plugin):
def get_network(self, context, _id, fields=None):
try:
b_network = self.core_plugin.get_network(context, _id)
subnet_ids = self._ensure_subnet(context, b_network, False)
if not self._in_subnet_delete(context):
subnet_ids = self._ensure_subnet(context, b_network, False)
else:
subnet_ids = []
except q_exceptions.NotFound:
if self._in_subnet_delete(context):
raise
t_ctx = t_context.get_context_from_neutron_context(context)
if self._skip_non_api_query(t_ctx):
raise q_exceptions.NetworkNotFound(net_id=_id)
@ -386,6 +408,15 @@ class TricirclePlugin(plugin.Ml2Plugin):
b_subnets.append(self._fields(b_subnet, fields))
return b_subnets
def delete_subnet(self, context, _id):
self._start_subnet_delete(context)
try:
self.core_plugin.delete_subnet(context, _id)
except Exception:
raise
finally:
self._end_subnet_delete(context)
def update_subnet(self, context, _id, subnet):
"""update bottom subnet

View File

@ -164,7 +164,7 @@ class FakeContext(object):
self.session = FakeSession()
self.auth_token = 'token'
self.project_id = ''
self.request_id = 'abcdefg'
self.request_id = 'req-' + uuidutils.generate_uuid()
def fake_get_trunk_plugin(trunk):
@ -259,6 +259,7 @@ class FakePlugin(plugin.TricirclePlugin):
self.core_plugin = FakeCorePlugin()
self.neutron_handle = FakeNeutronHandle()
self.on_trunk_create = {}
self.on_subnet_delete = {}
class PluginTest(unittest.TestCase):