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