Revision 03992c72

b/snf-cyclades-app/synnefo/api/actions.py
44 44
                                ItemNotFound, BuildInProgress)
45 45
from synnefo.api.util import random_password, get_vm, get_nic_from_index
46 46
from synnefo.db.models import NetworkInterface, Network
47
from synnefo.logic import backend, ippool
47
from synnefo.db.pools import IPPool
48
from synnefo.logic import backend
48 49
from synnefo.logic.utils import get_rsapi_state
49 50

  
50 51

  
......
313 314
        raise ServiceUnavailable('Network not active yet')
314 315

  
315 316
    # Get a free IP from the address pool.
316
    pool = ippool.IPPool(net)
317
    pool = IPPool(net)
317 318
    try:
318 319
        address = pool.get_free_address()
319
    except ippool.IPPool.IPPoolExhausted:
320
    except IPPool.IPPoolExhausted:
320 321
        raise ServiceUnavailable('Network is full')
321 322
    pool.save()
322 323

  
b/snf-cyclades-app/synnefo/api/networks.py
46 46
from synnefo.api.common import method_not_allowed
47 47
from synnefo.api.faults import (BadRequest, Unauthorized,
48 48
                                NetworkInUse, OverLimit)
49
from synnefo.db.models import Network, Pool
49
from synnefo.db.models import Network
50
from synnefo.db.pools import EmptyPool
50 51
from synnefo.logic import backend
51 52

  
52 53

  
......
198 199
                link=link,
199 200
                action='CREATE',
200 201
                state='PENDING')
201
    except Pool.PoolExhausted:
202
    except EmptyPool:
202 203
        raise OverLimit('Network count limit exceeded.')
203 204

  
204 205
    # Create BackendNetwork entries for each Backend
b/snf-cyclades-app/synnefo/api/util.py
59 59
                                BadMediaType)
60 60
from synnefo.db.models import (Flavor, VirtualMachine, VirtualMachineMetadata,
61 61
                               Network, BackendNetwork, NetworkInterface,
62
                               BridgePool)
62
                               BridgePoolTable)
63 63

  
64 64
from synnefo.lib.astakos import get_user
65 65
from synnefo.plankton.backend import ImageBackend
66
from synnefo.logic import ippool
66
from synnefo.db.pools import IPPool
67 67
from synnefo.settings import MAX_CIDR_BLOCK
68 68

  
69 69

  
......
231 231
def get_network_free_address(network):
232 232
    """Reserve an IP address from the IP Pool of the network.
233 233

  
234
    Raises Network.DoesNotExist , ippool.IPPool.IPPoolExhausted
234
    Raises Network.DoesNotExist , IPPool.IPPoolExhausted
235 235

  
236 236
    """
237 237

  
238 238
    # Get the Network object in exclusive mode in order to
239 239
    # safely (isolated) reserve an IP address
240 240
    network = Network.objects.select_for_update().get(id=network.id)
241
    pool = ippool.IPPool(network)
241
    pool = IPPool(network)
242 242
    address = pool.get_free_address()
243 243
    pool.save()
244 244
    return address
......
399 399
    if network_type == 'PRIVATE_MAC_FILTERED':
400 400
        link = settings.PRIVATE_MAC_FILTERED_BRIDGE
401 401
    elif network_type == 'PRIVATE_PHYSICAL_VLAN':
402
        link = BridgePool.get_available().value
402
        pool = BridgePoolTable.get_pool()
403
        link = pool.get()
404
        pool.save()
403 405
    elif network_type == 'CUSTOM_ROUTED':
404 406
        link = settings.CUSTOM_ROUTED_ROUTING_TABLE
405 407
    elif network_type == 'CUSTOM_BRIDGED':
b/snf-cyclades-app/synnefo/db/migrations/0051_auto__add_bridgepooltable__add_macprefixpooltable.py
1
# encoding: utf-8
2
import datetime
3
from south.db import db
4
from south.v2 import SchemaMigration
5
from django.db import models
6

  
7
class Migration(SchemaMigration):
8
    
9
    def forwards(self, orm):
10
        
11
        # Adding model 'BridgePoolTable'
12
        db.create_table('db_bridgepooltable', (
13
            ('reserved_map', self.gf('django.db.models.fields.TextField')(default='')),
14
            ('base', self.gf('django.db.models.fields.CharField')(max_length=32, null=True)),
15
            ('offset', self.gf('django.db.models.fields.IntegerField')(null=True)),
16
            ('available_map', self.gf('django.db.models.fields.TextField')(default='')),
17
            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
18
            ('size', self.gf('django.db.models.fields.IntegerField')()),
19
        ))
20
        db.send_create_signal('db', ['BridgePoolTable'])
21

  
22
        # Adding model 'MacPrefixPoolTable'
23
        db.create_table('db_macprefixpooltable', (
24
            ('reserved_map', self.gf('django.db.models.fields.TextField')(default='')),
25
            ('base', self.gf('django.db.models.fields.CharField')(max_length=32, null=True)),
26
            ('offset', self.gf('django.db.models.fields.IntegerField')(null=True)),
27
            ('available_map', self.gf('django.db.models.fields.TextField')(default='')),
28
            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
29
            ('size', self.gf('django.db.models.fields.IntegerField')()),
30
        ))
31
        db.send_create_signal('db', ['MacPrefixPoolTable'])
32
    
33
    
34
    def backwards(self, orm):
35
        
36
        # Deleting model 'BridgePoolTable'
37
        db.delete_table('db_bridgepooltable')
38

  
39
        # Deleting model 'MacPrefixPoolTable'
40
        db.delete_table('db_macprefixpooltable')
41
    
42
    
