Mutex protect internal/external network detection

We have stamp variables to prevent double processing the events as a
mechanism of caching, but they're not mutex protected, so we can also
have a race-condition thundering herd potential in multi-threaded code
like nodepool. Add mutex protection around it - but just use one mutex
for the two, because we can further refactor this to make a single pass
through the network list and sort the networks from that.

Change-Id: I74d8b279105e8d9e1a2c138da90e31485e123744
This commit is contained in:
Monty Taylor 2016-03-29 11:31:35 -07:00
parent 1853a54001
commit 75ee8f967d
1 changed files with 39 additions and 31 deletions

View File

@ -182,6 +182,8 @@ class OpenStackCloud(object):
self._servers_time = 0
self._servers_lock = threading.Lock()
self._networks_lock = threading.Lock()
cache_expiration_time = int(cloud_config.get_cache_expiration_time())
cache_class = cloud_config.get_cache_class()
cache_arguments = cloud_config.get_cache_arguments()
@ -1396,22 +1398,25 @@ class OpenStackCloud(object):
:returns: A list of network dicts if one is found
"""
_all_networks = self._get_network(
self._external_network_name_or_id,
self.use_external_network,
self._external_networks,
self._external_network_stamp,
filters=None)
# Filter locally because we have an or condition
_external_networks = []
for network in _all_networks:
if (('router:external' in network
and network['router:external']) or
'provider:network_type' in network):
_external_networks.append(network)
# TODO(mordred): This needs to be mutex protected
self._external_networks = _external_networks
self._external_network_stamp = True
if self._networks_lock.acquire():
try:
_all_networks = self._get_network(
self._external_network_name_or_id,
self.use_external_network,
self._external_networks,
self._external_network_stamp,
filters=None)
# Filter locally because we have an or condition
_external_networks = []
for network in _all_networks:
if (('router:external' in network
and network['router:external']) or
'provider:network_type' in network):
_external_networks.append(network)
self._external_networks = _external_networks
self._external_network_stamp = True
finally:
self._networks_lock.release()
return self._external_networks
def get_internal_networks(self):
@ -1420,21 +1425,24 @@ class OpenStackCloud(object):
:returns: A list of network dicts if one is found
"""
# Just router:external False is not enough.
_all_networks = self._get_network(
self._internal_network_name_or_id,
self.use_internal_network,
self._internal_networks,
self._internal_network_stamp,
filters={
'router:external': False,
})
_internal_networks = []
for network in _all_networks:
if 'provider:network_type' not in network:
_internal_networks.append(network)
# TODO(mordred): This needs to be mutex protected
self._internal_networks = _internal_networks
self._internal_network_stamp = True
if self._networks_lock.acquire():
try:
_all_networks = self._get_network(
self._internal_network_name_or_id,
self.use_internal_network,
self._internal_networks,
self._internal_network_stamp,
filters={
'router:external': False,
})
_internal_networks = []
for network in _all_networks:
if 'provider:network_type' not in network:
_internal_networks.append(network)
self._internal_networks = _internal_networks
self._internal_network_stamp = True
finally:
self._networks_lock.release()
return self._internal_networks
def get_keypair(self, name_or_id, filters=None):