Revision 03992c72 snf-cyclades-app/synnefo/db/models.py
b/snf-cyclades-app/synnefo/db/models.py | ||
---|---|---|
39 | 39 |
from hashlib import sha1 |
40 | 40 |
from synnefo.api.faults import ServiceUnavailable |
41 | 41 |
from synnefo.util.rapi import GanetiRapiClient |
42 |
from synnefo.logic.ippool import IPPool |
|
43 | 42 |
from synnefo import settings as snf_settings |
44 | 43 |
from aes_encrypt import encrypt_db_charfield, decrypt_db_charfield |
45 | 44 |
|
46 | 45 |
from synnefo.db.managers import ForUpdateManager, ProtectedDeleteManager |
46 |
from synnefo.db import pools |
|
47 | 47 |
|
48 | 48 |
BACKEND_CLIENTS = {} # {hash:Backend client} |
49 | 49 |
BACKEND_HASHES = {} # {Backend.id:hash} |
... | ... | |
537 | 537 |
self.deleted = True |
538 | 538 |
|
539 | 539 |
if self.mac_prefix: |
540 |
MacPrefixPool.set_available(self.mac_prefix) |
|
540 |
mac_pool = MacPrefixPoolTable.get_pool() |
|
541 |
mac_pool.put(self.mac_prefix) |
|
542 |
mac_pool.save() |
|
541 | 543 |
|
542 | 544 |
if self.link and self.type == 'PRIVATE_VLAN': |
543 |
BridgePool.set_available(self.link) |
|
545 |
bridge_pool = BridgePoolTable.get_pool() |
|
546 |
bridge_pool.put(self.link) |
|
547 |
bridge_pool.save() |
|
544 | 548 |
|
545 | 549 |
self.save() |
546 | 550 |
|
... | ... | |
548 | 552 |
super(Network, self).__init__(*args, **kwargs) |
549 | 553 |
if not self.mac_prefix: |
550 | 554 |
# Allocate a MAC prefix for just created Network instances |
551 |
mac_prefix = MacPrefixPool.get_available().value |
|
555 |
mac_pool = MacPrefixPoolTable.get_pool() |
|
556 |
mac_prefix = mac_pool.get() |
|
557 |
mac_pool.save() |
|
552 | 558 |
self.mac_prefix = mac_prefix |
553 | 559 |
|
554 | 560 |
def create_backend_network(self, backend=None): |
... | ... | |
563 | 569 |
if self.ip_pool: |
564 | 570 |
return self.ip_pool |
565 | 571 |
else: |
566 |
self.ip_pool = IPPool(self) |
|
572 |
self.ip_pool = pools.IPPool(self)
|
|
567 | 573 |
return self.ip_pool |
568 | 574 |
|
569 | 575 |
def reserve_address(self, address, pool=None): |
... | ... | |
681 | 687 |
return '%s@%s' % (self.machine.name, self.network.name) |
682 | 688 |
|
683 | 689 |
|
684 |
class Pool(models.Model): |
|
685 |
""" Abstract class modeling a generic pool of resources |
|
690 |
class PoolTable(models.Model): |
|
691 |
available_map = models.TextField(default="", null=False) |
|
692 |
reserved_map = models.TextField(default="", null=False) |
|
693 |
size = models.IntegerField(null=False) |
|
686 | 694 |
|
687 |
Subclasses must implement 'value_from_index' method which |
|
688 |
converts and index(Integer) to an arbitrary Char value. |
|
689 |
|
|
690 |
Methods of this class must be invoked inside a transaction |
|
691 |
to ensure consistency of the pool. |
|
692 |
""" |
|
693 |
available = models.BooleanField(default=True, null=False) |
|
694 |
index = models.IntegerField(null=False, unique=True) |
|
695 |
value = models.CharField(max_length=128, null=False, unique=True) |
|
696 |
max_index = 0 |
|
695 |
# Optional Fields |
|
696 |
base = models.CharField(null=True, max_length=32) |
|
697 |
offset = models.IntegerField(null=True) |
|
697 | 698 |
|
698 | 699 |
objects = ForUpdateManager() |
699 | 700 |
|
700 | 701 |
class Meta: |
701 | 702 |
abstract = True |
702 |
ordering = ['index'] |
|
703 | 703 |
|
704 | 704 |
@classmethod |
705 |
def get_available(cls):
|
|
705 |
def get_pool(cls):
|
|
706 | 706 |
try: |
707 |
entry = cls.objects.select_for_update().filter(available=True)[0] |
|
708 |
entry.available = False |
|
709 |
entry.save() |
|
710 |
return entry |
|
707 |
pool_row = cls.objects.select_for_update().all()[0] |
|
708 |
return pool_row.pool |
|
711 | 709 |
except IndexError: |
712 |
return cls.generate_new() |
|
713 |
|
|
714 |
@classmethod |
|
715 |
def generate_new(cls): |
|
716 |
try: |
|
717 |
last = cls.objects.order_by('-index')[0] |
|
718 |
index = last.index + 1 |
|
719 |
except IndexError: |
|
720 |
index = 1 |
|
721 |
|
|
722 |
if index <= cls.max_index: |
|
723 |
return cls.objects.create(index=index, |
|
724 |
value=cls.value_from_index(index), |
|
725 |
available=False) |
|
726 |
|
|
727 |
raise Pool.PoolExhausted() |
|
728 |
|
|
729 |
@classmethod |
|
730 |
def set_available(cls, value): |
|
731 |
entry = cls.objects.select_for_update().get(value=value) |
|
732 |
entry.available = True |
|
733 |
entry.save() |
|
734 |
|
|
735 |
class PoolExhausted(Exception): |
|
736 |
pass |
|
737 |
|
|
738 |
|
|
739 |
class BridgePool(Pool): |
|
740 |
max_index = snf_settings.PRIVATE_PHYSICAL_VLAN_MAX_NUMBER |
|
741 |
|
|
742 |
@staticmethod |
|
743 |
def value_from_index(index): |
|
744 |
return snf_settings.PRIVATE_PHYSICAL_VLAN_BRIDGE_PREFIX + str(index) |
|
710 |
raise pools.EmptyPool |
|
745 | 711 |
|
712 |
@property |
|
713 |
def pool(self): |
|
714 |
return self.manager(self) |
|
746 | 715 |
|
747 |
class MacPrefixPool(Pool): |
|
748 |
max_index = snf_settings.MAC_POOL_LIMIT |
|
749 | 716 |
|
750 |
@staticmethod |
|
751 |
def value_from_index(index): |
|
752 |
"""Convert number to mac prefix |
|
717 |
class BridgePoolTable(PoolTable): |
|
718 |
manager = pools.BridgePool |
|
753 | 719 |
|
754 |
""" |
|
755 |
base = snf_settings.MAC_POOL_BASE |
|
756 |
a = hex(int(base.replace(":", ""), 16) + index).replace("0x", '') |
|
757 |
mac_prefix = ":".join([a[x:x + 2] for x in xrange(0, len(a), 2)]) |
|
758 |
return mac_prefix |
|
720 |
class MacPrefixPoolTable(PoolTable): |
|
721 |
manager = pools.MacPrefixPool |
Also available in: Unified diff