43
    models = {
44
        'db.backend': {
45
            'Meta': {'object_name': 'Backend'},
46
            'clustername': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'}),
47
            'ctotal': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
48
            'dfree': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
49
            'drained': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
50
            'dtotal': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
51
            'hash': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
52
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
53
            'index': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'unique': 'True'}),
54
            'mfree': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
55
            'mtotal': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
56
            'offline': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
57
            'password_hash': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}),
58
            'pinst_cnt': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
59
            'port': ('django.db.models.fields.PositiveIntegerField', [], {'default': '5080'}),
60
            'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
61
            'username': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'})
62
        },
63
        'db.backendnetwork': {
64
            'Meta': {'unique_together': "(('network', 'backend'),)", 'object_name': 'BackendNetwork'},
65
            'backend': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'networks'", 'to': "orm['db.Backend']"}),
66
            'backendjobid': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
67
            'backendjobstatus': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
68
            'backendlogmsg': ('django.db.models.fields.TextField', [], {'null': 'True'}),
69
            'backendopcode': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
70
            'backendtime': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(1, 1, 1, 0, 0)'}),
71
            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
72
            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
73
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
74
            'mac_prefix': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
75
            'network': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'backend_networks'", 'to': "orm['db.Network']"}),
76
            'operstate': ('django.db.models.fields.CharField', [], {'default': "'PENDING'", 'max_length': '30'}),
77
            'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
78
        },
79
        'db.bridgepool': {
80
            'Meta': {'object_name': 'BridgePool'},
81
            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
82
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
83
            'index': ('django.db.models.fields.IntegerField', [], {'unique': 'True'}),
84
            'value': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'})
85
        },
86
        'db.bridgepooltable': {
87
            'Meta': {'object_name': 'BridgePoolTable'},
88
            'available_map': ('django.db.models.fields.TextField', [], {'default': "''"}),
89
            'base': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
90
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
91
            'offset': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
92
            'reserved_map': ('django.db.models.fields.TextField', [], {'default': "''"}),
93
            'size': ('django.db.models.fields.IntegerField', [], {})
94
        },
95
        'db.flavor': {
96
            'Meta': {'unique_together': "(('cpu', 'ram', 'disk', 'disk_template'),)", 'object_name': 'Flavor'},
97
            'cpu': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
98
            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
99
            'disk': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
100
            'disk_template': ('django.db.models.fields.CharField', [], {'default': "'plain'", 'max_length': '32'}),
101
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
102
            'ram': ('django.db.models.fields.IntegerField', [], {'default': '0'})
103
        },
104
        'db.macprefixpool': {
105
            'Meta': {'object_name': 'MacPrefixPool'},
106
            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
107
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
108
            'index': ('django.db.models.fields.IntegerField', [], {'unique': 'True'}),
109
            'value': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'})
110
        },
111
        'db.macprefixpooltable': {
112
            'Meta': {'object_name': 'MacPrefixPoolTable'},
113
            'available_map': ('django.db.models.fields.TextField', [], {'default': "''"}),
114
            'base': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
115
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
116
            'offset': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
117
            'reserved_map': ('django.db.models.fields.TextField', [], {'default': "''"}),
118
            'size': ('django.db.models.fields.IntegerField', [], {})
119
        },
120
        'db.network': {
121
            'Meta': {'object_name': 'Network'},
122
            'action': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '32', 'null': 'True'}),
123
            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
124
            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
125
            'dhcp': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
126
            'gateway': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
127
            'gateway6': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True'}),
128
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
129
            'link': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
130
            'mac_prefix': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
131
            'machines': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['db.VirtualMachine']", 'through': "orm['db.NetworkInterface']", 'symmetrical': 'False'}),
132
            'name': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
133
            'public': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
134
            'reservations': ('django.db.models.fields.TextField', [], {'default': "''"}),
135
            'state': ('django.db.models.fields.CharField', [], {'default': "'PENDING'", 'max_length': '32'}),
136
            'subnet': ('django.db.models.fields.CharField', [], {'default': "'10.0.0.0/24'", 'max_length': '32'}),
137
            'subnet6': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True'}),
138
            'type': ('django.db.models.fields.CharField', [], {'default': "'PRIVATE_PHYSICAL_VLAN'", 'max_length': '50'}),
139
            'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
140
            'userid': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'})
141
        },
142
        'db.networkinterface': {
143
            'Meta': {'object_name': 'NetworkInterface'},
144
            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
145
            'dirty': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
146
            'firewall_profile': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
147
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
148
            'index': ('django.db.models.fields.IntegerField', [], {}),
149
            'ipv4': ('django.db.models.fields.CharField', [], {'max_length': '15', 'null': 'True'}),
150
            'ipv6': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
151
            'mac': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32'}),
152
            'machine': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nics'", 'to': "orm['db.VirtualMachine']"}),
153
            'network': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nics'", 'to': "orm['db.Network']"}),
154
            'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
155
        },
156
        'db.virtualmachine': {
157
            'Meta': {'object_name': 'VirtualMachine'},
158
            'action': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
159
            'backend': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'virtual_machines'", 'null': 'True', 'to': "orm['db.Backend']"}),
160
            'backend_hash': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
161
            'backendjobid': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
162
            'backendjobstatus': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
163
            'backendlogmsg': ('django.db.models.fields.TextField', [], {'null': 'True'}),
164
            'backendopcode': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
165
            'backendtime': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(1, 1, 1, 0, 0)'}),
166
            'buildpercentage': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
167
            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
168
            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
169
            'flavor': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['db.Flavor']"}),
170
            'hostid': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
171
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
172
            'imageid': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
173
            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
174
            'operstate': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
175
            'suspended': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
176
            'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
177
            'userid': ('django.db.models.fields.CharField', [], {'max_length': '100'})
178
        },
