Revision 3165f027 snf-cyclades-app/synnefo/db/models.py

b/snf-cyclades-app/synnefo/db/models.py
32 32
from django.conf import settings
33 33
from django.db import models
34 34
from django.db import IntegrityError
35
from django.db import transaction
36

  
37
import utils
35 38

  
36 39
from hashlib import sha1
37 40
from synnefo.api.faults import ServiceUnavailable
......
124 127
                                null=True)
125 128
    # Sha1 is up to 40 characters long
126 129
    hash = models.CharField('Hash', max_length=40, editable=False, null=False)
130
    # Unique index of the Backend, used for the mac-prefixes of the
131
    # BackendNetworks
132
    index = models.PositiveIntegerField('Index', null=False, unique=True,
133
                                        default=0)
127 134
    drained = models.BooleanField('Drained', default=False, null=False)
128 135
    offline = models.BooleanField('Offline', default=False, null=False)
129 136
    # Last refresh of backend resources
......
192 199
            self.virtual_machines.all().backend = None
193 200
            super(Backend, self).delete(*args, **kwargs)
194 201

  
202
    def __init__(self, *args, **kwargs):
203
        super(Backend, self).__init__(*args, **kwargs)
204
        if not self.pk:
205
            # Generate a unique index for the Backend
206
            indexes = Backend.objects.all().values_list('index', flat=True)
207
            first_free = [x for x in xrange(0, 16) if x not in indexes][0]
208
            self.index = first_free
209

  
195 210

  
196 211
# A backend job may be in one of the following possible states
197 212
BACKEND_STATUSES = (
......
437 452
    type = models.CharField(choices=NETWORK_TYPES, max_length=50,
438 453
                            default='PRIVATE_PHYSICAL_VLAN')
439 454
    link = models.CharField('Network Link', max_length=128, null=True)
440
    mac_prefix = models.CharField('MAC Prefix', max_length=32, null=True)
455
    mac_prefix = models.CharField('MAC Prefix', max_length=32, null=False)
441 456
    public = models.BooleanField(default=False)
442 457
    created = models.DateTimeField(auto_now_add=True)
443 458
    updated = models.DateTimeField(auto_now=True)
......
495 510
    def __unicode__(self):
496 511
        return self.name
497 512

  
513
    @transaction.commit_on_success
498 514
    def update_state(self):
499 515
        """Update state of the Network.
500 516

  
......
528 544

  
529 545
        self.save()
530 546

  
547
    def __init__(self, *args, **kwargs):
548
        super(Network, self).__init__(*args, **kwargs)
549
        if not self.mac_prefix:
550
            # Allocate a MAC prefix for just created Network instances
551
            mac_prefix = MacPrefixPool.get_available().value
552
            self.mac_prefix = mac_prefix
553

  
531 554
    def save(self, *args, **kwargs):
532 555
        pk = self.pk
533 556
        super(Network, self).save(*args, **kwargs)
......
596 619
    created = models.DateTimeField(auto_now_add=True)
597 620
    updated = models.DateTimeField(auto_now=True)
598 621
    deleted = models.BooleanField('Deleted', default=False)
622
    mac_prefix = models.CharField('MAC Prefix', max_length=32, null=False)
599 623
    operstate = models.CharField(choices=OPER_STATES, max_length=30,
600 624
                                 default='PENDING')
601 625
    backendjobid = models.PositiveIntegerField(null=True)
......
607 631
    backendtime = models.DateTimeField(null=False,
608 632
                                       default=datetime.datetime.min)
609 633

  
634
    def __init__(self, *args, **kwargs):
635
        """Initialize state for just created BackendNetwork instances."""
636
        super(BackendNetwork, self).__init__(*args, **kwargs)
637
        if not self.mac_prefix:
638
            # Generate the MAC prefix of the BackendNetwork, by combining
639
            # the Network prefix with the index of the Backend
640
            net_prefix = self.network.mac_prefix
641
            backend_suffix = hex(self.backend.index).replace('0x', '')
642
            mac_prefix = net_prefix + backend_suffix
643
            try:
644
                utils.validate_mac(mac_prefix + ":00:00:00")
645
            except utils.InvalidMacAddress:
646
                raise utils.InvalidMacAddress("Invalid MAC prefix '%s'" % \
647
                                               mac_prefix)
648
            self.mac_prefix = mac_prefix
649

  
610 650
    def save(self, *args, **kwargs):
611 651
        super(BackendNetwork, self).save(*args, **kwargs)
612 652
        self.network.update_state()
......
628 668
    created = models.DateTimeField(auto_now_add=True)
629 669
    updated = models.DateTimeField(auto_now=True)
630 670
    index = models.IntegerField(null=False)
631
    mac = models.CharField(max_length=32, null=True)
671
    mac = models.CharField(max_length=32, null=False, unique=True)
632 672
    ipv4 = models.CharField(max_length=15, null=True)
633 673
    ipv6 = models.CharField(max_length=100, null=True)
634 674
    firewall_profile = models.CharField(choices=FIREWALL_PROFILES,
......
703 743

  
704 744

  
705 745
class MacPrefixPool(Pool):
706
    max_index = snf_settings.PRIVATE_MAC_FILTERED_MAX_PREFIX_NUMBER
746
    max_index = snf_settings.MAC_POOL_LIMIT
707 747

  
708 748
    @staticmethod
709 749
    def value_from_index(index):
710 750
        """Convert number to mac prefix
711 751

  
712 752
        """
713
        high = snf_settings.PRIVATE_MAC_FILTERED_BASE_MAC_PREFIX
714
        a = hex(int(high.replace(":", ""), 16) + index).replace("0x", '')
753
        base = snf_settings.MAC_POOL_BASE
754
        a = hex(int(base.replace(":", ""), 16) + index).replace("0x", '')
715 755
        mac_prefix = ":".join([a[x:x + 2] for x in xrange(0, len(a), 2)])
716 756
        return mac_prefix

Also available in: Unified diff