Revision bfb3f9c2
b/snf-cyclades-app/synnefo/db/models.py | ||
---|---|---|
567 | 567 |
def get_subnet(self, version=4): |
568 | 568 |
for subnet in self.subnets.all(): |
569 | 569 |
if subnet.ipversion == version: |
570 |
return subnet.cidr |
|
570 |
return subnet |
|
571 |
return None |
|
571 | 572 |
|
572 | 573 |
def ip_count(self): |
573 | 574 |
"""Return the total and free IPv4 addresses of the network.""" |
b/snf-cyclades-app/synnefo/logic/backend.py | ||
---|---|---|
37 | 37 |
from synnefo.db.models import (Backend, VirtualMachine, Network, |
38 | 38 |
BackendNetwork, BACKEND_STATUSES, |
39 | 39 |
pooled_rapi_client, VirtualMachineDiagnostic, |
40 |
Flavor, IPAddressLog) |
|
40 |
Flavor, IPAddress, IPAddressLog)
|
|
41 | 41 |
from synnefo.logic import utils, ips |
42 | 42 |
from synnefo import quotas |
43 | 43 |
from synnefo.api.util import release_resource |
... | ... | |
266 | 266 |
# Update the NIC in DB with the values from Ganeti NIC |
267 | 267 |
setattr(db_nic, f, ganeti_nic[f]) |
268 | 268 |
db_nic.save() |
269 |
|
|
269 | 270 |
# Special case where the IPv4 address has changed, because you |
270 | 271 |
# need to release the old IPv4 address and reserve the new one |
271 | 272 |
ipv4_address = ganeti_nic["ipv4_address"] |
272 | 273 |
if db_nic.ipv4_address != ipv4_address: |
273 |
remove_nic_ips(db_nic) |
|
274 |
if ipv4_address: |
|
275 |
network = ganeti_nic["network"] |
|
276 |
ipaddress = ips.allocate_ip(network, vm.userid, |
|
277 |
address=ipv4_address) |
|
278 |
ipaddress.nic = nic |
|
279 |
ipaddress.save() |
|
274 |
change_address_of_port(db_nic, vm.userid, |
|
275 |
old_address=db_nic.ipv4_address, |
|
276 |
new_address=ipv4_address, |
|
277 |
version=4) |
|
278 |
|
|
279 |
ipv6_address = ganeti_nic["ipv6_address"] |
|
280 |
if db_nic.ipv6_address != ipv6_address: |
|
281 |
change_address_of_port(db_nic, vm.userid, |
|
282 |
old_address=db_nic.ipv6_address, |
|
283 |
new_address=ipv6_address, |
|
284 |
version=6) |
|
280 | 285 |
|
281 | 286 |
vm.backendtime = etime |
282 | 287 |
vm.save() |
283 | 288 |
|
284 | 289 |
|
290 |
def change_address_of_port(port, userid, old_address, new_address, version): |
|
291 |
"""Change.""" |
|
292 |
if old_address is not None: |
|
293 |
msg = ("IPv%s Address of server '%s' changed from '%s' to '%s'" |
|
294 |
% (version, port.machine_id, old_address, new_address)) |
|
295 |
log.critical(msg) |
|
296 |
|
|
297 |
# Remove the old IP address |
|
298 |
remove_nic_ips(port, version=version) |
|
299 |
|
|
300 |
if version == 4: |
|
301 |
ipaddress = ips.allocate_ip(port.network, userid, address=new_address) |
|
302 |
ipaddress.nic = port |
|
303 |
ipaddress.save() |
|
304 |
elif version == 6: |
|
305 |
subnet6 = port.network.subnet6 |
|
306 |
ipaddress = IPAddress.objects.create(userid=userid, |
|
307 |
network=port.network, |
|
308 |
subnet=subnet6, |
|
309 |
nic=port, |
|
310 |
address=new_address) |
|
311 |
else: |
|
312 |
raise ValueError("Unknown version: %s" % version) |
|
313 |
|
|
314 |
# New address log |
|
315 |
ip_log = IPAddressLog.objects.create(server_id=port.machine_id, |
|
316 |
network_id=port.network_id, |
|
317 |
address=new_address, |
|
318 |
active=True) |
|
319 |
log.info("Created IP log entry '%s' for address '%s' to server '%s'", |
|
320 |
ip_log.id, new_address, port.machine_id) |
|
321 |
|
|
322 |
return ipaddress |
|
323 |
|
|
324 |
|
|
285 | 325 |
def nics_are_equal(db_nic, gnt_nic): |
286 | 326 |
for field in NIC_FIELDS: |
287 | 327 |
if getattr(db_nic, field) != gnt_nic[field]: |
... | ... | |
308 | 348 |
mac = gnic.get('mac') |
309 | 349 |
ipv4 = gnic.get('ip') |
310 | 350 |
subnet6 = network.subnet6 |
311 |
ipv6 = mac2eui64(mac, subnet6) if subnet6 else None |
|
351 |
ipv6 = mac2eui64(mac, subnet6.cidr) if subnet6 else None
|
|
312 | 352 |
|
313 | 353 |
firewall = gnic.get('firewall') |
314 | 354 |
firewall_profile = _reverse_tags.get(firewall) |
... | ... | |
328 | 368 |
return dict(new_nics) |
329 | 369 |
|
330 | 370 |
|
331 |
def remove_nic_ips(nic): |
|
371 |
def remove_nic_ips(nic, version=None):
|
|
332 | 372 |
"""Remove IP addresses associated with a NetworkInterface. |
333 | 373 |
|
334 | 374 |
Remove all IP addresses that are associated with the NetworkInterface |
335 | 375 |
object, by returning them to the pool and deleting the IPAddress object. If |
336 | 376 |
the IP is a floating IP, then it is just disassociated from the NIC. |
377 |
If version is specified, then only IP addressses of that version will be |
|
378 |
removed. |
|
337 | 379 |
|
338 | 380 |
""" |
339 |
|
|
340 | 381 |
for ip in nic.ips.all(): |
382 |
if version and ip.ipversion != version: |
|
383 |
continue |
|
384 |
|
|
341 | 385 |
# Update the DB table holding the logging of all IP addresses |
342 |
update_ip_address_log(nic, ip)
|
|
386 |
terminate_active_ipaddress_log(nic, ip)
|
|
343 | 387 |
|
344 |
if ip.ipversion == 4: |
|
345 |
if ip.floating_ip: |
|
346 |
ip.nic = None |
|
347 |
ip.save() |
|
348 |
else: |
|
349 |
ip.release_address() |
|
350 |
if not ip.floating_ip: |
|
388 |
if ip.floating_ip: |
|
389 |
ip.nic = None |
|
390 |
ip.save() |
|
391 |
else: |
|
392 |
# Release the IPv4 address |
|
393 |
ip.release_address() |
|
351 | 394 |
ip.delete() |
352 | 395 |
|
353 | 396 |
|
354 |
def update_ip_address_log(nic, ip):
|
|
397 |
def terminate_active_ipaddress_log(nic, ip):
|
|
355 | 398 |
"""Update DB logging entry for this IP address.""" |
356 | 399 |
if not ip.network.public or nic.machine is None: |
357 | 400 |
return |
b/snf-cyclades-app/synnefo/logic/tests/networks.py | ||
---|---|---|
45 | 45 |
kwargs = { |
46 | 46 |
"name": "test", |
47 | 47 |
"userid": "user", |
48 |
"subnet": "192.168.20.0/24", |
|
49 | 48 |
"flavor": "CUSTOM", |
50 | 49 |
} |
51 |
# wrong gateway |
|
52 |
kw = copy(kwargs) |
|
53 |
kw["gateway"] = "192.168.3.1" |
|
54 |
self.assertRaises(faults.BadRequest, networks.create, **kw) |
|
55 |
# wrong subnet |
|
56 |
kw = copy(kwargs) |
|
57 |
kw["subnet"] = "192.168.2.0" |
|
58 |
self.assertRaises(faults.OverLimit, networks.create, **kw) |
|
59 |
kw["subnet"] = "192.168.0.0/16" |
|
60 |
self.assertRaises(faults.OverLimit, networks.create, **kw) |
|
61 |
kw["subnet"] = "192.168.0.3/24" |
|
62 |
self.assertRaises(faults.BadRequest, networks.create, **kw) |
|
63 | 50 |
# wrong flavor |
64 | 51 |
kw = copy(kwargs) |
65 | 52 |
kw["flavor"] = "UNKNOWN" |
66 | 53 |
self.assertRaises(faults.BadRequest, networks.create, **kw) |
67 | 54 |
# Test create objet |
68 |
kwargs["gateway"] = "192.168.20.1" |
|
69 | 55 |
kwargs["public"] = True |
70 |
kwargs["dhcp"] = False |
|
71 | 56 |
with mocked_quotaholder(): |
72 | 57 |
net = networks.create(**kwargs) |
73 |
self.assertEqual(net.subnet4, "192.168.20.0/24") |
|
74 |
self.assertEqual(net.subnets.get(ipversion=4).gateway, "192.168.20.1") |
|
75 | 58 |
self.assertEqual(net.public, True) |
76 | 59 |
self.assertEqual(net.flavor, "CUSTOM") |
77 |
self.assertEqual(net.subnets.get(ipversion=4).dhcp, False) |
|
78 | 60 |
self.assertEqual(net.action, "CREATE") |
79 | 61 |
self.assertEqual(net.state, "ACTIVE") |
80 | 62 |
self.assertEqual(net.name, "test") |
... | ... | |
126 | 108 |
self.assertEqual(net.mac_prefix, settings.DEFAULT_MAC_PREFIX) |
127 | 109 |
self.assertEqual(net.link, settings.DEFAULT_BRIDGE) |
128 | 110 |
self.assertEqual(net.backend_tag, []) |
129 |
|
|
130 |
def test_create_network_ipv6(self): |
|
131 |
kwargs = { |
|
132 |
"name": "test", |
|
133 |
"userid": "user", |
|
134 |
"flavor": "CUSTOM", |
|
135 |
"subnet6": "2001:648:2ffc:1112::/64", |
|
136 |
} |
|
137 |
# Wrong subnet |
|
138 |
kw = copy(kwargs) |
|
139 |
kw["subnet6"] = "2001:64q:2ffc:1112::/64" |
|
140 |
self.assertRaises(faults.BadRequest, networks.create, **kw) |
|
141 |
# Wrong gateway |
|
142 |
kw = copy(kwargs) |
|
143 |
kw["gateway6"] = "2001:64q:2ffc:1119::1" |
|
144 |
self.assertRaises(faults.BadRequest, networks.create, **kw) |
|
145 |
# floating_ip_pools cannot be ipv6 only |
|
146 |
kw = copy(kwargs) |
|
147 |
kw["floating_ip_pool"] = True |
|
148 |
self.assertRaises(faults.BadRequest, networks.create, **kw) |
|
149 |
kwargs["gateway6"] = "2001:648:2ffc:1112::1" |
|
150 |
with mocked_quotaholder(): |
|
151 |
net = networks.create(**kwargs) |
|
152 |
subnet6 = net.subnets.get(ipversion=6) |
|
153 |
self.assertEqual(subnet6.cidr, "2001:648:2ffc:1112::/64") |
|
154 |
self.assertEqual(subnet6.gateway, "2001:648:2ffc:1112::1") |
|
155 |
self.assertEqual(net.get_ip_pools(), []) |
b/snf-cyclades-app/synnefo/logic/tests/reconciliation.py | ||
---|---|---|
239 | 239 |
"group_list": [["default", |
240 | 240 |
"bridged", |
241 | 241 |
"prv0"]], |
242 |
"network": net1.subnet4, |
|
242 |
"network": net1.subnet4.cidr,
|
|
243 | 243 |
"map": "....", |
244 | 244 |
"external_reservations": ""}] |
245 | 245 |
self.reconciler.reconcile_networks() |
... | ... | |
308 | 308 |
operstate="PENDING") |
309 | 309 |
mrapi().GetNetworks.return_value = [{"name": net.backend_id, |
310 | 310 |
"group_list": [], |
311 |
"network": net.subnet4, |
|
311 |
"network": net.subnet4.cidr,
|
|
312 | 312 |
"map": "....", |
313 | 313 |
"external_reservations": ""}] |
314 | 314 |
self.assertEqual(bn.operstate, "PENDING") |
... | ... | |
321 | 321 |
deleted=True) |
322 | 322 |
mrapi().GetNetworks.return_value = [{"name": net.backend_id, |
323 | 323 |
"group_list": [], |
324 |
"network": net.subnet4, |
|
324 |
"network": net.subnet4.cidr,
|
|
325 | 325 |
"map": "....", |
326 | 326 |
"external_reservations": ""}] |
327 | 327 |
self.reconciler.reconcile_networks() |
Also available in: Unified diff