179
        'db.virtualmachinemetadata': {
180
            'Meta': {'unique_together': "(('meta_key', 'vm'),)", 'object_name': 'VirtualMachineMetadata'},
181
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
182
            'meta_key': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
183
            'meta_value': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
184
            'vm': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'metadata'", 'to': "orm['db.VirtualMachine']"})
185
        }
186
    }
187
    
188
    complete_apps = ['db']
b/snf-cyclades-app/synnefo/db/migrations/0052_migrate_pool_entries.py
1
# encoding: utf-8
2
import datetime
3
from south.db import db
4
from south.v2 import DataMigration
5
from django.db import models
6
from synnefo import settings
7
from bitarray import bitarray
8
from base64 import b64encode
9

  
10
def create_empty_pool(size):
11
    ba = bitarray(size)
12
    ba.setall(True)
13
    return ba
14

  
15
def bitarray_to_string(bitarray_):
16
    return b64encode(bitarray_.tostring())
17

  
18
def validate_mac(value):
19
    hex_ = value.replace(":", "")
20
    bin_ = bin(int(hex_, 16))[2:].zfill(8)
21
    return bin_[6] == '1' and bin_[7] == '0'
22

  
23
def mac_from_index(base, index):
24
    """Convert number to mac prefix
25

  
26
    """
27
    a = hex(int(base.replace(":", ""), 16) + index).replace("0x", '')
28
    mac_prefix = ":".join([a[x:x + 2] for x in xrange(0, len(a), 2)])
29
    return mac_prefix
30

  
31
class Migration(DataMigration):
32
    
33
    def forwards(self, orm):
34
        "Write your forwards methods here."
35

  
36
        # Migrate Bridge Pool
37
        bridges = orm.BridgePool.objects.all()
38
        if bridges:
39
            try:
40
                pool_prefix = settings.PRIVATE_PHYSICAL_VLAN_BRIDGE_PREFIX
41
            except AttributeError:
42
                pool_prefix = ''
43

  
44
            try:
45
                pool_length = settings.PRIVATE_PHYSICAL_VLAN_MAX_NUMBER
46
            except:
47
                pool_length = len(bridges)
48

  
49
            reserved = create_empty_pool(pool_length)
50
            available = create_empty_pool(pool_length)
51

  
52
            for bridge in bridges:
53
                if not bridge.available:
54
                    available[bridge.index] = False
55
            available_map = bitarray_to_string(available)
56
            reserved_map = bitarray_to_string(reserved)
57

  
58
            orm.BridgePoolTable.objects.create(available_map=available_map,
59
                                               reserved_map=reserved_map,
60
                                               size=pool_length,
61
                                               base=pool_prefix)
62

  
63

  
64
        mac_prefixes = orm.MacPrefixPool.objects.all()
65
        if mac_prefixes:
66
            try:
67
                macp_base = settings.MAC_POOL_BASE
68
            except AttributeError:
69
                first = mac_prefixes[0]
70
                first[-1]= '0'
71
                macp_base =  first
72

  
73
            try:
74
                macp_length = settings.MAC_POOL_LIMIT
75
            except:
76
                macp_length = len(bridges)
77

  
78
            reserved = create_empty_pool(macp_length)
79
            available = create_empty_pool(macp_length)
80

  
81
            for macp in mac_prefixes:
82
                if not macp.available:
83
                    available[macp.index] = False
84

  
85
            for index in range(0, macp_length):
86
                mac = mac_from_index(macp_base, index)
87
                if not validate_mac(mac):
88
                    reserved[index] = False
89

  
90
            available_map = bitarray_to_string(available)
91
            reserved_map = bitarray_to_string(reserved)
92

  
93
            orm.MacPrefixPoolTable.objects.create(available_map=available_map,
94
                                               reserved_map=reserved_map,
95
                                               size=macp_length,
96
                                               base=macp_base)
97

  
98
    def backwards(self, orm):
99
        "Write your backwards methods here."
100
        raise RuntimeError("Can not reverse this migrations")
101

  
102
    models = {
103
        'db.backend': {
104
            'Meta': {'object_name': 'Backend'},
105
            'clustername': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'}),
106
            'ctotal': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
107
            'dfree': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
108
            'drained': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
109
            'dtotal': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
110
            'hash': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
111
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
112
            'index': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'unique': 'True'}),
113
            'mfree': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
114
            'mtotal': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
115
            'offline': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
116
            'password_hash': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}),
117
            'pinst_cnt': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
118
            'port': ('django.db.models.fields.PositiveIntegerField', [], {'default': '5080'}),
119
            'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
120
            'username': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'})
121
        },
122
        'db.backendnetwork': {
123
            'Meta': {'unique_together': "(('network', 'backend'),)", 'object_name': 'BackendNetwork'},
124
            'backend': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'networks'", 'to': "orm['db.Backend']"}),
125
            'backendjobid': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
126
            'backendjobstatus': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
127
            'backendlogmsg': ('django.db.models.fields.TextField', [], {'null': 'True'}),
128
            'backendopcode': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
129
            'backendtime': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(1, 1, 1, 0, 0)'}),
130
            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
131
            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
132
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
133
            'mac_prefix': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
134
            'network': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'backend_networks'", 'to': "orm['db.Network']"}),
135
            'operstate': ('django.db.models.fields.CharField', [], {'default': "'PENDING'", 'max_length': '30'}),
136
            'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
137
        },
138
        'db.bridgepool': {
139
            'Meta': {'object_name': 'BridgePool'},
140
            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
141
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
142
            'index': ('django.db.models.fields.IntegerField', [], {'unique': 'True'}),
143
            'value': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'})
144
        },
145
        'db.bridgepooltable': {
146
            'Meta': {'object_name': 'BridgePoolTable'},
147
            'available_map': ('django.db.models.fields.TextField', [], {'default': "''"}),
148
            'base': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
149
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
150
            'offset': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
151
            'reserved_map': ('django.db.models.fields.TextField', [], {'default': "''"}),
152
            'size': ('django.db.models.fields.IntegerField', [], {})
153
        },
154
        'db.flavor': {
155
            'Meta': {'unique_together': "(('cpu', 'ram', 'disk', 'disk_template'),)", 'object_name': 'Flavor'},
156
            'cpu': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
157
            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
158
            'disk': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
159
            'disk_template': ('django.db.models.fields.CharField', [], {'default': "'plain'", 'max_length': '32'}),
160
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
161
            'ram': ('django.db.models.fields.IntegerField', [], {'default': '0'})
162
        },
163
        'db.macprefixpool': {
164
            'Meta': {'object_name': 'MacPrefixPool'},
165
            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
166
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
167
            'index': ('django.db.models.fields.IntegerField', [], {'unique': 'True'}),
168
            'value': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'})
169
        },
170
        'db.macprefixpooltable': {
171
            'Meta': {'object_name': 'MacPrefixPoolTable'},
172
            'available_map': ('django.db.models.fields.TextField', [], {'default': "''"}),
173
            'base': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
174
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
175
            'offset': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
176
            'reserved_map': ('django.db.models.fields.TextField', [], {'default': "''"}),
177
            'size': ('django.db.models.fields.IntegerField', [], {})
178
        },
179
        'db.network': {
180
            'Meta': {'object_name': 'Network'},
181
            'action': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '32', 'null': 'True'}),
182
            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
183
            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
184
            'dhcp': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
185
            'gateway': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
186
            'gateway6': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True'}),
187
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
188
            'link': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
189
            'mac_prefix': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
190
            'machines': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['db.VirtualMachine']", 'through': "orm['db.NetworkInterface']", 'symmetrical': 'False'}),
191
            'name': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
192
            'public': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
193
            'reservations': ('django.db.models.fields.TextField', [], {'default': "''"}),
194
            'state': ('django.db.models.fields.CharField', [], {'default': "'PENDING'", 'max_length': '32'}),
195
            'subnet': ('django.db.models.fields.CharField', [], {'default': "'10.0.0.0/24'", 'max_length': '32'}),
196
            'subnet6': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True'}),
197
            'type': ('django.db.models.fields.CharField', [], {'default': "'PRIVATE_PHYSICAL_VLAN'", 'max_length': '50'}),
198
            'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
199
            'userid': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'})
200
        },
201
        'db.networkinterface': {
202
            'Meta': {'object_name': 'NetworkInterface'},
203
            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
204
            'dirty': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
205
            'firewall_profile': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
206
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
207
            'index': ('django.db.models.fields.IntegerField', [], {}),
208
            'ipv4': ('django.db.models.fields.CharField', [], {'max_length': '15', 'null': 'True'}),
209
            'ipv6': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
210
            'mac': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32'}),
211
            'machine': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nics'", 'to': "orm['db.VirtualMachine']"}),
212
            'network': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nics'", 'to': "orm['db.Network']"}),
213
            'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
214
        },
215
        'db.virtualmachine': {
216
            'Meta': {'object_name': 'VirtualMachine'},
217
            'action': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
218
            'backend': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'virtual_machines'", 'null': 'True', 'to': "orm['db.Backend']"}),
219
            'backend_hash': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
220
            'backendjobid': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
221
            'backendjobstatus': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
222
            'backendlogmsg': ('django.db.models.fields.TextField', [], {'null': 'True'}),
223
            'backendopcode': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
224
            'backendtime': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(1, 1, 1, 0, 0)'}),
225
            'buildpercentage': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
226
            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
227
            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
228
            'flavor': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['db.Flavor']"}),
229
            'hostid': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
230
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
231
            'imageid': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
232
            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
233
            'operstate': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
234
            'suspended': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
235
            'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
236
            'userid': ('django.db.models.fields.CharField', [], {'max_length': '100'})
237
        },
238
        'db.virtualmachinemetadata': {
239
            'Meta': {'unique_together': "(('meta_key', 'vm'),)", 'object_name': 'VirtualMachineMetadata'},
240
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
241
            'meta_key': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
242
            'meta_value': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
243
            'vm': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'metadata'", 'to': "orm['db.VirtualMachine']"})
244
        }
245
    }
246
    
247
    complete_apps = ['db']
b/snf-cyclades-app/synnefo/db/migrations/0053_auto__del_bridgepool__del_macprefixpool.py
1
# encoding: utf-8
2
import datetime
3
from south.db import db
4
from south.v2 import SchemaMigration
5
from django.db import models
6

  
7
class Migration(SchemaMigration):
8
    
9
    def forwards(self, orm):
10
        
11
        # Deleting model 'BridgePool'
12
        db.delete_table('db_bridgepool')
13

  
14
        # Deleting model 'MacPrefixPool'
15
        db.delete_table('db_macprefixpool')
16
    
17
    
18
    def backwards(self, orm):
19
        
20
        # Adding model 'BridgePool'
21
        db.create_table('db_bridgepool', (
22
            ('available', self.gf('django.db.models.fields.BooleanField')(default=True, blank=True)),
23
            ('index', self.gf('django.db.models.fields.IntegerField')(unique=True)),
24
            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
25
            ('value', self.gf('django.db.models.fields.CharField')(max_length=128, unique=True)),
26
        ))
27
        db.send_create_signal('db', ['BridgePool'])
28

  
29
        # Adding model 'MacPrefixPool'
30
        db.create_table('db_macprefixpool', (
31
            ('available', self.gf('django.db.models.fields.BooleanField')(default=True, blank=True)),
32
            ('index', self.gf('django.db.models.fields.IntegerField')(unique=True)),
33
            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
34
            ('value', self.gf('django.db.models.fields.CharField')(max_length=128, unique=True)),
35
        ))
