Commit 6d8cb9e5 authored by Christos Stavrakakis's avatar Christos Stavrakakis
Browse files

cyclades: Reserve a specific floating IP

Add extra optional 'address' attribute, in  POST /os-floating-ips/
request, to allow a user to reserve a specific floating IP. This request
will fail if the user tries to allocate an IP address that is used by
anothers user VM (it will succeed if they address is already used by
the same user).
parent d4b508f8
......@@ -40,7 +40,7 @@ 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.db.models import Network, FloatingIP
from synnefo.db.models import Network, FloatingIP, NetworkInterface
from logging import getLogger
......@@ -137,10 +137,30 @@ def allocate_floating_ip(request):
except Network.DoesNotExist:
raise faults.ItemNotFound("Pool '%s' does not exist." % pool)
address = req.get("address", None)
machine = None
try:
address = util.get_network_free_address(network)
if address is None:
address = util.get_network_free_address(network) # Get X-Lock
else:
if FloatingIP.objects.filter(network=network,
ipv4=address).exists():
msg = "Floating IP '%s' is reserved" % address
raise faults.Conflict(msg)
pool = network.get_pool() # Gets X-Lock
if not pool.contains(address):
raise faults.BadRequest("Invalid address")
if not pool.is_available(address):
try:
network.nics.get(ipv4=address,
machine__userid=userid)
except NetworkInterface.DoesNotExist:
msg = "Address '%s' is already in use" % address
raise faults.Conflict(msg)
pool.reserve(address)
pool.save()
floating_ip = FloatingIP.objects.create(ipv4=address, network=network,
userid=userid)
userid=userid, machine=machine)
quotas.issue_and_accept_commission(floating_ip)
except:
transaction.rollback()
......
......@@ -108,6 +108,50 @@ class FloatingIPAPITest(BaseAPITest):
response = self.post(URL, "test_user", json.dumps(request), "json")
self.assertEqual(response.status_code, 413)
def test_reserve_with_address(self):
net = NetworkFactory(userid="test_user", subnet="192.168.2.0/24",
gateway=None, public=True)
request = {'pool': net.id, "address": "192.168.2.10"}
with mocked_quotaholder():
response = self.post(URL, "test_user", json.dumps(request), "json")
self.assertSuccess(response)
self.assertEqual(json.loads(response.content)["floating_ip"],
{"instance_id": None, "ip": "192.168.2.10",
"fixed_ip": None, "id": "1", "pool": "1"})
# Already reserved
FloatingIPFactory(network=net, ipv4="192.168.2.3")
request = {'pool': net.id, "address": "192.168.2.3"}
with mocked_quotaholder():
response = self.post(URL, "test_user", json.dumps(request), "json")
self.assertFault(response, 409, "conflict")
# Already used
pool = net.get_pool()
pool.reserve("192.168.2.5")
pool.save()
# ..by another_user
nic = NetworkInterfaceFactory(network=net, ipv4="192.168.2.5",
machine__userid="test2")
request = {'pool': net.id, "address": "192.168.2.5"}
with mocked_quotaholder():
response = self.post(URL, "test_user", json.dumps(request), "json")
self.assertFault(response, 409, "conflict")
# ..and by him
nic.delete()
NetworkInterfaceFactory(network=net, ipv4="192.168.2.5",
machine__userid="test_user")
request = {'pool': net.id, "address": "192.168.2.5"}
with mocked_quotaholder():
response = self.post(URL, "test_user", json.dumps(request), "json")
self.assertSuccess(response)
# Address out of pool
request = {'pool': net.id, "address": "192.168.3.5"}
with mocked_quotaholder():
response = self.post(URL, "test_user", json.dumps(request), "json")
self.assertBadRequest(response)
def test_release_in_use(self):
ip = FloatingIPFactory()
vm = ip.machine
......
......@@ -264,3 +264,7 @@ class IPPool(PoolManager):
def index_to_value(self, index):
return str(self.net[index])
def contains(self, address):
addr = ipaddr.IPAddress(address)
return addr in self.net
......@@ -220,6 +220,8 @@ class IPPoolTestCase(TestCase):
self.assertEqual(pool.is_available('192.168.2.255'), False)
self.assertEqual(pool.count_available(), 253)
self.assertEqual(pool.get(), '192.168.2.2')
self.assertTrue(pool.contains("192.168.2.10"))
self.assertFalse(pool.contains("192.168.3.10"))
def test_auto_reservations_2(self):
obj = DummyObject(0)
......
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