Revision 92d2d1ce
b/snf-cyclades-app/synnefo/api/floating_ips.py | ||
---|---|---|
234 | 234 |
|
235 | 235 |
|
236 | 236 |
def network_to_pool(network): |
237 |
pool = network.get_pool(with_lock=False)
|
|
237 |
pool = network.get_pool(locked=False)
|
|
238 | 238 |
return {"name": str(network.id), |
239 | 239 |
"size": pool.pool_size, |
240 | 240 |
"free": pool.count_available()} |
b/snf-cyclades-app/synnefo/api/servers.py | ||
---|---|---|
43 | 43 |
from snf_django.lib.api import faults, utils |
44 | 44 |
|
45 | 45 |
from synnefo.api import util |
46 |
from synnefo.db import query as db_query |
|
46 | 47 |
from synnefo.db.models import (VirtualMachine, VirtualMachineMetadata) |
47 | 48 |
from synnefo.logic import servers, utils as logic_utils |
48 | 49 |
|
... | ... | |
108 | 109 |
d = {'id': nic.id, |
109 | 110 |
'network_id': str(nic.network.id), |
110 | 111 |
'mac_address': nic.mac, |
111 |
'ipv4': nic.ipv4, |
|
112 |
'ipv6': nic.ipv6, |
|
113 |
'OS-EXT-IPS:type': nic.ip_type.lower()} |
|
112 |
'ipv4': '', |
|
113 |
'ipv6': ''} |
|
114 |
for ip in nic.ips.filter(deleted=False).select_related("subnet"): |
|
115 |
ip_type = "floating" if ip.floating_ip else "fixed" |
|
116 |
if ip.subnet.ipversion == 4: |
|
117 |
d["ipv4"] = ip.address |
|
118 |
d["OS-EXT-IPS:type"] = ip_type |
|
119 |
else: |
|
120 |
d["ipv6"] = ip.address |
|
121 |
d["OS-EXT-IPS:type"] = ip_type |
|
114 | 122 |
|
115 | 123 |
if nic.firewall_profile: |
116 | 124 |
d['firewallProfile'] = nic.firewall_profile |
... | ... | |
121 | 129 |
addresses = {} |
122 | 130 |
for nic in attachments: |
123 | 131 |
net_nics = [] |
124 |
net_nics.append({"version": 4, |
|
125 |
"addr": nic["ipv4"], |
|
126 |
"OS-EXT-IPS:type": nic["OS-EXT-IPS:type"]}) |
|
132 |
if nic["ipv4"]: |
|
133 |
net_nics.append({"version": 4, |
|
134 |
"addr": nic["ipv4"], |
|
135 |
"OS-EXT-IPS:type": nic["OS-EXT-IPS:type"]}) |
|
127 | 136 |
if nic["ipv6"]: |
128 | 137 |
net_nics.append({"version": 6, |
129 | 138 |
"addr": nic["ipv6"], |
... | ... | |
180 | 189 |
def get_server_fqdn(vm): |
181 | 190 |
fqdn_setting = settings.CYCLADES_SERVERS_FQDN |
182 | 191 |
if fqdn_setting is None: |
183 |
public_nics = vm.nics.filter(network__public=True, state="ACTIVE") |
|
184 | 192 |
# Return the first public IPv4 address if exists |
185 |
ipv4_nics = public_nics.exclude(ipv4=None)
|
|
186 |
if ipv4_nics:
|
|
187 |
return ipv4_nics[0].ipv4
|
|
188 |
# Else return the first public IPv6 address if exists
|
|
189 |
ipv6_nics = public_nics.exclude(ipv6=None)
|
|
190 |
if ipv6_nics:
|
|
191 |
return ipv6_nics[0].ipv6
|
|
192 |
return ""
|
|
193 |
address = db_query.get_server_public_ip(server=vm, version=4)
|
|
194 |
if address is None:
|
|
195 |
# Else return the first public IPv6 address if exists
|
|
196 |
address = db_query.get_server_public_ip(server=vm, version=6)
|
|
197 |
if address is None:
|
|
198 |
return ""
|
|
199 |
else:
|
|
200 |
return address
|
|
193 | 201 |
elif isinstance(fqdn_setting, basestring): |
194 | 202 |
return fqdn_setting % {"id": vm.id} |
195 | 203 |
else: |
... | ... | |
214 | 222 |
port_forwarding = {} |
215 | 223 |
for dport, to_dest in settings.CYCLADES_PORT_FORWARDING.items(): |
216 | 224 |
if hasattr(to_dest, "__call__"): |
217 |
public_nics = vm.nics.filter(network__public=True, state="ACTIVE")\ |
|
218 |
.exclude(ipv4=None).order_by('index') |
|
219 |
if public_nics: |
|
220 |
vm_ipv4 = public_nics[0].ipv4 |
|
221 |
else: |
|
222 |
vm_ipv4 = None |
|
223 |
to_dest = to_dest(vm_ipv4, vm.id, fqdn, vm.userid) |
|
225 |
address = db_query.get_server_public_ip(server=vm, version=4) |
|
226 |
to_dest = to_dest(address, vm.id, fqdn, vm.userid) |
|
224 | 227 |
msg = ("Invalid setting: CYCLADES_PORT_FOWARDING." |
225 | 228 |
" Value must be a tuple of two elements (host, port).") |
226 | 229 |
if to_dest is None: |
b/snf-cyclades-app/synnefo/api/tests/floating_ips.py | ||
---|---|---|
35 | 35 |
|
36 | 36 |
from snf_django.utils.testing import BaseAPITest, mocked_quotaholder |
37 | 37 |
from synnefo.db.models import IPAddress |
38 |
from synnefo.db.models_factory import (IPAddressFactory, NetworkFactory,
|
|
38 |
from synnefo.db.models_factory import (FloatingIPFactory, NetworkFactory,
|
|
39 | 39 |
VirtualMachineFactory, |
40 | 40 |
NetworkInterfaceFactory, |
41 | 41 |
BackendNetworkFactory) |
... | ... | |
52 | 52 |
NETWORKS_URL = join_urls(compute_path, "networks") |
53 | 53 |
SERVERS_URL = join_urls(compute_path, "servers") |
54 | 54 |
|
55 |
IPAddressPoolFactory = partial(NetworkFactory, public=True, deleted=False, |
|
55 |
|
|
56 |
floating_ips = IPAddress.objects.filter(floating_ip=True) |
|
57 |
FloatingIPPoolFactory = partial(NetworkFactory, public=True, deleted=False, |
|
56 | 58 |
floating_ip_pool=True) |
57 | 59 |
|
58 | 60 |
|
59 |
class IPAddressAPITest(BaseAPITest):
|
|
61 |
class FloatingIPAPITest(BaseAPITest):
|
|
60 | 62 |
def test_no_floating_ip(self): |
61 | 63 |
response = self.get(URL) |
62 | 64 |
self.assertSuccess(response) |
63 | 65 |
self.assertEqual(json.loads(response.content)["floating_ips"], []) |
64 | 66 |
|
65 | 67 |
def test_list_ips(self): |
66 |
ip = IPAddressFactory(userid="user1")
|
|
67 |
IPAddressFactory(userid="user1", deleted=True)
|
|
68 |
ip = FloatingIPFactory(userid="user1")
|
|
69 |
FloatingIPFactory(userid="user1", deleted=True)
|
|
68 | 70 |
with mocked_quotaholder(): |
69 | 71 |
response = self.get(URL, "user1") |
70 | 72 |
self.assertSuccess(response) |
... | ... | |
75 | 77 |
str(ip.network.id)}) |
76 | 78 |
|
77 | 79 |
def test_get_ip(self): |
78 |
ip = IPAddressFactory(userid="user1")
|
|
80 |
ip = FloatingIPFactory(userid="user1")
|
|
79 | 81 |
with mocked_quotaholder(): |
80 | 82 |
response = self.get(URL + "/%s" % ip.id, "user1") |
81 | 83 |
self.assertSuccess(response) |
... | ... | |
86 | 88 |
str(ip.network.id)}) |
87 | 89 |
|
88 | 90 |
def test_wrong_user(self): |
89 |
ip = IPAddressFactory(userid="user1")
|
|
91 |
ip = FloatingIPFactory(userid="user1")
|
|
90 | 92 |
with mocked_quotaholder(): |
91 | 93 |
response = self.delete(URL + "/%s" % ip.id, "user2") |
92 | 94 |
self.assertItemNotFound(response) |
93 | 95 |
|
94 | 96 |
def test_deleted_ip(self): |
95 |
ip = IPAddressFactory(userid="user1", deleted=True)
|
|
97 |
ip = FloatingIPFactory(userid="user1", deleted=True)
|
|
96 | 98 |
with mocked_quotaholder(): |
97 | 99 |
response = self.delete(URL + "/%s" % ip.id, "user1") |
98 | 100 |
self.assertItemNotFound(response) |
99 | 101 |
|
100 | 102 |
def test_reserve(self): |
101 |
net = IPAddressPoolFactory(userid="test_user",
|
|
103 |
net = FloatingIPPoolFactory(userid="test_user",
|
|
102 | 104 |
subnet="192.168.2.0/24", |
103 | 105 |
gateway=None) |
104 | 106 |
request = {'pool': net.id} |
105 | 107 |
with mocked_quotaholder(): |
106 | 108 |
response = self.post(URL, "test_user", json.dumps(request), "json") |
107 | 109 |
self.assertSuccess(response) |
108 |
ip = IPAddress.objects.get()
|
|
110 |
ip = floating_ips.get()
|
|
109 | 111 |
self.assertEqual(ip.ipv4, "192.168.2.1") |
110 | 112 |
self.assertEqual(ip.machine, None) |
111 | 113 |
self.assertEqual(ip.network, net) |
... | ... | |
120 | 122 |
response = self.post(URL, "test_user", json.dumps({}), "json") |
121 | 123 |
self.assertFault(response, 413, "overLimit") |
122 | 124 |
# Full network |
123 |
IPAddressPoolFactory(userid="test_user",
|
|
125 |
FloatingIPPoolFactory(userid="test_user",
|
|
124 | 126 |
subnet="192.168.2.0/32", |
125 | 127 |
gateway=None) |
126 | 128 |
with mocked_quotaholder(): |
127 | 129 |
response = self.post(URL, "test_user", json.dumps({}), "json") |
128 | 130 |
self.assertFault(response, 413, "overLimit") |
129 | 131 |
# Success |
130 |
net2 = IPAddressPoolFactory(userid="test_user",
|
|
132 |
net2 = FloatingIPPoolFactory(userid="test_user",
|
|
131 | 133 |
subnet="192.168.2.0/24", |
132 | 134 |
gateway=None) |
133 | 135 |
with mocked_quotaholder(): |
134 | 136 |
response = self.post(URL, "test_user", json.dumps({}), "json") |
135 | 137 |
self.assertSuccess(response) |
136 |
ip = IPAddress.objects.get()
|
|
138 |
ip = floating_ips.get()
|
|
137 | 139 |
self.assertEqual(json.loads(response.content)["floating_ip"], |
138 | 140 |
{"instance_id": None, "ip": "192.168.2.1", |
139 | 141 |
"fixed_ip": None, "id": str(ip.id), |
140 | 142 |
"pool": str(net2.id)}) |
141 | 143 |
|
142 | 144 |
def test_reserve_full(self): |
143 |
net = IPAddressPoolFactory(userid="test_user",
|
|
145 |
net = FloatingIPPoolFactory(userid="test_user",
|
|
144 | 146 |
subnet="192.168.2.0/32") |
145 | 147 |
request = {'pool': net.id} |
146 | 148 |
with mocked_quotaholder(): |
... | ... | |
148 | 150 |
self.assertEqual(response.status_code, 413) |
149 | 151 |
|
150 | 152 |
def test_reserve_with_address(self): |
151 |
net = IPAddressPoolFactory(userid="test_user",
|
|
153 |
net = FloatingIPPoolFactory(userid="test_user",
|
|
152 | 154 |
subnet="192.168.2.0/24") |
153 | 155 |
request = {'pool': net.id, "address": "192.168.2.10"} |
154 | 156 |
with mocked_quotaholder(): |
155 | 157 |
response = self.post(URL, "test_user", json.dumps(request), "json") |
156 | 158 |
self.assertSuccess(response) |
157 |
ip = IPAddress.objects.get()
|
|
159 |
ip = floating_ips.get()
|
|
158 | 160 |
self.assertEqual(json.loads(response.content)["floating_ip"], |
159 | 161 |
{"instance_id": None, "ip": "192.168.2.10", |
160 | 162 |
"fixed_ip": None, "id": str(ip.id), "pool": |
161 | 163 |
str(net.id)}) |
162 | 164 |
|
163 | 165 |
# Already reserved |
164 |
IPAddressFactory(network=net, ipv4="192.168.2.3")
|
|
166 |
FloatingIPFactory(network=net, ipv4="192.168.2.3")
|
|
165 | 167 |
request = {'pool': net.id, "address": "192.168.2.3"} |
166 | 168 |
with mocked_quotaholder(): |
167 | 169 |
response = self.post(URL, "test_user", json.dumps(request), "json") |
... | ... | |
194 | 196 |
self.assertBadRequest(response) |
195 | 197 |
|
196 | 198 |
def test_release_in_use(self): |
197 |
ip = IPAddressFactory()
|
|
199 |
ip = FloatingIPFactory()
|
|
198 | 200 |
vm = ip.machine |
199 | 201 |
vm.operstate = "ACTIVE" |
200 | 202 |
vm.userid = ip.userid |
... | ... | |
218 | 220 |
self.assertFault(response, 409, "conflict") |
219 | 221 |
|
220 | 222 |
def test_release(self): |
221 |
ip = IPAddressFactory(machine=None)
|
|
223 |
ip = FloatingIPFactory(machine=None)
|
|
222 | 224 |
with mocked_quotaholder(): |
223 | 225 |
response = self.delete(URL + "/%s" % ip.id, ip.userid) |
224 | 226 |
self.assertSuccess(response) |
225 |
ips_after = IPAddress.objects.filter(id=ip.id)
|
|
227 |
ips_after = floating_ips.filter(id=ip.id)
|
|
226 | 228 |
self.assertEqual(len(ips_after), 0) |
227 | 229 |
|
228 | 230 |
@patch("synnefo.logic.backend", Mock()) |
229 | 231 |
def test_delete_network_with_floating_ips(self): |
230 |
ip = IPAddressFactory(machine=None, network__flavor="IP_LESS_ROUTED")
|
|
232 |
ip = FloatingIPFactory(machine=None, network__flavor="IP_LESS_ROUTED")
|
|
231 | 233 |
net = ip.network |
232 | 234 |
# Can not remove network with floating IPs |
233 | 235 |
with mocked_quotaholder(): |
... | ... | |
246 | 248 |
POOLS_URL = join_urls(compute_path, "os-floating-ip-pools") |
247 | 249 |
|
248 | 250 |
|
249 |
class IPAddressPoolsAPITest(BaseAPITest):
|
|
251 |
class FloatingIPPoolsAPITest(BaseAPITest):
|
|
250 | 252 |
def test_no_pool(self): |
251 | 253 |
response = self.get(POOLS_URL) |
252 | 254 |
self.assertSuccess(response) |
253 | 255 |
self.assertEqual(json.loads(response.content)["floating_ip_pools"], []) |
254 | 256 |
|
255 | 257 |
def test_list_pools(self): |
256 |
net = IPAddressPoolFactory(subnet="192.168.0.0/30",
|
|
258 |
net = FloatingIPPoolFactory(subnet="192.168.0.0/30",
|
|
257 | 259 |
gateway="192.168.0.1") |
258 | 260 |
NetworkFactory(public=True, deleted=True) |
259 | 261 |
NetworkFactory(public=False, deleted=False) |
... | ... | |
264 | 266 |
[{"name": str(net.id), "size": 4, "free": 1}]) |
265 | 267 |
|
266 | 268 |
|
267 |
class IPAddressActionsTest(BaseAPITest):
|
|
269 |
class FloatingIPActionsTest(BaseAPITest):
|
|
268 | 270 |
def setUp(self): |
269 | 271 |
vm = VirtualMachineFactory() |
270 | 272 |
vm.operstate = "ACTIVE" |
... | ... | |
289 | 291 |
self.assertItemNotFound(response) |
290 | 292 |
# In use |
291 | 293 |
vm1 = VirtualMachineFactory() |
292 |
ip1 = IPAddressFactory(userid=self.vm.userid, machine=vm1)
|
|
294 |
ip1 = FloatingIPFactory(userid=self.vm.userid, machine=vm1)
|
|
293 | 295 |
BackendNetworkFactory(network=ip1.network, backend=vm1.backend, |
294 | 296 |
operstate='ACTIVE') |
295 | 297 |
request = {"addFloatingIp": {"address": ip1.ipv4}} |
296 | 298 |
response = self.post(url, self.vm.userid, json.dumps(request), "json") |
297 | 299 |
self.assertFault(response, 409, "conflict") |
298 | 300 |
# Success |
299 |
ip1 = IPAddressFactory(userid=self.vm.userid, machine=None)
|
|
301 |
ip1 = FloatingIPFactory(userid=self.vm.userid, machine=None)
|
|
300 | 302 |
BackendNetworkFactory(network=ip1.network, backend=self.vm.backend, |
301 | 303 |
operstate='ACTIVE') |
302 | 304 |
request = {"addFloatingIp": {"address": ip1.ipv4}} |
303 | 305 |
mock().ModifyInstance.return_value = 1 |
304 | 306 |
response = self.post(url, self.vm.userid, json.dumps(request), "json") |
305 | 307 |
self.assertEqual(response.status_code, 202) |
306 |
ip1_after = IPAddress.objects.get(id=ip1.id)
|
|
308 |
ip1_after = floating_ips.get(id=ip1.id)
|
|
307 | 309 |
self.assertEqual(ip1_after.machine, self.vm) |
308 | 310 |
self.assertTrue(ip1_after.in_use()) |
309 | 311 |
nic = self.vm.nics.get(ipv4=ip1_after.ipv4) |
... | ... | |
323 | 325 |
response = self.post(url, self.vm.userid, json.dumps(request), "json") |
324 | 326 |
self.assertItemNotFound(response) |
325 | 327 |
# Not In Use |
326 |
ip1 = IPAddressFactory(userid=self.vm.userid, machine=None)
|
|
328 |
ip1 = FloatingIPFactory(userid=self.vm.userid, machine=None)
|
|
327 | 329 |
request = {"removeFloatingIp": {"address": ip1.ipv4}} |
328 | 330 |
response = self.post(url, self.vm.userid, json.dumps(request), "json") |
329 | 331 |
self.assertItemNotFound(response) |
330 | 332 |
# Success |
331 |
ip1 = IPAddressFactory(userid=self.vm.userid, machine=self.vm)
|
|
333 |
ip1 = FloatingIPFactory(userid=self.vm.userid, machine=self.vm)
|
|
332 | 334 |
NetworkInterfaceFactory(machine=self.vm, ipv4=ip1.ipv4) |
333 | 335 |
request = {"removeFloatingIp": {"address": ip1.ipv4}} |
334 | 336 |
mock().ModifyInstance.return_value = 2 |
335 | 337 |
response = self.post(url, self.vm.userid, json.dumps(request), "json") |
336 | 338 |
self.assertEqual(response.status_code, 202) |
337 | 339 |
# Yet used. Wait for the callbacks |
338 |
ip1_after = IPAddress.objects.get(id=ip1.id)
|
|
340 |
ip1_after = floating_ips.get(id=ip1.id)
|
|
339 | 341 |
self.assertEqual(ip1_after.machine, self.vm) |
340 | 342 |
self.assertTrue(ip1_after.in_use()) |
b/snf-cyclades-app/synnefo/api/tests/servers.py | ||
---|---|---|
122 | 122 |
"""Test if a server details are returned.""" |
123 | 123 |
db_vm = self.vm2 |
124 | 124 |
user = self.vm2.userid |
125 |
net = mfactory.NetworkFactory() |
|
126 |
nic = mfactory.NetworkInterfaceFactory(machine=self.vm2, network=net, |
|
127 |
ipv6="::babe") |
|
125 |
ip4 = mfactory.IPv4AddressFactory(nic__machine=self.vm2) |
|
126 |
nic = ip4.nic |
|
127 |
net = ip4.network |
|
128 |
ip6 = mfactory.IPv6AddressFactory(nic=nic, network=net) |
|
129 |
nic.mac = "aa:00:11:22:33:44" |
|
130 |
nic.save() |
|
128 | 131 |
|
129 | 132 |
db_vm_meta = mfactory.VirtualMachineMetadataFactory(vm=db_vm) |
130 | 133 |
|
... | ... | |
141 | 144 |
self.assertEqual(api_nic['network_id'], str(net.id)) |
142 | 145 |
self.assertEqual(api_nic['mac_address'], nic.mac) |
143 | 146 |
self.assertEqual(api_nic['firewallProfile'], nic.firewall_profile) |
144 |
self.assertEqual(api_nic['ipv4'], nic.ipv4)
|
|
145 |
self.assertEqual(api_nic['ipv6'], nic.ipv6)
|
|
147 |
self.assertEqual(api_nic['ipv4'], ip4.address)
|
|
148 |
self.assertEqual(api_nic['ipv6'], ip6.address)
|
|
146 | 149 |
self.assertEqual(api_nic['OS-EXT-IPS:type'], "fixed") |
147 | 150 |
self.assertEqual(api_nic['id'], nic.id) |
148 | 151 |
api_address = server["addresses"] |
149 | 152 |
self.assertEqual(api_address[str(net.id)], [ |
150 |
{"version": 4, "addr": nic.ipv4, "OS-EXT-IPS:type": "fixed"},
|
|
151 |
{"version": 6, "addr": nic.ipv6, "OS-EXT-IPS:type": "fixed"}
|
|
153 |
{"version": 4, "addr": ip4.address, "OS-EXT-IPS:type": "fixed"},
|
|
154 |
{"version": 6, "addr": ip6.address, "OS-EXT-IPS:type": "fixed"}
|
|
152 | 155 |
]) |
153 | 156 |
|
154 | 157 |
metadata = server['metadata'] |
... | ... | |
184 | 187 |
self.assertEqual(server["SNF:fqdn"], "") |
185 | 188 |
|
186 | 189 |
# IPv6 NIC |
187 |
nic = mfactory.NetworkInterfaceFactory(machine=vm, ipv4=None, |
|
188 |
ipv6="babe::", state="ACTIVE", |
|
189 |
network__public=True) |
|
190 |
ipv6_address = mfactory.IPv6AddressFactory(nic__machine=vm, |
|
191 |
network__public=True) |
|
190 | 192 |
with override_settings(settings, |
191 | 193 |
CYCLADES_SERVERS_FQDN=None): |
192 | 194 |
response = self.myget("servers/%d" % vm.id, vm.userid) |
193 | 195 |
server = json.loads(response.content)['server'] |
194 |
self.assertEqual(server["SNF:fqdn"], nic.ipv6)
|
|
196 |
self.assertEqual(server["SNF:fqdn"], ipv6_address.address)
|
|
195 | 197 |
|
196 | 198 |
# IPv4 NIC |
197 |
nic = mfactory.NetworkInterfaceFactory(machine=vm, |
|
198 |
network__public=True, |
|
199 |
state="ACTIVE") |
|
199 |
ipv4_address = mfactory.IPv4AddressFactory(nic__machine=vm, |
|
200 |
network__public=True) |
|
200 | 201 |
with override_settings(settings, |
201 | 202 |
CYCLADES_SERVERS_FQDN=None): |
202 | 203 |
response = self.myget("servers/%d" % vm.id, vm.userid) |
203 | 204 |
server = json.loads(response.content)['server'] |
204 |
self.assertEqual(server["SNF:fqdn"], nic.ipv4)
|
|
205 |
self.assertEqual(server["SNF:fqdn"], ipv4_address.address)
|
|
205 | 206 |
|
206 | 207 |
def test_server_port_forwarding(self): |
207 | 208 |
vm = mfactory.VirtualMachineFactory() |
... | ... | |
229 | 230 |
server = json.loads(response.content)['server'] |
230 | 231 |
self.assertEqual(server["SNF:port_forwarding"], {}) |
231 | 232 |
|
232 |
mfactory.NetworkInterfaceFactory(machine=vm, ipv4="192.168.2.2", |
|
233 |
network__public=True) |
|
233 |
mfactory.IPv4AddressFactory(nic__machine=vm, |
|
234 |
network__public=True, |
|
235 |
address="192.168.2.2") |
|
234 | 236 |
with override_settings(settings, |
235 | 237 |
CYCLADES_PORT_FORWARDING=ports): |
236 | 238 |
response = self.myget("servers/%d" % vm.id, vm.userid) |
... | ... | |
335 | 337 |
def setUp(self): |
336 | 338 |
self.flavor = mfactory.FlavorFactory() |
337 | 339 |
# Create public network and backend |
338 |
self.network = mfactory.NetworkFactory(public=True) |
|
340 |
subnet = mfactory.IPv4SubnetFactory(network__public=True) |
|
341 |
self.network = subnet.network |
|
339 | 342 |
self.backend = mfactory.BackendFactory() |
340 | 343 |
mfactory.BackendNetworkFactory(network=self.network, |
341 | 344 |
backend=self.backend, |
... | ... | |
386 | 389 |
|
387 | 390 |
def test_create_network_settings(self, mrapi): |
388 | 391 |
mrapi().CreateInstance.return_value = 12 |
389 |
bnet1 = mfactory.BackendNetworkFactory(operstate="ACTIVE", |
|
390 |
backend=self.backend) |
|
391 |
bnet2 = mfactory.BackendNetworkFactory(operstate="ACTIVE", |
|
392 |
backend=self.backend) |
|
393 |
bnet3 = mfactory.BackendNetworkFactory(network__userid="test_user", |
|
394 |
operstate="ACTIVE", |
|
395 |
backend=self.backend) |
|
396 |
bnet4 = mfactory.BackendNetworkFactory(network__userid="test_user", |
|
397 |
operstate="ACTIVE", |
|
398 |
backend=self.backend) |
|
392 |
# Create public network and backend |
|
393 |
subnet1 = mfactory.IPv4SubnetFactory() |
|
394 |
bnet1 = mfactory.BackendNetworkFactory(network=subnet1.network, |
|
395 |
backend=self.backend, |
|
396 |
operstate="ACTIVE") |
|
397 |
subnet2 = mfactory.IPv4SubnetFactory() |
|
398 |
bnet2 = mfactory.BackendNetworkFactory(network=subnet2.network, |
|
399 |
backend=self.backend, |
|
400 |
operstate="ACTIVE") |
|
401 |
subnet3 = mfactory.IPv4SubnetFactory(network__userid="test_user") |
|
402 |
bnet3 = mfactory.BackendNetworkFactory(network=subnet3.network, |
|
403 |
backend=self.backend, |
|
404 |
operstate="ACTIVE") |
|
405 |
subnet4 = mfactory.IPv4SubnetFactory(network__userid="test_user") |
|
406 |
bnet4 = mfactory.BackendNetworkFactory(network=subnet4.network, |
|
407 |
backend=self.backend, |
|
408 |
operstate="ACTIVE") |
|
399 | 409 |
# User requested private networks |
400 | 410 |
request = deepcopy(self.request) |
401 | 411 |
request["server"]["networks"] = [bnet3.network.id, bnet4.network.id] |
... | ... | |
464 | 474 |
# Test floating IPs |
465 | 475 |
request = deepcopy(self.request) |
466 | 476 |
request["server"]["networks"] = [bnet4.network.id] |
467 |
network = mfactory.NetworkFactory(subnet="10.0.0.0/24") |
|
468 |
mfactory.BackendNetworkFactory(network=network, |
|
469 |
backend=self.backend, |
|
470 |
operstate="ACTIVE") |
|
471 |
fp1 = mfactory.IPAddressFactory(ipv4="10.0.0.2", |
|
477 |
fp1 = mfactory.FloatingIPFactory(address="10.0.0.2", |
|
472 | 478 |
userid="test_user", |
473 |
network=network, machine=None)
|
|
474 |
fp2 = mfactory.IPAddressFactory(ipv4="10.0.0.3", network=network,
|
|
479 |
nic=None)
|
|
480 |
fp2 = mfactory.FloatingIPFactory(address="10.0.0.3",
|
|
475 | 481 |
userid="test_user", |
476 |
machine=None)
|
|
477 |
request["server"]["floating_ips"] = [fp1.ipv4, fp2.ipv4]
|
|
482 |
nic=None)
|
|
483 |
request["server"]["floating_ips"] = [fp1.address, fp2.address]
|
|
478 | 484 |
with override_settings(settings, |
479 | 485 |
DEFAULT_INSTANCE_NETWORKS=[bnet3.network.id]): |
480 | 486 |
with mocked_quotaholder(): |
... | ... | |
483 | 489 |
self.assertEqual(response.status_code, 202) |
484 | 490 |
api_server = json.loads(response.content)['server'] |
485 | 491 |
vm = VirtualMachine.objects.get(id=api_server["id"]) |
486 |
fp1 = IPAddress.objects.get(id=fp1.id) |
|
487 |
fp2 = IPAddress.objects.get(id=fp2.id) |
|
488 |
self.assertEqual(fp1.machine, vm) |
|
489 |
self.assertEqual(fp2.machine, vm) |
|
492 |
fp1 = IPAddress.objects.get(floating_ip=True, id=fp1.id)
|
|
493 |
fp2 = IPAddress.objects.get(floating_ip=True, id=fp2.id)
|
|
494 |
self.assertEqual(fp1.nic.machine, vm)
|
|
495 |
self.assertEqual(fp2.nic.machine, vm)
|
|
490 | 496 |
name, args, kwargs = mrapi().CreateInstance.mock_calls[2] |
491 | 497 |
self.assertEqual(len(kwargs["nics"]), 4) |
492 | 498 |
self.assertEqual(kwargs["nics"][0]["network"], |
493 | 499 |
bnet3.network.backend_id) |
494 |
self.assertEqual(kwargs["nics"][1]["network"], network.backend_id) |
|
495 |
self.assertEqual(kwargs["nics"][1]["ip"], fp1.ipv4)
|
|
496 |
self.assertEqual(kwargs["nics"][2]["network"], network.backend_id) |
|
497 |
self.assertEqual(kwargs["nics"][2]["ip"], fp2.ipv4)
|
|
500 |
self.assertEqual(kwargs["nics"][1]["network"], fp1.network.backend_id)
|
|
501 |
self.assertEqual(kwargs["nics"][1]["ip"], fp1.address)
|
|
502 |
self.assertEqual(kwargs["nics"][2]["network"], fp2.network.backend_id)
|
|
503 |
self.assertEqual(kwargs["nics"][2]["ip"], fp2.address)
|
|
498 | 504 |
self.assertEqual(kwargs["nics"][3]["network"], |
499 | 505 |
bnet4.network.backend_id) |
500 | 506 |
|
... | ... | |
510 | 516 |
"""Test if the create server call returns the expected response |
511 | 517 |
if a valid request has been speficied.""" |
512 | 518 |
mrapi().CreateInstance.side_effect = GanetiApiError("..ganeti is down") |
513 |
# Create public network and backend |
|
514 |
network = mfactory.NetworkFactory(public=True) |
|
515 |
backend = mfactory.BackendFactory() |
|
516 |
mfactory.BackendNetworkFactory(network=network, backend=backend) |
|
517 | 519 |
|
518 | 520 |
request = self.request |
519 | 521 |
with mocked_quotaholder(): |
b/snf-cyclades-app/synnefo/api/util.py | ||
---|---|---|
234 | 234 |
raise faults.ItemNotFound("Floating IP does not exist.") |
235 | 235 |
|
236 | 236 |
|
237 |
def allocate_public_address(backend): |
|
237 |
def allocate_public_address(backend, userid):
|
|
238 | 238 |
"""Get a public IP for any available network of a backend.""" |
239 | 239 |
# Guarantee exclusive access to backend, because accessing the IP pools of |
240 | 240 |
# the backend networks may result in a deadlock with backend allocator |
241 | 241 |
# which also checks that backend networks have a free IP. |
242 | 242 |
backend = Backend.objects.select_for_update().get(id=backend.id) |
243 | 243 |
public_networks = backend_public_networks(backend) |
244 |
return get_free_ip(public_networks) |
|
244 |
return get_free_ip(public_networks, userid)
|
|
245 | 245 |
|
246 | 246 |
|
247 | 247 |
def backend_public_networks(backend): |
... | ... | |
255 | 255 |
network__public=True, |
256 | 256 |
network__deleted=False, |
257 | 257 |
network__floating_ip_pool=False, |
258 |
network__subnet__isnull=False, |
|
259 | 258 |
network__drained=False) |
260 | 259 |
return [b.network for b in bnets] |
261 | 260 |
|
262 | 261 |
|
263 |
def get_free_ip(networks): |
|
262 |
def get_free_ip(networks, userid):
|
|
264 | 263 |
for network in networks: |
265 | 264 |
try: |
266 |
address = get_network_free_address(network) |
|
267 |
return network, address |
|
265 |
return network.allocate_address(userid=userid) |
|
268 | 266 |
except faults.OverLimit: |
269 | 267 |
pass |
270 | 268 |
msg = "Can not allocate public IP. Public networks are full." |
... | ... | |
272 | 270 |
raise faults.OverLimit(msg) |
273 | 271 |
|
274 | 272 |
|
275 |
def get_network_free_address(network): |
|
273 |
def get_network_free_address(network, userid):
|
|
276 | 274 |
"""Reserve an IP address from the IP Pool of the network.""" |
277 | 275 |
|
278 |
pool = network.get_pool() |
|
279 | 276 |
try: |
280 |
address = pool.get()
|
|
277 |
return network.allocate_address(userid=userid)
|
|
281 | 278 |
except EmptyPool: |
282 | 279 |
raise faults.OverLimit("Network %s is full." % network.backend_id) |
283 |
pool.save() |
|
284 |
return address |
|
285 | 280 |
|
286 | 281 |
|
287 | 282 |
def get_vm_nic(vm, nic_id): |
b/snf-cyclades-app/synnefo/db/models.py | ||
---|---|---|
531 | 531 |
if not backend_exists: |
532 | 532 |
BackendNetwork.objects.create(backend=backend, network=self) |
533 | 533 |
|
534 |
def get_pool(self, with_lock=True):
|
|
534 |
def get_pool(self, locked=True):
|
|
535 | 535 |
try: |
536 | 536 |
subnet = self.subnets.get(ipversion=4, deleted=False) |
537 | 537 |
except Subnet.DoesNotExist: |
538 | 538 |
raise pools.EmptyPool |
539 |
return subnet.get_pool(locked=locked) |
|
540 |
|
|
541 |
def allocate_address(self, userid): |
|
539 | 542 |
try: |
540 |
pool = subnet.ip_pools.all()[0] |
|
541 |
except IndexError: |
|
542 |
pool = IPPoolTable.objects.create(available_map='', |
|
543 |
reserved_map='', |
|
544 |
size=0, |
|
545 |
subnet=subnet) |
|
546 |
objects = IPPoolTable.objects |
|
547 |
if with_lock: |
|
548 |
objects = objects.select_for_update() |
|
549 |
return objects.get(id=pool.id) |
|
543 |
subnet = self.subnets.get(ipversion=4, deleted=False) |
|
544 |
except Subnet.DoesNotExist: |
|
545 |
raise pools.EmptyPool |
|
546 |
return subnet.allocate_address(userid) |
|
550 | 547 |
|
551 | 548 |
def reserve_address(self, address): |
552 | 549 |
pool = self.get_pool() |
... | ... | |
601 | 598 |
def __unicode__(self): |
602 | 599 |
return "<Subnet %s, Network: %s>" % (self.id, self.network_id) |
603 | 600 |
|
601 |
def get_pool(self, locked=True): |
|
602 |
if self.ipversion == 6: |
|
603 |
raise Exception("IPv6 Subnets have no IP Pool.") |
|
604 |
ip_pools = self.ip_pools |
|
605 |
if locked: |
|
606 |
ip_pools = ip_pools.select_for_update() |
|
607 |
return ip_pools.all()[0].pool |
|
608 |
|
|
609 |
def allocate_address(self, userid): |
|
610 |
pool = self.get_pool(locked=True) |
|
611 |
address = pool.get() |
|
612 |
pool.save() |
|
613 |
return IPAddress.objects.create(network=self.network, subnet=self, |
|
614 |
address=address, userid=userid) |
|
615 |
|
|
604 | 616 |
|
605 | 617 |
class BackendNetwork(models.Model): |
606 | 618 |
OPER_STATES = ( |
... | ... | |
755 | 767 |
"""Return the backend id by prepending backend-prefix.""" |
756 | 768 |
return "%snic-%s" % (settings.BACKEND_PREFIX_ID, str(self.id)) |
757 | 769 |
|
770 |
@property |
|
771 |
def ipv4_address(self): |
|
772 |
try: |
|
773 |
return self.ips.get(subnet__ipversion=4).address |
|
774 |
except IPAddress.DoesNotExist: |
|
775 |
return None |
|
776 |
|
|
758 | 777 |
|
759 | 778 |
class SecurityGroup(models.Model): |
760 | 779 |
SECURITY_GROUP_NAME_LENGTH = 128 |
b/snf-cyclades-app/synnefo/db/models_factory.py | ||
---|---|---|
186 | 186 |
factory.Sequence(round_seq_first(FACTORY_FOR.FIREWALL_PROFILES)) |
187 | 187 |
|
188 | 188 |
|
189 |
class IPPoolTableFactory(factory.DjangoModelFactory): |
|
190 |
FACTORY_FOR = models.IPPoolTable |
|
191 |
size = 0 |
|
192 |
|
|
193 |
|
|
189 | 194 |
class IPv4SubnetFactory(factory.DjangoModelFactory): |
190 | 195 |
FACTORY_FOR = models.Subnet |
191 | 196 |
|
192 |
network = factory.SubFactory(NetworkFactory) |
|
197 |
network = factory.SubFactory(NetworkFactory, state="ACTIVE")
|
|
193 | 198 |
name = factory.LazyAttribute(lambda self: random_string(30)) |
194 | 199 |
ipversion = 4 |
195 | 200 |
cidr = factory.Sequence(lambda n: '192.168.{0}.0/24'.format(n)) |
... | ... | |
197 | 202 |
gateway = factory.Sequence(lambda n: '192.168.{0}.1'.format(n)) |
198 | 203 |
dns_nameservers = [] |
199 | 204 |
host_routes = [] |
205 |
pool = factory.RelatedFactory(IPPoolTableFactory, 'subnet') |
|
200 | 206 |
|
201 | 207 |
|
202 | 208 |
class IPv6SubnetFactory(IPv4SubnetFactory): |
... | ... | |
213 | 219 |
address =\ |
214 | 220 |
factory.LazyAttributeSequence(lambda self, n: self.subnet.cidr[:-4] + |
215 | 221 |
'{0}'.format(int(n) + 2)) |
222 |
nic = factory.SubFactory(NetworkInterfaceFactory, |
|
223 |
network=factory.SelfAttribute('..network')) |
|
224 |
|
|
225 |
|
|
226 |
class IPv6AddressFactory(IPv4AddressFactory): |
|
227 |
FACTORY_FOR = models.IPAddress |
|
228 |
|
|
229 |
subnet = factory.SubFactory(IPv6SubnetFactory) |
|
230 |
network = factory.SubFactory(NetworkFactory) |
|
231 |
address = "babe::" |
|
232 |
nic = factory.SubFactory(NetworkInterfaceFactory, |
|
233 |
network=factory.SelfAttribute('..network')) |
|
216 | 234 |
|
217 | 235 |
|
218 | 236 |
class FloatingIPFactory(IPv4AddressFactory): |
b/snf-cyclades-app/synnefo/db/query.py | ||
---|---|---|
1 |
from synnefo.db.models import IPAddress |
|
2 |
|
|
3 |
|
|
4 |
def get_server_ips(server, for_update=False): |
|
5 |
ips = IPAddress.objects.select_related("subnet") |
|
6 |
ips = ips.filter(nic__machine=server, deleted=False) |
|
7 |
if for_update: |
|
8 |
ips = ips.select_for_update() |
|
9 |
return ips |
|
10 |
|
|
11 |
|
|
12 |
def get_server_active_ips(server, for_update=False): |
|
13 |
ips = get_server_ips(server, for_update=for_update) |
|
14 |
return ips.filter(nic__state="ACTIVE") |
|
15 |
|
|
16 |
|
|
17 |
def get_server_public_ip(server, version=4): |
|
18 |
ips = get_server_active_ips(server) |
|
19 |
try: |
|
20 |
public_ips = ips.filter(network__public=True, |
|
21 |
subnet__ipversion=version) |
|
22 |
return public_ips[0].address |
|
23 |
except IndexError: |
|
24 |
return None |
|
25 |
|
|
26 |
|
|
27 |
def get_floating_ips(for_update=False): |
|
28 |
ips = IPAddress.objects.select_related("subnet") |
|
29 |
ips = ips.filter(floating_ip=True, deleted=False) |
|
30 |
if for_update: |
|
31 |
ips = ips.select_for_update() |
|
32 |
return ips |
|
33 |
|
|
34 |
|
|
35 |
def get_server_floating_ips(server, for_update=False): |
|
36 |
floating_ips = get_floating_ips(for_update=for_update) |
|
37 |
return floating_ips.filter(nic__machine=server) |
|
38 |
|
|
39 |
|
|
40 |
def get_server_floating_ip(server, address, for_update=False): |
|
41 |
server_fips = get_server_floating_ips(server, for_update=for_update) |
|
42 |
return server_fips.get(address=address) |
|
43 |
|
|
44 |
|
|
45 |
def get_user_floating_ip(userid, address, for_update=False): |
|
46 |
fips = get_floating_ips(for_update=for_update) |
|
47 |
return fips.get(userid=userid, address=address) |
b/snf-cyclades-app/synnefo/logic/backend.py | ||
---|---|---|
544 | 544 |
|
545 | 545 |
kw['nics'] = [{"name": nic.backend_uuid, |
546 | 546 |
"network": nic.network.backend_id, |
547 |
"ip": nic.ipv4} |
|
547 |
"ip": nic.ipv4_address}
|
|
548 | 548 |
for nic in nics] |
549 | 549 |
backend = vm.backend |
550 | 550 |
depend_jobs = [] |
551 | 551 |
for nic in nics: |
552 |
network = Network.objects.select_for_update().get(id=nic.network.id)
|
|
552 |
network = Network.objects.select_for_update().get(id=nic.network_id)
|
|
553 | 553 |
bnet, created = BackendNetwork.objects.get_or_create(backend=backend, |
554 | 554 |
network=network) |
555 | 555 |
if bnet.operstate != "ACTIVE": |
... | ... | |
714 | 714 |
"""Create a network.""" |
715 | 715 |
|
716 | 716 |
tags = network.backend_tag |
717 |
if network.dhcp: |
|
718 |
tags.append('nfdhcpd') |
|
717 |
subnet = None |
|
718 |
subnet6 = None |
|
719 |
gateway = None |
|
720 |
gateway6 = None |
|
721 |
for subnet in network.subnets.all(): |
|
722 |
if subnet.ipversion == 4: |
|
723 |
if subnet.dhcp: |
|
724 |
tags.append('nfdhcpd') |
|
725 |
subnet = subnet.cidr |
|
726 |
gateway = subnet.gateway |
|
727 |
elif subnet.ipversion == 6: |
|
728 |
subnet6 = subnet.cidr |
|
729 |
gateway6 = subnet.gateway |
|
719 | 730 |
|
720 | 731 |
if network.public: |
721 | 732 |
conflicts_check = True |
... | ... | |
728 | 739 |
# not support IPv6 only networks. To bypass this limitation, we create the |
729 | 740 |
# network with a dummy network subnet, and make Cyclades connect instances |
730 | 741 |
# to such networks, with address=None. |
731 |
subnet = network.subnet |
|
732 | 742 |
if subnet is None: |
733 | 743 |
subnet = "10.0.0.0/24" |
734 | 744 |
|
... | ... | |
742 | 752 |
with pooled_rapi_client(backend) as client: |
743 | 753 |
return client.CreateNetwork(network_name=network.backend_id, |
744 | 754 |
network=subnet, |
745 |
network6=network.subnet6,
|
|
746 |
gateway=network.gateway,
|
|
747 |
gateway6=network.gateway6,
|
|
755 |
network6=subnet6, |
|
756 |
gateway=gateway, |
|
757 |
gateway6=gateway6, |
|
748 | 758 |
mac_prefix=mac_prefix, |
749 | 759 |
conflicts_check=conflicts_check, |
750 | 760 |
tags=tags) |
b/snf-cyclades-app/synnefo/logic/management/commands/backend-list.py | ||
---|---|---|
53 | 53 |
free_ips = 0 |
54 | 54 |
total_ips = 0 |
55 | 55 |
for network in util.backend_public_networks(backend): |
56 |
pool = network.get_pool(with_lock=False)
|
|
56 |
pool = network.get_pool(locked=False)
|
|
57 | 57 |
free_ips += pool.count_available() |
58 | 58 |
total_ips += pool.pool_size |
59 | 59 |
return "%s/%s" % (free_ips, total_ips) |
b/snf-cyclades-app/synnefo/logic/servers.py | ||
---|---|---|
13 | 13 |
from synnefo.logic import backend |
14 | 14 |
from synnefo.logic.backend_allocator import BackendAllocator |
15 | 15 |
from synnefo.db.models import (NetworkInterface, VirtualMachine, Network, |
16 |
VirtualMachineMetadata, IPAddress) |
|
16 |
VirtualMachineMetadata, IPAddress, Subnet) |
|
17 |
from synnefo.db import query as db_query |
|
17 | 18 |
|
18 | 19 |
from vncauthproxy.client import request_forwarding as request_vnc_forwarding |
19 | 20 |
|
... | ... | |
242 | 243 |
""" |
243 | 244 |
attachments = [] |
244 | 245 |
for network_id in settings.DEFAULT_INSTANCE_NETWORKS: |
245 |
network, address = None, None |
|
246 |
network, ipaddress = None, None
|
|
246 | 247 |
if network_id == "SNF:ANY_PUBLIC": |
247 |
network, address = util.allocate_public_address(backend=vm.backend) |
|
248 |
ipaddress = util.allocate_public_address(backend=vm.backend, |
|
249 |
userid=userid) |
|
250 |
network = ipaddress.network |
|
248 | 251 |
else: |
249 | 252 |
try: |
250 | 253 |
network = Network.objects.get(id=network_id, deleted=False) |
... | ... | |
254 | 257 |
" network '%s'" % network_id |
255 | 258 |
log.error(msg) |
256 | 259 |
raise Exception(msg) |
257 |
if network.subnet is not None and network.dhcp: |
|
258 |
address = util.get_network_free_address(network) |
|
259 |
attachments.append((network, address)) |
|
260 |
try: |
|
261 |
subnet = network.subnets.get(ipversion=4, dhcp=True) |
|
262 |
ipaddress = util.get_network_free_address(subnet, userid) |
|
263 |
except Subnet.DoesNotExist: |
|
264 |
ipaddress = None |
|
265 |
attachments.append((network, ipaddress)) |
|
260 | 266 |
for address in floating_ips: |
261 |
floating_ip = add_floating_ip_to_vm(vm=vm, address=address) |
|
262 |
network = floating_ip.network |
|
263 |
attachments.append((network, address)) |
|
267 |
floating_ip = get_floating_ip(userid=vm.userid, address=address) |
|
268 |
attachments.append((floating_ip.network, floating_ip)) |
|
264 | 269 |
for network_id in private_networks: |
265 |
network, address = None, None |
|
266 | 270 |
network = util.get_network(network_id, userid, non_deleted=True) |
267 | 271 |
if network.public: |
268 | 272 |
raise faults.Forbidden("Can not connect to public network") |
269 |
if network.dhcp: |
|
270 |
address = util.get_network_free_address(network) |
|
271 |
attachments.append((network, address)) |
|
273 |
attachments.append((network, ipaddress)) |
|
272 | 274 |
|
273 | 275 |
nics = [] |
274 |
for index, (network, address) in enumerate(attachments): |
|
276 |
for index, (network, ipaddress) in enumerate(attachments):
|
|
275 | 277 |
# Create VM's public NIC. Do not wait notification form ganeti |
276 | 278 |
# hooks to create this NIC, because if the hooks never run (e.g. |
277 | 279 |
# building error) the VM's public IP address will never be |
278 | 280 |
# released! |
279 |
nic = NetworkInterface.objects.create(machine=vm, network=network,
|
|
280 |
index=index, ipv4=address,
|
|
281 |
nic = NetworkInterface.objects.create(userid=userid, machine=vm,
|
|
282 |
network=network, index=index,
|
|
281 | 283 |
state="BUILDING") |
284 |
if ipaddress is not None: |
|
285 |
ipaddress.nic = nic |
|
286 |
ipaddress.save() |
|
282 | 287 |
nics.append(nic) |
283 | 288 |
return nics |
284 | 289 |
|
... | ... | |
427 | 432 |
|
428 | 433 |
@server_command("CONNECT") |
429 | 434 |
def add_floating_ip(vm, address): |
430 |
floating_ip = add_floating_ip_to_vm(vm, address)
|
|
435 |
floating_ip = get_floating_ip(userid=vm.userid, address=address)
|
|
431 | 436 |
nic = NetworkInterface.objects.create(machine=vm, |
432 | 437 |
network=floating_ip.network, |
433 | 438 |
ipv4=floating_ip.ipv4, |
... | ... | |
438 | 443 |
return backend.connect_to_network(vm, nic) |
439 | 444 |
|
440 | 445 |
|
441 |
def add_floating_ip_to_vm(vm, address):
|
|
442 |
"""Get a floating IP by it's address and add it to VirtualMachine.
|
|
446 |
def get_floating_ip(userid, address):
|
|
447 |
"""Get a floating IP by it's address. |
|
443 | 448 |
|
444 |
Helper function for looking up a IPAddress by it's address and associating |
|
445 |
it with a VirtualMachine object (without adding the NIC in the Ganeti |
|
446 |
backend!). This function also checks if the floating IP is currently used |
|
447 |
by any instance and if it is available in the Backend that hosts the VM. |
|
449 |
Helper function for looking up a IPAddress by it's address. This function |
|
450 |
also checks if the floating IP is currently used by any instance. |
|
448 | 451 |
|
449 | 452 |
""" |
450 |
user_id = vm.userid |
|
451 | 453 |
try: |
452 | 454 |
# Get lock in VM, to guarantee that floating IP will only by assigned |
453 | 455 |
# once |
454 |
floating_ip = IPAddress.objects.select_for_update()\
|
|
455 |
.get(userid=user_id, ipv4=address,
|
|
456 |
deleted=False)
|
|
456 |
floating_ip = db_query.get_user_floating_ip(userid=userid,
|
|
457 |
address=address,
|
|
458 |
for_update=True)
|
|
457 | 459 |
except IPAddress.DoesNotExist: |
458 |
raise faults.ItemNotFound("Floating IP '%s' does not exist" % address) |
|
460 |
raise faults.ItemNotFound("Floating IP with address '%s' does not" |
|
461 |
" exist" % address) |
|
459 | 462 |
|
460 |
if floating_ip.in_use():
|
|
463 |
if floating_ip.nic is not None:
|
|
461 | 464 |
raise faults.Conflict("Floating IP '%s' already in use" % |
462 | 465 |
floating_ip.id) |
463 | 466 |
|
464 |
bnet = floating_ip.network.backend_networks.filter(backend=vm.backend_id) |
|
465 |
if not bnet.exists(): |
|
466 |
msg = "Network '%s' is a floating IP pool, but it not connected"\ |
|
467 |
" to backend '%s'" % (floating_ip.network, vm.backend) |
|
468 |
raise faults.ServiceUnavailable(msg) |
|
469 |
|
|
470 |
floating_ip.machine = vm |
|
471 |
floating_ip.save() |
|
472 | 467 |
return floating_ip |
473 | 468 |
|
474 | 469 |
|
475 | 470 |
@server_command("DISCONNECT") |
476 | 471 |
def remove_floating_ip(vm, address): |
477 |
user_id = vm.userid |
|
478 | 472 |
try: |
479 |
floating_ip = IPAddress.objects.select_for_update()\
|
|
480 |
.get(userid=user_id, ipv4=address,
|
|
481 |
deleted=False, machine=vm)
|
|
473 |
floating_ip = db_query.get_server_floating_ip(server=vm,
|
|
474 |
address=address,
|
|
475 |
for_update=True)
|
|
482 | 476 |
except IPAddress.DoesNotExist: |
483 |
raise faults.ItemNotFound("Floating IP '%s' does not exist" % address) |
|
484 |
|
|
485 |
try: |
|
486 |
nic = NetworkInterface.objects.get(machine=vm, ipv4=address) |
|
487 |
except NetworkInterface.DoesNotExist: |
|
488 |
raise faults.ItemNotFound("Floating IP '%s' is not attached to" |
|
489 |
"VM '%s'" % (floating_ip, vm)) |
|
477 |
raise faults.BadRequest("Server '%s' has no floating ip with" |
|
478 |
" address '%s'" % (vm, address)) |
|
490 | 479 |
|
480 |
nic = floating_ip.nic |
|
491 | 481 |
log.info("Removing NIC %s from VM %s. Floating IP '%s'", str(nic.index), |
492 | 482 |
vm, floating_ip) |
493 | 483 |
|
b/snf-cyclades-app/synnefo/logic/tests/servers.py | ||
---|---|---|
122 | 122 |
mfactory.BackendNetworkFactory(network=net, backend=vm.backend) |
123 | 123 |
mrapi().ModifyInstance.return_value = 42 |
124 | 124 |
servers.connect(vm, net) |
125 |
pool = net.get_pool(with_lock=False)
|
|
125 |
pool = net.get_pool(locked=False)
|
|
126 | 126 |
self.assertFalse(pool.is_available("192.168.2.2")) |
127 | 127 |
args, kwargs = mrapi().ModifyInstance.call_args |
128 | 128 |
nics = kwargs["nics"][0] |
... | ... | |
140 | 140 |
dhcp=False) |
141 | 141 |
mfactory.BackendNetworkFactory(network=net, backend=vm.backend) |
142 | 142 |
servers.connect(vm, net) |
143 |
pool = net.get_pool(with_lock=False)
|
|
143 |
pool = net.get_pool(locked=False)
|
|
144 | 144 |
self.assertTrue(pool.is_available("192.168.2.2")) |
145 | 145 |
args, kwargs = mrapi().ModifyInstance.call_args |
146 | 146 |
nics = kwargs["nics"][0] |
b/snf-cyclades-app/synnefo/quotas/__init__.py | ||
---|---|---|
298 | 298 |
elif isinstance(resource, Network): |
299 | 299 |
return {"cyclades.network.private": 1} |
300 | 300 |
elif isinstance(resource, IPAddress): |
301 |
return {"cyclades.floating_ip": 1} |
|
301 |
if resource.floating_ip: |
|
302 |
return {"cyclades.floating_ip": 1} |
|
302 | 303 |
else: |
303 | 304 |
raise ValueError("Unknown Resource '%s'" % resource) |
304 | 305 |
|
Also available in: Unified diff