36
        db.send_create_signal('db', ['MacPrefixPool'])
37
    
38
    
39
    models = {
40
        'db.backend': {
41
            'Meta': {'object_name': 'Backend'},
42
            'clustername': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'}),
43
            'ctotal': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
44
            'dfree': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
45
            'drained': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
46
            'dtotal': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
47
            'hash': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
48
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
49
            'index': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'unique': 'True'}),
50
            'mfree': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
51
            'mtotal': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
52
            'offline': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
53
            'password_hash': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}),
54
            'pinst_cnt': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
55
            'port': ('django.db.models.fields.PositiveIntegerField', [], {'default': '5080'}),
56
            'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
57
            'username': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'})
58
        },
59
        'db.backendnetwork': {
60
            'Meta': {'unique_together': "(('network', 'backend'),)", 'object_name': 'BackendNetwork'},
61
            'backend': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'networks'", 'to': "orm['db.Backend']"}),
62
            'backendjobid': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
63
            'backendjobstatus': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
64
            'backendlogmsg': ('django.db.models.fields.TextField', [], {'null': 'True'}),
65
            'backendopcode': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
66
            'backendtime': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(1, 1, 1, 0, 0)'}),
67
            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
68
            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
69
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
70
            'mac_prefix': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
71
            'network': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'backend_networks'", 'to': "orm['db.Network']"}),
72
            'operstate': ('django.db.models.fields.CharField', [], {'default': "'PENDING'", 'max_length': '30'}),
73
            'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
74
        },
75
        'db.bridgepooltable': {
76
            'Meta': {'object_name': 'BridgePoolTable'},
77
            'available_map': ('django.db.models.fields.TextField', [], {'default': "''"}),
78
            'base': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
79
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
80
            'offset': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
81
            'reserved_map': ('django.db.models.fields.TextField', [], {'default': "''"}),
82
            'size': ('django.db.models.fields.IntegerField', [], {})
83
        },
84
        'db.flavor': {
85
            'Meta': {'unique_together': "(('cpu', 'ram', 'disk', 'disk_template'),)", 'object_name': 'Flavor'},
86
            'cpu': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
87
            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
88
            'disk': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
89
            'disk_template': ('django.db.models.fields.CharField', [], {'default': "'plain'", 'max_length': '32'}),
90
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
91
            'ram': ('django.db.models.fields.IntegerField', [], {'default': '0'})
92
        },
93
        'db.macprefixpooltable': {
94
            'Meta': {'object_name': 'MacPrefixPoolTable'},
95
            'available_map': ('django.db.models.fields.TextField', [], {'default': "''"}),
96
            'base': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
97
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
98
            'offset': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
99
            'reserved_map': ('django.db.models.fields.TextField', [], {'default': "''"}),
100
            'size': ('django.db.models.fields.IntegerField', [], {})
101
        },
102
        'db.network': {
103
            'Meta': {'object_name': 'Network'},
104
            'action': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '32', 'null': 'True'}),
105
            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
106
            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
107
            'dhcp': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
108
            'gateway': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
109
            'gateway6': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True'}),
110
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
111
            'link': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
112
            'mac_prefix': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
113
            'machines': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['db.VirtualMachine']", 'through': "orm['db.NetworkInterface']", 'symmetrical': 'False'}),
114
            'name': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
115
            'public': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
116
            'reservations': ('django.db.models.fields.TextField', [], {'default': "''"}),
117
            'state': ('django.db.models.fields.CharField', [], {'default': "'PENDING'", 'max_length': '32'}),
118
            'subnet': ('django.db.models.fields.CharField', [], {'default': "'10.0.0.0/24'", 'max_length': '32'}),
119
            'subnet6': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True'}),
120
            'type': ('django.db.models.fields.CharField', [], {'default': "'PRIVATE_PHYSICAL_VLAN'", 'max_length': '50'}),
121
            'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
122
            'userid': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'})
123
        },
124
        'db.networkinterface': {
125
            'Meta': {'object_name': 'NetworkInterface'},
126
            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
127
            'dirty': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
128
            'firewall_profile': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
129
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
130
            'index': ('django.db.models.fields.IntegerField', [], {}),
131
            'ipv4': ('django.db.models.fields.CharField', [], {'max_length': '15', 'null': 'True'}),
132
            'ipv6': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
133
            'mac': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32'}),
134
            'machine': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nics'", 'to': "orm['db.VirtualMachine']"}),
135
            'network': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nics'", 'to': "orm['db.Network']"}),
136
            'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
137
        },
138
        'db.virtualmachine': {
139
            'Meta': {'object_name': 'VirtualMachine'},
140
            'action': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
141
            'backend': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'virtual_machines'", 'null': 'True', 'to': "orm['db.Backend']"}),
142
            'backend_hash': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
143
            'backendjobid': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
144
            'backendjobstatus': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
145
            'backendlogmsg': ('django.db.models.fields.TextField', [], {'null': 'True'}),
146
            'backendopcode': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
147
            'backendtime': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(1, 1, 1, 0, 0)'}),
148
            'buildpercentage': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
149
            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
150
            'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
151
            'flavor': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['db.Flavor']"}),
152
            'hostid': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
153
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
154
            'imageid': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
155
            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
156
            'operstate': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
157
            'suspended': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
158
            'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
159
            'userid': ('django.db.models.fields.CharField', [], {'max_length': '100'})
160
        },
161
        'db.virtualmachinemetadata': {
162
            'Meta': {'unique_together': "(('meta_key', 'vm'),)", 'object_name': 'VirtualMachineMetadata'},
163
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
164
            'meta_key': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
165
            'meta_value': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
166
            'vm': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'metadata'", 'to': "orm['db.VirtualMachine']"})
167
        }
168
    }
169
    
