Commit a8819ad5 authored by Christos Stavrakakis's avatar Christos Stavrakakis
Browse files

cyclades: Refactor code

Move code relative with allocating ips and floating IPs to 'logic.ips'
module.
parent 227ccc21
......@@ -39,7 +39,7 @@ from django.utils import simplejson as json
from snf_django.lib import api
from snf_django.lib.api import faults, utils
from synnefo.api import util
from synnefo import quotas
from synnefo.logic import ips
from synnefo.db.models import Network, IPAddress
from logging import getLogger
......@@ -147,7 +147,7 @@ def allocate_floating_ip(request):
"floating_network_id",
required=False)
if network_id is None:
floating_ip = util.allocate_public_ip(userid, floating_ip=True)
floating_ip = ips.create_floating_ip(userid)
else:
try:
network_id = int(network_id)
......@@ -156,28 +156,12 @@ def allocate_floating_ip(request):
network = util.get_network(network_id, userid, for_update=True,
non_deleted=True)
if not network.floating_ip_pool:
msg = ("Can not allocate floating IP. Network %s is"
" not a floating IP pool.")
raise faults.Conflict(msg % network.id)
if network.action == "DESTROY":
msg = "Can not allocate floating IP. Network %s is being deleted."
raise faults.Conflict(msg % network.id)
address = api.utils.get_attribute(floating_ip_dict,
"floating_ip_address",
required=False)
# Allocate the floating IP
floating_ip = util.allocate_ip(network, userid, address=address,
floating_ip=True)
# Issue commission (quotas)
quotas.issue_and_accept_commission(floating_ip)
transaction.commit()
floating_ip = ips.create_floating_ip(userid, network, address)
log.info("User '%s' allocated floating IP '%s'", userid, floating_ip)
request.serialization = "json"
data = json.dumps({"floatingip": ip_to_dict(floating_ip)})
return HttpResponse(data, status=200)
......@@ -193,23 +177,7 @@ def release_floating_ip(request, floating_ip_id):
floating_ip = util.get_floating_ip_by_id(userid, floating_ip_id,
for_update=True)
if floating_ip.nic:
# This is safe, you also need for_update to attach floating IP to
# instance.
msg = "Floating IP '%s' is attached to instance." % floating_ip.id
raise faults.Conflict(msg)
# Return the address of the floating IP back to pool
floating_ip.release_address()
# And mark the floating IP as deleted
floating_ip.deleted = True
floating_ip.save()
# Release quota for floating IP
quotas.issue_and_accept_commission(floating_ip, delete=True)
transaction.commit()
# Delete the floating IP from DB
floating_ip.delete()
ips.delete_floating_ip(floating_ip)
log.info("User '%s' released IP '%s", userid, floating_ip)
return HttpResponse(status=204)
......
......@@ -33,26 +33,21 @@
from optparse import make_option
from django.db import transaction
from django.core.management.base import BaseCommand, CommandError
from synnefo.management.common import convert_api_faults
from synnefo.logic import ips
from synnefo.api import util
from synnefo.db import pools
from synnefo import quotas
class Command(BaseCommand):
can_import_settings = True
output_transaction = True
help = "Allocate a new floating IP"
option_list = BaseCommand.option_list + (
make_option(
'--pool',
dest='pool',
help="The IP pool to allocate the address from"),
help="The ID of the floating IP pool(network) to allocate the"
" address from"),
make_option(
'--address',
dest='address',
......@@ -61,48 +56,29 @@ class Command(BaseCommand):
'--owner',
dest='owner',
default=None,
# required=True,
help='The owner of the floating IP'),
)
@transaction.commit_on_success
@convert_api_faults
def handle(self, *args, **options):
if args:
raise CommandError("Command doesn't accept any arguments")
pool = options['pool']
network_id = options['pool']
address = options['address']
owner = options['owner']
if not owner:
raise CommandError("'owner' is required for floating IP creation")
if pool is None:
if address:
raise CommandError('Please specify a pool as well')
# User did not specified a pool. Choose a random public IP
try:
floating_ip = util.allocate_public_ip(userid=owner,
floating_ip=True)
except pools.EmptyPool:
raise faults.Conflict("No more IP addresses available.")
else:
try:
network_id = int(pool)
except ValueError:
raise CommandError("Invalid pool ID.")
if network_id is not None:
network = util.get_network(network_id, owner, for_update=True,
non_deleted=True)
if not network.floating_ip_pool:
# Check that it is a floating IP pool
raise CommandError("Floating IP pool %s does not exist." %
network_id)
floating_ip = util.allocate_ip(network, owner, address=address,
floating_ip=True)
else:
network = None
quotas.issue_and_accept_commission(floating_ip)
transaction.commit()
floating_ip = ips.create_floating_ip(userid=owner,
network=network,
address=address)
self.stdout.write("Created floating IP '%s'.\n" % floating_ip)
# Copyright 2012 GRNET S.A. All rights reserved.
# Copyright 2013 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
......@@ -31,18 +31,15 @@
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
from optparse import make_option
#from optparse import make_option
from django.db import transaction
from django.core.management.base import BaseCommand, CommandError
from synnefo.management import common
from synnefo.logic import ips
from synnefo.management.common import get_floating_ip_by_address
from synnefo import quotas
class Command(BaseCommand):
can_import_settings = True
output_transaction = True
help = "Release a floating IP"
@transaction.commit_on_success
......@@ -50,24 +47,9 @@ class Command(BaseCommand):
if not args:
raise CommandError("Please provide a floating-ip address")
address = args[0]
floating_ip = get_floating_ip_by_address(address, for_update=True)
if floating_ip.nic:
# This is safe, you also need for_update to attach floating IP to
# instance.
msg = "Floating IP '%s' is attached to instance." % floating_ip.id
raise CommandError(msg)
# Return the address of the floating IP back to pool
floating_ip.release_address()
# And mark the floating IP as deleted
floating_ip.deleted = True
floating_ip.save()
# Release quota for floating IP
quotas.issue_and_accept_commission(floating_ip, delete=True)
transaction.commit()
# Delete the floating IP from DB
floating_ip.delete()
floating_ip_id = args[0]
self.stdout.write("Deleted floating IP '%s'.\n" % address)
floating_ip = common.get_floating_ip_by_id(floating_ip_id,
for_update=True)
ips.delete_floating_ip(floating_ip)
self.stdout.write("Deleted floating IP '%s'.\n" % floating_ip_id)
......@@ -44,7 +44,7 @@ from snf_django.lib.api import faults
from synnefo.api import util
from synnefo.db.models import NetworkInterface
from synnefo.logic import servers
from synnefo.logic import servers, ips
from logging import getLogger
......@@ -141,8 +141,8 @@ def create_port(request):
ipaddress = util.get_floating_ip_by_address(user_id, fixed_ip_address,
for_update=True)
elif fixed_ip_address:
ipaddress = util.allocate_ip(network, user_id,
address=fixed_ip_address)
ipaddress = ips.allocate_ip(network, user_id,
address=fixed_ip_address)
device_id = api.utils.get_attribute(port_dict, "device_id", required=False)
vm = None
......
......@@ -50,8 +50,6 @@ from synnefo.db.models import (Flavor, VirtualMachine, VirtualMachineMetadata,
Network, NetworkInterface, SecurityGroup,
BridgePoolTable, MacPrefixPoolTable, IPAddress,
IPPoolTable)
from synnefo.db import pools
from synnefo.plankton.utils import image_backend
from synnefo.cyclades_settings import cyclades_services, BASE_HOST
......@@ -272,103 +270,6 @@ def get_floating_ip_by_id(userid, floating_ip_id, for_update=False):
floating_ip_id)
def allocate_ip_from_pools(pool_rows, userid, address=None, floating_ip=False):
"""Try to allocate a value from a number of pools.
This function takes as argument a number of PoolTable objects and tries to
allocate a value from them. If all pools are empty EmptyPool is raised.
If an address is specified and does not belong to any of the pools,
InvalidValue is raised.
"""
for pool_row in pool_rows:
pool = pool_row.pool
try:
value = pool.get(value=address)
pool.save()
subnet = pool_row.subnet
ipaddress = IPAddress.objects.create(subnet=subnet,
network=subnet.network,
userid=userid,
address=value,
floating_ip=floating_ip)
return ipaddress
except pools.EmptyPool:
pass
except pools.InvalidValue:
pass
if address is None:
raise pools.EmptyPool("No more IP addresses available on pools %s" %
pool_rows)
else:
raise pools.InvalidValue("Address %s does not belong to pools %s" %
(address, pool_rows))
def allocate_ip(network, userid, address=None, floating_ip=False):
"""Try to allocate an IP from networks IP pools."""
if network.action == "DESTROY":
raise faults.Conflict("Can not allocate IP. Network %s is being"
" deleted" % network.id)
ip_pools = IPPoolTable.objects.select_for_update()\
.filter(subnet__network=network)
try:
return allocate_ip_from_pools(ip_pools, userid, address=address,
floating_ip=floating_ip)
except pools.EmptyPool:
raise faults.Conflict("No more IP addresses available on network %s"
% network.id)
except pools.ValueNotAvailable:
raise faults.Conflict("IP address %s is already used." % address)
except pools.InvalidValue:
raise faults.BadRequest("Address %s does not belong to network %s" %
(address, network.id))
def allocate_public_ip(userid, floating_ip=False, backend=None):
"""Try to allocate a public or floating IP address.
Try to allocate a a public IPv4 address from one of the available networks.
If 'floating_ip' is set, only networks which are floating IP pools will be
used and the IPAddress that will be created will be marked as a floating
IP. If 'backend' is set, only the networks that exist in this backend will
be used.
"""
ip_pool_rows = IPPoolTable.objects.select_for_update()\
.prefetch_related("subnet__network")\
.filter(subnet__deleted=False)\
.filter(subnet__network__deleted=False)\
.filter(subnet__network__public=True)\
.filter(subnet__network__drained=False)
if floating_ip:
ip_pool_rows = ip_pool_rows\
.filter(subnet__network__floating_ip_pool=True)
if backend is not None:
ip_pool_rows = ip_pool_rows\
.filter(subnet__network__backend_networks__backend=backend)
try:
return allocate_ip_from_pools(ip_pool_rows, userid,
floating_ip=floating_ip)
except pools.EmptyPool:
ip_type = "floating" if floating_ip else "public"
log_msg = "Failed to allocate a %s IP. Reason:" % ip_type
if ip_pool_rows:
log_msg += " No network exists."
else:
log_msg += " All network are full."
if backend is not None:
log_msg += " Backend: %s" % backend
log.error(log_msg)
exception_msg = "Can not allocate a %s IP address." % ip_type
if floating_ip:
raise faults.Conflict(exception_msg)
else:
raise faults.ServiceUnavailable(exception_msg)
def backend_has_free_public_ip(backend):
"""Check if a backend has a free public IPv4 address."""
ip_pool_rows = IPPoolTable.objects.select_for_update()\
......
......@@ -38,9 +38,9 @@ from synnefo.db.models import (Backend, VirtualMachine, Network,
BackendNetwork, BACKEND_STATUSES,
pooled_rapi_client, VirtualMachineDiagnostic,
Flavor, IPAddressLog)
from synnefo.logic import utils
from synnefo.logic import utils, ips
from synnefo import quotas
from synnefo.api.util import release_resource, allocate_ip
from synnefo.api.util import release_resource
from synnefo.util.mac2eui64 import mac2eui64
from synnefo.logic.rapi import GanetiApiError
......@@ -273,8 +273,8 @@ def _process_net_status(vm, etime, nics):
remove_nic_ips(db_nic)
if ipv4_address:
network = ganeti_nic["network"]
ipaddress = allocate_ip(network, vm.userid,
address=ipv4_address)
ipaddress = ips.allocate_ip(network, vm.userid,
address=ipv4_address)
ipaddress.nic = nic
ipaddress.save()
......
......@@ -10,9 +10,8 @@ from snf_django.lib.api import faults
from django.conf import settings
from synnefo import quotas
from synnefo.api import util
from synnefo.logic import backend
from synnefo.logic import backend, ips
from synnefo.logic.backend_allocator import BackendAllocator
from synnefo.db import pools
from synnefo.db.models import (NetworkInterface, VirtualMachine,
VirtualMachineMetadata, IPAddressLog)
from vncauthproxy.client import request_forwarding as request_vnc_forwarding
......@@ -243,8 +242,8 @@ def create_instance_nics(vm, userid, networks=[], floating_ips=[]):
ports = []
for network_id in settings.DEFAULT_INSTANCE_NETWORKS:
if network_id == "SNF:ANY_PUBLIC":
ipaddress = util.allocate_public_ip(userid=userid,
backend=vm.backend)
ipaddress = ips.allocate_public_ip(userid=userid,
backend=vm.backend)
port = _create_port(userid, network=ipaddress.network,
use_ipaddress=ipaddress)
else:
......@@ -480,12 +479,8 @@ def _create_port(userid, network, machine=None, use_ipaddress=None,
# If network has IPv4 subnets, try to allocate the address that the
# the user specified or a random one.
if network.subnets.filter(ipversion=4).exists():
try:
ipaddress = util.allocate_ip(network, userid=userid,
address=address)
except pools.ValueNotAvailable:
msg = "Address %s is already in use." % address
raise faults.Conflict(msg)
ipaddress = ips.allocate_ip(network, userid=userid,
address=address)
elif address is not None:
raise faults.BadRequest("Address %s is not a valid IP for the"
" defined network subnets" % address)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment