Revision 660b9f3b snf-cyclades-app/synnefo/api/util.py
b/snf-cyclades-app/synnefo/api/util.py | ||
---|---|---|
284 | 284 |
|
285 | 285 |
|
286 | 286 |
def allocate_public_address(backend): |
287 |
"""Allocate a public IP for a vm.""" |
|
288 |
for network in backend_public_networks(backend): |
|
289 |
try: |
|
290 |
address = get_network_free_address(network) |
|
291 |
except faults.OverLimit: |
|
292 |
pass |
|
293 |
else: |
|
294 |
return (network, address) |
|
295 |
return (None, None) |
|
296 |
|
|
297 |
|
|
298 |
def get_public_ip(backend): |
|
299 |
"""Reserve an IP from a public network. |
|
300 |
|
|
301 |
This method should run inside a transaction. |
|
302 |
|
|
303 |
""" |
|
304 |
|
|
287 |
"""Get a public IP for any available network of a backend.""" |
|
305 | 288 |
# Guarantee exclusive access to backend, because accessing the IP pools of |
306 | 289 |
# the backend networks may result in a deadlock with backend allocator |
307 | 290 |
# which also checks that backend networks have a free IP. |
308 | 291 |
backend = Backend.objects.select_for_update().get(id=backend.id) |
309 |
|
|
310 |
address = None |
|
311 |
if settings.PUBLIC_USE_POOL: |
|
312 |
(network, address) = allocate_public_address(backend) |
|
313 |
else: |
|
314 |
for net in list(backend_public_networks(backend)): |
|
315 |
pool = net.get_pool() |
|
316 |
if not pool.empty(): |
|
317 |
address = 'pool' |
|
318 |
network = net |
|
319 |
break |
|
320 |
if address is None: |
|
321 |
log.error("Public networks of backend %s are full", backend) |
|
322 |
raise faults.OverLimit("Can not allocate IP for new machine." |
|
323 |
" Public networks are full.") |
|
324 |
return (network, address) |
|
292 |
public_networks = backend_public_networks(backend) |
|
293 |
return get_free_ip(public_networks) |
|
325 | 294 |
|
326 | 295 |
|
327 | 296 |
def backend_public_networks(backend): |
... | ... | |
331 | 300 |
to the specified backend. |
332 | 301 |
|
333 | 302 |
""" |
334 |
for network in Network.objects.filter(public=True, deleted=False, |
|
335 |
drained=False): |
|
336 |
if BackendNetwork.objects.filter(network=network, |
|
337 |
backend=backend).exists(): |
|
338 |
yield network |
|
303 |
bnets = BackendNetwork.objects.filter(backend=backend, |
|
304 |
network__public=True, |
|
305 |
network__deleted=False, |
|
306 |
network__drained=False) |
|
307 |
return [b.network for b in bnets] |
|
308 |
|
|
309 |
|
|
310 |
def get_free_ip(networks): |
|
311 |
for network in networks: |
|
312 |
try: |
|
313 |
address = get_network_free_address(network) |
|
314 |
return network, address |
|
315 |
except faults.OverLimit: |
|
316 |
pass |
|
317 |
msg = "Can not allocate public IP. Public networks are full." |
|
318 |
log.error(msg) |
|
319 |
raise faults.OverLimit(msg) |
|
339 | 320 |
|
340 | 321 |
|
341 | 322 |
def get_network_free_address(network): |
... | ... | |
346 | 327 |
address = pool.get() |
347 | 328 |
except EmptyPool: |
348 | 329 |
raise faults.OverLimit("Network %s is full." % network.backend_id) |
349 |
address = None |
|
350 | 330 |
pool.save() |
351 | 331 |
return address |
352 | 332 |
|
353 | 333 |
|
354 |
def allocate_public_ip(networks=None): |
|
355 |
"""Allocate an IP address from public networks.""" |
|
356 |
if networks is None: |
|
357 |
networks = Network.objects.select_for_update().filter(public=True, |
|
358 |
deleted=False) |
|
359 |
for network in networks: |
|
360 |
try: |
|
361 |
address = get_network_free_address(network) |
|
362 |
except: |
|
363 |
pass |
|
364 |
else: |
|
365 |
return network, address |
|
366 |
msg = "Can not allocate public IP. Public networks are full." |
|
367 |
log.error(msg) |
|
368 |
raise faults.OverLimit(msg) |
|
369 |
|
|
370 |
|
|
371 | 334 |
def get_nic(machine, network): |
372 | 335 |
try: |
373 | 336 |
return NetworkInterface.objects.get(machine=machine, network=network) |
Also available in: Unified diff