170
    complete_apps = ['db']
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
b/snf-cyclades-app/synnefo/db/pools/__init__.py
1
from bitarray import bitarray
2
from base64 import b64encode, b64decode
3
import ipaddr
4

  
5
AVAILABLE = True
6
UNAVAILABLE = False
7

  
8

  
9
class PoolManager(object):
10
    """PoolManager for DB PoolTable models.
11

  
12
    This class implements a persistent Pool mechanism based on rows of
13
    PoolTable objects. Values that are pooled by this class, are mapped to an
14
    index on a bitarray, which is the one that is stored on the DB.
15

  
16
    The object that will be used in order to initialize this pool, must have
17
    two string attributes (available_map and reserved_map) and the size of the
18
    pool.
19

  
20
    Subclasses of PoolManager must implement value_to_index and index_to_value
21
    method's in order to denote how the value will be mapped to the index in
22
    the bitarray.
23

  
24
    Important!!: Updates on a PoolManager object are not reflected to the DB,
25
    until save() method is called.
26

  
27
    """
28
    def __init__(self, pool_table):
29
        self.pool_table = pool_table
30

  
31
        if pool_table.available_map:
32
            self.available = _bitarray_from_string(pool_table.available_map)
33
            self.reserved = _bitarray_from_string(pool_table.reserved_map)
34
        else:
35
            size = self.pool_table.size
36
            padding = find_padding(size)
37
            size = size + padding
38
            self.pool_size = size
39
            self.available = self._create_empty_pool()
40
            self.reserved = self._create_empty_pool()
41
            for i in xrange(0, padding):
42
                self._reserve(size - i - 1, external=True)
43

  
44
    def _create_empty_pool(self):
45
        assert(self.pool_size % 8 == 0)
46
        ba = bitarray(self.pool_size)
47
        ba.setall(AVAILABLE)
48
        return ba
49

  
50
    @property
51
    def pool(self):
52
        return (self.available & self.reserved)
53

  
54
    def get(self):
55
        """Get a value from the pool."""
56
        if self.empty():
57
            raise EmptyPool
58
        # Get the first available index
59
        index = int(self.pool.index(AVAILABLE))
60
        self._reserve(index)
61
        return self.index_to_value(index)
62

  
63
    def put(self, value, external=False):
64
        """Return a value to the pool."""
65
        if value is None:
66
            raise ValueError
67
        index = self.value_to_index(value)
68
        self._release(index, external)
69

  
70
    def reserve(self, value, external=True):
71
        """Reserve a value."""
72
        index = self.value_to_index(value)
73
        self._reserve(index, external)
74
        return True
75

  
76
    def save(self, db=True):
77
        """Save changes to the DB."""
78
        self.pool_table.available_map = _bitarray_to_string(self.available)
79
        self.pool_table.reserved_map = _bitarray_to_string(self.reserved)
80
        if db:
81
            self.pool_table.save()
82

  
83
    def empty(self):
84
        """Return True when pool is empty."""
85
        return not self.pool.any()
86

  
87
    def size(self):
88
        return self.pool.length()
89

  
90
    def _reserve(self, index, external=False):
91
        if external:
92
            self.reserved[index] = UNAVAILABLE
93
        else:
94
            self.available[index] = UNAVAILABLE
95

  
96
    def _release(self, index, external=False):
97
        if external:
98
            self.reserved[index] = AVAILABLE
99
        else:
100
            self.available[index] = AVAILABLE
101

  
102
    def count_available(self):
103
        return self.pool.count(AVAILABLE)
104

  
105
    def count_unavailable(self):
106
        return self.pool.count(UNAVAILABLE)
107

  
108
    def count_reserved(self):
109
        return self.reserved.count(UNAVAILABLE)
110

  
111
    def count_unreserved(self):
112
        return self.size() - self.count_reserved()
113

  
114
    def is_available(self, value, index=False):
115
        if not index:
116
            idx = self.value_to_index(value)
117
        else:
118
            idx = value
119
        return self.pool[idx] == AVAILABLE
120

  
121
    def is_reserved(self, value, index=False):
122
        if not index:
123
            idx = self.value_to_index(value)
124
        else:
125
            idx = value
126
        return self.reserved[idx] == UNAVAILABLE
127

  
128
    def to_01(self):
129
        return self.pool.to01()
130

  
131
    def to_map(self):
132
        return self.to_01().replace("0", "X").replace("1", ".")
133

  
134
    def index_to_value(self, index):
135
        raise NotImplementedError
136

  
137
    def value_to_index(self, value):
138
        raise NotImplementedError
139

  
140

  
141
class EmptyPool(Exception):
142
    pass
143

  
144

  
145
def find_padding(size):
146
    extra = size % 8
147
    return extra and (8 - extra) or 0
148

  
149

  
150
def bitarray_to_01(bitarray_):
151
    return bitarray_.to01()
152

  
153

  
154
def bitarray_to_map(bitarray_):
155
    return bitarray_to_01(bitarray_).replace("0", "X").replace("1", ".")
156

  
157

  
158
def _bitarray_from_string(bitarray_):
159
    ba = bitarray()
160
    ba.fromstring(b64decode(bitarray_))
161
    return ba
162

  
163

  
164
def _bitarray_to_string(bitarray_):
165
    return b64encode(bitarray_.tostring())
166

  
167
##
168
## Custom pools
169
##
170

  
171

  
172
class BridgePool(PoolManager):
173
    def index_to_value(self, index):
174
        return self.pool_table.base + str(index)
175

  
176
    def value_to_index(self, value):
177
        return int(value.replace(self.pool_table.base, ""))
178

  
179

  
180
class MacPrefixPool(PoolManager):
181
    def __init__(self, pool_table):
182
        do_init = False if pool_table.available_map else True
183
        super(MacPrefixPool, self).__init__(pool_table)
184
        if do_init:
