From 70112ea9941b92aa98e32c0c37f0208877953557 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Fri, 20 Aug 2010 13:05:46 -0700 Subject: fix concurrency issue with multiple instances getting the same ip --- nova/network/model.py | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/nova/network/model.py b/nova/network/model.py index 6e4fcc47e..6c12836b7 100644 --- a/nova/network/model.py +++ b/nova/network/model.py @@ -231,7 +231,8 @@ class BaseNetwork(datastore.BasicModel): self.network_id = network_id self.network_str = network_str super(BaseNetwork, self).__init__() - self.save() + if self.is_new_record(): + self._create_assigned_set() @property def network(self): @@ -278,6 +279,16 @@ class BaseNetwork(datastore.BasicModel): """Remove a host from the datastore""" self.address_class(ip_address).destroy() + def _create_assigned_set(self): + for idx in range(self.num_bottom_reserved_ips, + len(self.network) - self.num_top_reserved_ips): + redis = datastore.Redis.instance() + redis.sadd(self._available_key, str(self.network[idx])) + + @property + def _available_key(self): + return 'available:%s' % self.identifier + @property def assigned(self): """Returns a list of all assigned addresses""" @@ -294,15 +305,6 @@ class BaseNetwork(datastore.BasicModel): return self.address_class(ip_address) return None - @property - def available(self): - """Returns a list of all available addresses in the network""" - for idx in range(self.num_bottom_reserved_ips, - len(self.network) - self.num_top_reserved_ips): - address = str(self.network[idx]) - if not address in self.assigned: - yield address - @property def num_bottom_reserved_ips(self): """Returns number of ips reserved at the bottom of the range""" @@ -315,13 +317,14 @@ class BaseNetwork(datastore.BasicModel): def allocate_ip(self, user_id, project_id, mac, hostname=None): """Allocates an ip to a mac address""" - for address in self.available: - logging.debug("Allocating IP %s to %s", address, project_id) - self._add_host(user_id, project_id, address, mac, hostname) - self.express(address=address) - return address - raise exception.NoMoreAddresses("Project %s with network %s" % - (project_id, str(self.network))) + address = datastore.Redis.instance().spop(self._available_key) + if not address: + raise exception.NoMoreAddresses("Project %s with network %s" % + (project_id, str(self.network))) + logging.debug("Allocating IP %s to %s", address, project_id) + self._add_host(user_id, project_id, address, mac, hostname) + self.express(address=address) + return address def lease_ip(self, ip_str): """Called when DHCP lease is activated""" @@ -342,6 +345,7 @@ class BaseNetwork(datastore.BasicModel): logging.debug("Releasing IP %s", ip_str) self._rem_host(ip_str) self.deexpress(address=ip_str) + datastore.Redis.instance().sadd(self._available_key, ip_str) def deallocate_ip(self, ip_str): """Deallocates an allocated ip""" @@ -400,7 +404,6 @@ class BridgedNetwork(BaseNetwork): def __init__(self, *args, **kwargs): super(BridgedNetwork, self).__init__(*args, **kwargs) self['bridge_dev'] = FLAGS.bridge_dev - self.save() def express(self, address=None): super(BridgedNetwork, self).express(address=address) -- cgit