Revision fae6e5f0 snf-cyclades-app/synnefo/logic/servers.py
b/snf-cyclades-app/synnefo/logic/servers.py | ||
---|---|---|
12 | 12 |
from synnefo.api import util |
13 | 13 |
from synnefo.logic import backend |
14 | 14 |
from synnefo.logic.backend_allocator import BackendAllocator |
15 |
from synnefo.db import pools |
|
15 | 16 |
from synnefo.db.models import (NetworkInterface, VirtualMachine, |
16 |
VirtualMachineMetadata, IPAddress, |
|
17 |
IPAddressLog) |
|
18 |
from synnefo.db import query as db_query, pools |
|
19 |
|
|
17 |
VirtualMachineMetadata, IPAddressLog) |
|
20 | 18 |
from vncauthproxy.client import request_forwarding as request_vnc_forwarding |
21 | 19 |
|
22 | 20 |
log = logging.getLogger(__name__) |
... | ... | |
247 | 245 |
if network_id == "SNF:ANY_PUBLIC": |
248 | 246 |
ipaddress = util.allocate_public_ip(userid=userid, |
249 | 247 |
backend=vm.backend) |
250 |
nic, ipaddress = create_nic(vm, ipaddress=ipaddress) |
|
248 |
nic = _create_port(userid, network=ipaddress.network, |
|
249 |
use_ipaddress=ipaddress) |
|
251 | 250 |
else: |
252 | 251 |
try: |
253 | 252 |
network = util.get_network(network_id, userid, |
... | ... | |
258 | 257 |
" network '%s'" % network_id |
259 | 258 |
log.error(msg) |
260 | 259 |
raise faults.InternalServerError(msg) |
261 |
nic, ipaddress = create_nic(vm, network=network)
|
|
260 |
nic = _create_port(userid, network)
|
|
262 | 261 |
nics.append(nic) |
263 | 262 |
for address in floating_ips: |
264 | 263 |
floating_ip = util.get_floating_ip_by_address(vm.userid, address, |
265 | 264 |
for_update=True) |
266 |
nic, ipaddress = create_nic(vm, ipaddress=floating_ip) |
|
265 |
nic = _create_port(userid, network=floating_ip.network, |
|
266 |
use_ipaddress=floating_ip) |
|
267 | 267 |
nics.append(nic) |
268 | 268 |
for network_id in private_networks: |
269 | 269 |
network = util.get_network(network_id, userid, non_deleted=True) |
270 | 270 |
if network.public: |
271 | 271 |
raise faults.Forbidden("Can not connect to public network") |
272 |
nic, ipaddress = create_nic(vm, network=network)
|
|
272 |
nic = _create_port(userid, network)
|
|
273 | 273 |
nics.append(nic) |
274 | 274 |
for index, nic in enumerate(nics): |
275 |
associate_port_with_machine(nic, vm) |
|
275 | 276 |
nic.index = index |
276 | 277 |
nic.save() |
277 | 278 |
return nics |
278 | 279 |
|
279 | 280 |
|
280 |
def create_nic(vm, network=None, ipaddress=None, address=None, name=None): |
|
281 |
"""Helper functions for create NIC objects. |
|
282 |
|
|
283 |
Create a NetworkInterface connecting a VirtualMachine to a network with the |
|
284 |
IPAddress specified. If no 'ipaddress' is passed and the network has an |
|
285 |
IPv4 subnet, then an IPv4 address will be automatically be allocated. |
|
286 |
|
|
287 |
""" |
|
288 |
userid = vm.userid |
|
289 |
|
|
290 |
if ipaddress is None: |
|
291 |
if network.subnets.filter(ipversion=4).exists(): |
|
292 |
try: |
|
293 |
ipaddress = util.allocate_ip(network, userid=userid, |
|
294 |
address=address) |
|
295 |
except pools.ValueNotAvailable: |
|
296 |
raise faults.Conflict("Address '%s' is not available." % |
|
297 |
address) |
|
298 |
|
|
299 |
if ipaddress is not None and ipaddress.nic is not None: |
|
300 |
raise faults.Conflict("IP address '%s' already in use" % |
|
301 |
ipaddress.address) |
|
302 |
|
|
303 |
if network is None: |
|
304 |
network = ipaddress.network |
|
305 |
elif network.state != 'ACTIVE': |
|
306 |
# TODO: What if is in settings ? |
|
307 |
raise faults.BuildInProgress('Network not active yet') |
|
308 |
|
|
309 |
#device_owner = "router" if vm.router else "vm" |
|
310 |
device_owner = "vm" |
|
311 |
nic = NetworkInterface.objects.create(machine=vm, network=network, |
|
312 |
state="BUILD", |
|
313 |
userid=vm.userid, |
|
314 |
device_owner=device_owner, |
|
315 |
name=name) |
|
316 |
log.debug("Created NIC %s with IP %s", nic, ipaddress) |
|
317 |
if ipaddress is not None: |
|
318 |
ipaddress.nic = nic |
|
319 |
ipaddress.save() |
|
320 |
|
|
321 |
if ipaddress.network.public: |
|
322 |
ip_log = IPAddressLog.objects.create( |
|
323 |
server_id=vm.id, |
|
324 |
network_id=ipaddress.network_id, |
|
325 |
address=ipaddress.address, |
|
326 |
active=True) |
|
327 |
log.debug("Created IP log entry %s", ip_log) |
|
328 |
|
|
329 |
return nic, ipaddress |
|
330 |
|
|
331 |
|
|
332 | 281 |
@server_command("DESTROY") |
333 | 282 |
def destroy(vm): |
334 | 283 |
log.info("Deleting VM %s", vm) |
... | ... | |
395 | 344 |
@server_command("CONNECT") |
396 | 345 |
def connect(vm, network, port=None): |
397 | 346 |
if port is None: |
398 |
nic, ipaddress = create_nic(vm, network) |
|
399 |
else: |
|
400 |
nic = port |
|
401 |
ipaddress = port.ips.all()[0] |
|
347 |
port = _create_port(vm.userid, network) |
|
348 |
associate_port_with_machine(port, vm) |
|
402 | 349 |
|
403 |
log.info("Creating NIC %s with IPAddress %s", nic, ipaddress)
|
|
350 |
log.info("Creating NIC %s with IPv4 Address %s", port, port.ipv4_address)
|
|
404 | 351 |
|
405 |
return backend.connect_to_network(vm, nic)
|
|
352 |
return backend.connect_to_network(vm, port)
|
|
406 | 353 |
|
407 | 354 |
|
408 | 355 |
@server_command("DISCONNECT") |
... | ... | |
467 | 414 |
return console |
468 | 415 |
|
469 | 416 |
|
470 |
@server_command("CONNECT") |
|
471 |
def add_floating_ip(vm, address): |
|
472 |
# Use for_update, to guarantee that floating IP will only by assigned once |
|
473 |
# and that it can not be released will it is being attached! |
|
474 |
floating_ip = util.get_floating_ip_by_address(vm.userid, address, |
|
475 |
for_update=True) |
|
476 |
nic, floating_ip = create_nic(vm, ipaddress=floating_ip) |
|
477 |
log.info("Created NIC %s with floating IP %s", nic, floating_ip) |
|
478 |
return backend.connect_to_network(vm, nic) |
|
479 |
|
|
480 |
|
|
481 |
@server_command("DISCONNECT") |
|
482 |
def remove_floating_ip(vm, address): |
|
483 |
try: |
|
484 |
floating_ip = db_query.get_server_floating_ip(server=vm, |
|
485 |
address=address, |
|
486 |
for_update=True) |
|
487 |
except IPAddress.DoesNotExist: |
|
488 |
raise faults.BadRequest("Server '%s' has no floating ip with" |
|
489 |
" address '%s'" % (vm, address)) |
|
490 |
|
|
491 |
nic = floating_ip.nic |
|
492 |
log.info("Removing NIC %s from VM %s. Floating IP '%s'", str(nic.index), |
|
493 |
vm, floating_ip) |
|
494 |
|
|
495 |
return backend.disconnect_from_network(vm, nic) |
|
496 |
|
|
497 |
|
|
498 | 417 |
def rename(server, new_name): |
499 | 418 |
"""Rename a VirtualMachine.""" |
500 | 419 |
old_name = server.name |
... | ... | |
503 | 422 |
log.info("Renamed server '%s' from '%s' to '%s'", server, old_name, |
504 | 423 |
new_name) |
505 | 424 |
return server |
425 |
|
|
426 |
|
|
427 |
@transaction.commit_on_success |
|
428 |
def create_port(*args, **kwargs): |
|
429 |
return _create_port(*args, **kwargs) |
|
430 |
|
|
431 |
|
|
432 |
def _create_port(userid, network, machine=None, use_ipaddress=None, |
|
433 |
address=None, name="", security_groups=None, |
|
434 |
device_owner=None): |
|
435 |
"""Create a new port on the specified network. |
|
436 |
|
|
437 |
Create a new Port(NetworkInterface model) on the specified Network. If |
|
438 |
'machine' is specified, the machine will be connected to the network using |
|
439 |
this port. If 'use_ipaddress' argument is specified, the port will be |
|
440 |
assigned this IPAddress. Otherwise, an IPv4 address from the IPv4 subnet |
|
441 |
will be allocated. |
|
442 |
|
|
443 |
""" |
|
444 |
if network.state != "ACTIVE": |
|
445 |
raise faults.BuildInProgress("Can not create port while network is in" |
|
446 |
" state %s" % network.state) |
|
447 |
ipaddress = None |
|
448 |
if use_ipaddress is not None: |
|
449 |
# Use an existing IPAddress object. |
|
450 |
ipaddress = use_ipaddress |
|
451 |
if ipaddress and (ipaddress.network_id != network.id): |
|
452 |
msg = "IP Address %s does not belong to network %s" |
|
453 |
raise faults.Conflict(msg % (ipaddress.address, network.id)) |
|
454 |
else: |
|
455 |
# If network has IPv4 subnets, try to allocate the address that the |
|
456 |
# the user specified or a random one. |
|
457 |
if network.subnets.filter(ipversion=4).exists(): |
|
458 |
try: |
|
459 |
ipaddress = util.allocate_ip(network, userid=userid, |
|
460 |
address=address) |
|
461 |
except pools.ValueNotAvailable: |
|
462 |
msg = "Address %s is already in use." % address |
|
463 |
raise faults.Conflict(msg) |
|
464 |
elif address is not None: |
|
465 |
raise faults.BadRequest("Address %s is not a valid IP for the" |
|
466 |
" defined network subnets" % address) |
|
467 |
|
|
468 |
if ipaddress is not None and ipaddress.nic is not None: |
|
469 |
raise faults.Conflict("IP address '%s' is already in use" % |
|
470 |
ipaddress.address) |
|
471 |
|
|
472 |
port = NetworkInterface.objects.create(network=network, |
|
473 |
state="DOWN", |
|
474 |
userid=userid, |
|
475 |
device_owner=None, |
|
476 |
name=name) |
|
477 |
|
|
478 |
# add the security groups if any |
|
479 |
if security_groups: |
|
480 |
port.security_groups.add(*security_groups) |
|
481 |
|
|
482 |
if ipaddress is not None: |
|
483 |
# Associate IPAddress with the Port |
|
484 |
ipaddress.nic = port |
|
485 |
ipaddress.save() |
|
486 |
|
|
487 |
if machine is not None: |
|
488 |
# Associate Port(NIC) with VirtualMachine |
|
489 |
port = associate_port_with_machine(port, machine) |
|
490 |
# Send job to connect port to instance |
|
491 |
machine = connect(machine, network, port) |
|
492 |
jobID = machine.task_job_id |
|
493 |
log.info("Created Port %s with IP %s. Ganeti Job: %s", |
|
494 |
port, ipaddress, jobID) |
|
495 |
else: |
|
496 |
log.info("Created Port %s with IP %s not attached to any instance", |
|
497 |
port, ipaddress) |
|
498 |
|
|
499 |
return port |
|
500 |
|
|
501 |
|
|
502 |
def associate_port_with_machine(port, machine): |
|
503 |
"""Associate a Port with a VirtualMachine. |
|
504 |
|
|
505 |
Associate the port with the VirtualMachine and add an entry to the |
|
506 |
IPAddressLog if the port has a public IPv4 address from a public network. |
|
507 |
|
|
508 |
""" |
|
509 |
if port.network.public: |
|
510 |
ipv4_address = port.ipv4_address |
|
511 |
if ipv4_address is not None: |
|
512 |
ip_log = IPAddressLog.objects.create(server_id=machine.id, |
|
513 |
network_id=port.network_id, |
|
514 |
address=ipv4_address, |
|
515 |
active=True) |
|
516 |
log.debug("Created IP log entry %s", ip_log) |
|
517 |
port.machine = machine |
|
518 |
port.state = "BUILD" |
|
519 |
port.device_owner = "vm" |
|
520 |
port.save() |
|
521 |
return port |
|
522 |
|
|
523 |
|
|
524 |
@transaction.commit_on_success |
|
525 |
def delete_port(port): |
|
526 |
"""Delete a port by removing the NIC card from the instance. |
|
527 |
|
|
528 |
Send a Job to remove the NIC card from the instance. The port |
|
529 |
will be deleted and the associated IPv4 addressess will be released |
|
530 |
when the job completes successfully. |
|
531 |
|
|
532 |
""" |
|
533 |
|
|
534 |
if port.machine is not None: |
|
535 |
vm = disconnect(port.machine, port) |
|
536 |
log.info("Removing port %s, Job: %s", port, vm.task_job_id) |
|
537 |
else: |
|
538 |
backend.remove_nic_ips(port) |
|
539 |
port.delete() |
|
540 |
log.info("Removed port %s", port) |
|
541 |
|
|
542 |
return port |
Also available in: Unified diff