185
            for i in xrange(1, self.size()):
186
                if not self.validate_mac(self.index_to_value(i)):
187
                    self._reserve(i, external=True)
188
            # Reserve the first mac-prefix for public-networks
189
            self._reserve(0, external=True)
190

  
191
    def index_to_value(self, index):
192
        """Convert index to mac_prefix"""
193
        base = self.pool_table.base
194
        a = hex(int(base.replace(":", ""), 16) + index).replace("0x", '')
195
        mac_prefix = ":".join([a[x:x + 2] for x in xrange(0, len(a), 2)])
196
        return mac_prefix
197

  
198
    def value_to_index(self, value):
199
        base = self.pool_table.base
200
        return int(value.replace(":", ""), 16) - int(base.replace(":", ""), 16)
201

  
202
    @staticmethod
203
    def validate_mac(value):
204
        hex_ = value.replace(":", "")
205
        bin_ = bin(int(hex_, 16))[2:].zfill(8)
206
        return bin_[6] == '1' and bin_[7] == '0'
207

  
208

  
209
# class IPPool(PoolManager):
210
#     def __init__(self, network):
211
#         do_init = False if network.pool else True
212
#         self.net = ipaddr.IPNetwork(network.subnet)
213
#         network.size = self.net.numhosts
214
#         super(IPPool, self).__init__(network)
215
#         gateway = network.gateway
216
#         self.gateway = gateway and ipaddr.IPAddress(gateway) or None
217
#         if do_init:
218
#             self._reserve(0)
219
#             self.put(gateway)
220
#             self._reserve(self.size() - 1)
221
#
222
#     def value_to_index(self, value):
223
#         addr = ipaddr.IPAddress(value)
224
#         return int(addr) - int(self.net.network)
225
#
226
#     def index_to_value(self, index):
227
#         return str(self.net[index])
228

  
229
class IPPool(object):
230
    """IP pool class, based on a models.Network object
231

  
232
    Implementation of an IP address pool based on a models.Network
233
    object.
234

  
235
    """
236
    def __init__(self, network):
237
        self.net = network
238
        self.network = ipaddr.IPNetwork(self.net.subnet)
239

  
240
        gateway = self.net.gateway
241
        self.gateway = gateway and ipaddr.IPAddress(gateway) or None
242

  
243
        if self.net.reservations:
244
            self.reservations = bitarray()
245
            self.reservations.fromstring(b64decode(self.net.reservations))
246
        else:
247
            numhosts = self.network.numhosts
248
            self.reservations = bitarray(numhosts)
249
            self.reservations.setall(False)
250
            self.reservations[0] = True
251
            self.reservations[numhosts - 1] = True
252
            if self.gateway:
253
                self.reserve(self.gateway)
254

  
255
    def _contains(self, address):
256
        if address is None:
257
            return False
258
        addr = ipaddr.IPAddress(address)
259

  
260
        return (addr in self.network)
261

  
262
    def _address_index(self, address):
263
        """Convert IP address to bitarray index
264

  
265
        """
266
        if not self._contains(address):
267
            raise Exception("%s does not contain %s" %
268
                            (str(self.network), address))
269
        addr = ipaddr.IPAddress(address)
270

  
271
        return int(addr) - int(self.network.network)
272

  
273
    def _mark(self, address, value):
274
        index = self._address_index(address)
275
        self.reservations[index] = value
276

  
277
    def reserve(self, address):
278
        self._mark(address, True)
279

  
280
    def release(self, address):
281
        self._mark(address, False)
282

  
283
    def is_reserved(self, address):
284
        index = self._address_index(address)
285
        return self.reservations[index]
286

  
287
    def is_full(self):
288
            return self.reservations.all()
289

  
290
    def count_reserved(self):
291
        return self.reservations.count(True)
292

  
293
    def count_free(self):
294
        return self.reservations.count(False)
295

  
296
    def get_map(self):
297
        return self.reservations.to01().replace("1", "X").replace("0", ".")
298

  
299
    def get_free_address(self):
300
        """Get the first available address."""
301
        if self.is_full():
302
            raise IPPool.IPPoolExhausted("%s if full" % str(self.network))
303

  
304
        index = self.reservations.index(False)
305
        address = str(self.network[index])
306
        self.reserve(address)
307
        return address
308

  
309
    def save(self):
310
        """Update the Network model and save it to DB."""
311
        self._update_network()
312
        self.net.save()
313

  
314
    def _update_network(self):
315
        self.net.reservations = b64encode(self.reservations.tostring())
316

  
317
    class IPPoolExhausted(Exception):
318
        pass
b/snf-cyclades-app/synnefo/logic/backend.py
40 40

  
41 41
from synnefo.db.models import (Backend, VirtualMachine, Network,
42 42
                               BackendNetwork, BACKEND_STATUSES)
43
from synnefo.logic import utils, ippool
43
from synnefo.logic import utils
44
from synnefo.db.pools import IPPool
44 45
from synnefo.api.faults import OverLimit
45 46
from synnefo.api.util import backend_public_networks, get_network_free_address
46 47
from synnefo.util.rapi import GanetiRapiClient
......
366 367
        try:
367 368
            address = get_network_free_address(network)
368 369
            return (network, address)
369
        except ippool.IPPool.IPPoolExhausted:
370
        except IPPool.IPPoolExhausted:
370 371
            pass
371 372
    return (None, None)
372 373

  
/dev/null
1
import ipaddr
2

  
3
from bitarray import bitarray
4
from base64 import b64encode, b64decode
5

  
6

  
7
class IPPool(object):
8
    """IP pool class, based on a models.Network object
9

  
10
    Implementation of an IP address pool based on a models.Network
11
    object.
12

  
13
    """
14
    def __init__(self, network):
15
        self.net = network
16
        self.network = ipaddr.IPNetwork(self.net.subnet)
17

  
18
        gateway = self.net.gateway
19
        self.gateway = gateway and ipaddr.IPAddress(gateway) or None
20

  
21
        if self.net.reservations:
22
            self.reservations = bitarray()
23
            self.reservations.fromstring(b64decode(self.net.reservations))
24
        else:
25
            numhosts = self.network.numhosts
26
            self.reservations = bitarray(numhosts)
27
            self.reservations.setall(False)
28
            self.reservations[0] = True
29
            self.reservations[numhosts - 1] = True
30
            if self.gateway:
31
                self.reserve(self.gateway)
32

  
33
    def _contains(self, address):
34
        if address is None:
35
            return False
36
        addr = ipaddr.IPAddress(address)
37

  
38
        return (addr in self.network)
39

  
40
    def _address_index(self, address):
41
        """Convert IP address to bitarray index
42

  
43
        """
44
        if not self._contains(address):
45
            raise Exception("%s does not contain %s" %
46
                            (str(self.network), address))
47
        addr = ipaddr.IPAddress(address)
48

  
49
        return int(addr) - int(self.network.network)
50

  
51
    def _mark(self, address, value):
52
        index = self._address_index(address)
53
        self.reservations[index] = value
54

  
55
    def reserve(self, address):
56
        self._mark(address, True)
57

  
58
    def release(self, address):
59
        self._mark(address, False)
60

  
61
    def is_reserved(self, address):
62
        index = self._address_index(address)
63
        return self.reservations[index]
64

  
65
    def is_full(self):
66
            return self.reservations.all()
67

  
68
    def count_reserved(self):
69
        return self.reservations.count(True)
70

  
71
    def count_free(self):
72
        return self.reservations.count(False)
73

  
74
    def get_map(self):
75
        return self.reservations.to01().replace("1", "X").replace("0", ".")
76

  
77
    def get_free_address(self):
78
        """Get the first available address."""
79
        if self.is_full():
80
            raise IPPool.IPPoolExhausted("%s if full" % str(self.network))
81

  
82
        index = self.reservations.index(False)
83
        address = str(self.network[index])
84
        self.reserve(address)
85
        return address
86

  
87
    def save(self):
88
        """Update the Network model and save it to DB."""
89
        self._update_network()
90
        self.net.save()
91

  
92
    def _update_network(self):
93
        self.net.reservations = b64encode(self.reservations.tostring())
94

  
95
    class IPPoolExhausted(Exception):
96
        pass
b/snf-cyclades-app/synnefo/logic/management/commands/reconcile-pools.py
30 30
from django.core.management.base import BaseCommand
31 31

  
32 32
from synnefo.db.models import (Network, BackendNetwork,
33
                               BridgePool, MacPrefixPool)
33
                               BridgePoolTable, MacPrefixPoolTable)
34 34

  
35 35

  
36 36
class Command(BaseCommand):
......
48 48
        write("Checking consistency of the Bridge Pool\n")
49 49
        write("---------------------------------------\n")
50 50

  
51
        pool_bridges = BridgePool.objects.filter(available=False)\
52
                                         .values_list('value', flat=True)
51
        bridge_pool = BridgePoolTable.get_pool()
52
        bridges = []
53
        for i in xrange(0, bridge_pool.size()):
54
            if not bridge_pool.is_available(i, index=True) and \
55
               not bridge_pool.is_reserved(i, index=True):
56
                bridges.append(bridge_pool.index_to_value(i))
53 57

  
54
        write("Used bridges from Pool: %d\n" %
55
                          len(pool_bridges))
58
        write("Used bridges from Pool: %d\n" % len(bridges))
56 59

  
57 60
        network_bridges = Network.objects.filter(type='PRIVATE_PHYSICAL_VLAN',
58 61
                                                deleted=False)\
......
81 84
        write("Checking consistency of the MAC Prefix Pool\n")
82 85
        write("---------------------------------------\n")
83 86

  
84
        pool_mac_prefixes = MacPrefixPool.objects.filter(available=False)\
85
                                         .values_list('value', flat=True)
87
        macp_pool = MacPrefixPoolTable.get_pool()
88
        macs = []
89
        for i in xrange(0, macp_pool.size()):
90
            if not macp_pool.is_available(i, index=True) and \
91
               not macp_pool.is_reserved(i, index=True):
92
                macs.append(macp_pool.index_to_value(i))
86 93

  
87
        write("Used MAC prefixes from Pool: %d\n" %
88
                          len(pool_mac_prefixes))
94
        write("Used MAC prefixes from Pool: %d\n" % len(macs))
89 95

  
90 96
        network_mac_prefixes = Network.objects.filter(deleted=False)\
91 97
                                         .values_list('mac_prefix', flat=True)
......
101 107
            for mac_prefix in set(duplicates):
102 108
                write("Duplicated mac_prefix: %s. " % mac_prefix)
103 109
                write("Used by the following Networks:\n")
104
                nets = Network.objects.filter(deleted=False, mac_prefix=mac_prefix)
110
                nets = Network.objects.filter(deleted=False,
111
                                              mac_prefix=mac_prefix)
105 112
                write("  " + "\n  ".join([str(net.id) for net in nets])\
106 113
                                  + "\n")
107 114

  
......
124 131
            for mac_prefix in set(duplicates):
125 132
                write("Duplicated mac_prefix: %s. " % mac_prefix)
126 133
                write("Used by the following BackendNetworks:\n")
127
                nets = BackendNetwork.objects.filter(deleted=False, mac_prefix=mac_prefix)
134
                nets = BackendNetwork.objects.filter(deleted=False,
135
                                                     mac_prefix=mac_prefix)
128 136
                write("  " + "\n  ".join([str(net.id) for net in nets])\
129 137
                                  + "\n")

Also available in: Unified diff