Revision b3a43976 snf-cyclades-app/synnefo/api/servers.py
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 |
|
47 | 46 |
from synnefo.db.models import (VirtualMachine, VirtualMachineMetadata) |
48 | 47 |
from synnefo.logic import servers, utils as logic_utils |
49 | 48 |
|
... | ... | |
105 | 104 |
return api.api_method_not_allowed(request) |
106 | 105 |
|
107 | 106 |
|
108 |
def nic_to_dict(nic): |
|
107 |
def nic_to_attachments(nic): |
|
108 |
"""Convert a NIC object to 'attachments attribute. |
|
109 |
|
|
110 |
Convert a NIC object to match the format of 'attachments' attribute of the |
|
111 |
response to the /servers API call. |
|
112 |
|
|
113 |
NOTE: The 'ips' of the NIC object have been prefetched in order to avoid DB |
|
114 |
queries. No subsequent queries for 'ips' (like filtering) should be |
|
115 |
performed because this will return in a new DB query. |
|
116 |
|
|
117 |
""" |
|
109 | 118 |
d = {'id': nic.id, |
110 |
'network_id': str(nic.network.id),
|
|
119 |
'network_id': str(nic.network_id),
|
|
111 | 120 |
'mac_address': nic.mac, |
112 | 121 |
'ipv4': '', |
113 | 122 |
'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 |
|
122 | 123 |
|
123 | 124 |
if nic.firewall_profile: |
124 | 125 |
d['firewallProfile'] = nic.firewall_profile |
126 |
|
|
127 |
for ip in nic.ips.all(): |
|
128 |
if not ip.deleted: |
|
129 |
ip_type = "floating" if ip.floating_ip else "fixed" |
|
130 |
if ip.ipversion == 4: |
|
131 |
d["ipv4"] = ip.address |
|
132 |
d["OS-EXT-IPS:type"] = ip_type |
|
133 |
else: |
|
134 |
d["ipv6"] = ip.address |
|
135 |
d["OS-EXT-IPS:type"] = ip_type |
|
125 | 136 |
return d |
126 | 137 |
|
127 | 138 |
|
128 | 139 |
def attachments_to_addresses(attachments): |
140 |
"""Convert 'attachments' attribute to 'addresses'. |
|
141 |
|
|
142 |
Convert a a list of 'attachments' attribute to a list of 'addresses' |
|
143 |
attribute, as expected in the response to /servers API call. |
|
144 |
|
|
145 |
""" |
|
129 | 146 |
addresses = {} |
130 | 147 |
for nic in attachments: |
131 |
net_nics = []
|
|
148 |
net_addrs = []
|
|
132 | 149 |
if nic["ipv4"]: |
133 |
net_nics.append({"version": 4,
|
|
134 |
"addr": nic["ipv4"], |
|
135 |
"OS-EXT-IPS:type": nic["OS-EXT-IPS:type"]}) |
|
150 |
net_addrs.append({"version": 4,
|
|
151 |
"addr": nic["ipv4"],
|
|
152 |
"OS-EXT-IPS:type": nic["OS-EXT-IPS:type"]})
|
|
136 | 153 |
if nic["ipv6"]: |
137 |
net_nics.append({"version": 6,
|
|
138 |
"addr": nic["ipv6"], |
|
139 |
"OS-EXT-IPS:type": nic["OS-EXT-IPS:type"]}) |
|
140 |
addresses[nic["network_id"]] = net_nics
|
|
154 |
net_addrs.append({"version": 6,
|
|
155 |
"addr": nic["ipv6"],
|
|
156 |
"OS-EXT-IPS:type": nic["OS-EXT-IPS:type"]})
|
|
157 |
addresses[nic["network_id"]] = net_addrs
|
|
141 | 158 |
return addresses |
142 | 159 |
|
143 | 160 |
|
... | ... | |
162 | 179 |
metadata = dict((m.meta_key, m.meta_value) for m in vm.metadata.all()) |
163 | 180 |
d['metadata'] = metadata |
164 | 181 |
|
165 |
vm_nics = vm.nics.filter(state="ACTIVE").order_by("id") |
|
166 |
attachments = map(nic_to_dict, vm_nics) |
|
182 |
nics = vm.nics.all() |
|
183 |
active_nics = filter(lambda nic: nic.state == "ACTIVE", nics) |
|
184 |
active_nics.sort(key=lambda nic: nic.id) |
|
185 |
attachments = map(nic_to_attachments, active_nics) |
|
167 | 186 |
d['attachments'] = attachments |
168 | 187 |
d['addresses'] = attachments_to_addresses(attachments) |
169 | 188 |
|
... | ... | |
179 | 198 |
d["config_drive"] = "" |
180 | 199 |
d["accessIPv4"] = "" |
181 | 200 |
d["accessIPv6"] = "" |
182 |
fqdn = get_server_fqdn(vm) |
|
201 |
fqdn = get_server_fqdn(vm, active_nics)
|
|
183 | 202 |
d["SNF:fqdn"] = fqdn |
184 |
d["SNF:port_forwarding"] = get_server_port_forwarding(vm, fqdn)
|
|
185 |
|
|
203 |
d["SNF:port_forwarding"] = get_server_port_forwarding(vm, active_nics,
|
|
204 |
fqdn) |
|
186 | 205 |
return d |
187 | 206 |
|
188 | 207 |
|
189 |
def get_server_fqdn(vm): |
|
208 |
def get_server_public_ip(vm_nics, version=4): |
|
209 |
"""Get the first public IP address of a server. |
|
210 |
|
|
211 |
NOTE: 'vm_nics' objects have prefetched the ips |
|
212 |
""" |
|
213 |
for version in [4, 6]: |
|
214 |
for nic in vm_nics: |
|
215 |
for ip in nic.ips.all(): |
|
216 |
if ip.ipversion == version and ip.public: |
|
217 |
return ip |
|
218 |
return None |
|
219 |
|
|
220 |
|
|
221 |
def get_server_fqdn(vm, vm_nics): |
|
222 |
public_ip = get_server_public_ip(vm_nics) |
|
223 |
if public_ip is None: |
|
224 |
return "" |
|
225 |
|
|
190 | 226 |
fqdn_setting = settings.CYCLADES_SERVERS_FQDN |
191 | 227 |
if fqdn_setting is None: |
192 |
# Return the first public IPv4 address if exists |
|
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 |
|
228 |
return public_ip.address |
|
201 | 229 |
elif isinstance(fqdn_setting, basestring): |
202 | 230 |
return fqdn_setting % {"id": vm.id} |
203 | 231 |
else: |
... | ... | |
206 | 234 |
raise faults.InternalServerError(msg) |
207 | 235 |
|
208 | 236 |
|
209 |
def get_server_port_forwarding(vm, fqdn): |
|
237 |
def get_server_port_forwarding(vm, vm_nics, fqdn):
|
|
210 | 238 |
"""Create API 'port_forwarding' attribute from corresponding setting. |
211 | 239 |
|
212 | 240 |
Create the 'port_forwarding' API vm attribute based on the corresponding |
... | ... | |
218 | 246 |
* fqdn |
219 | 247 |
* owner UUID |
220 | 248 |
|
249 |
NOTE: 'vm_nics' objects have prefetched the ips |
|
221 | 250 |
""" |
222 | 251 |
port_forwarding = {} |
252 |
public_ip = get_server_public_ip(vm_nics) |
|
253 |
if public_ip is None: |
|
254 |
return port_forwarding |
|
223 | 255 |
for dport, to_dest in settings.CYCLADES_PORT_FORWARDING.items(): |
224 | 256 |
if hasattr(to_dest, "__call__"): |
225 |
address = db_query.get_server_public_ip(server=vm, version=4) |
|
226 |
to_dest = to_dest(address, vm.id, fqdn, vm.userid) |
|
257 |
to_dest = to_dest(public_ip.address, vm.id, fqdn, vm.userid) |
|
227 | 258 |
msg = ("Invalid setting: CYCLADES_PORT_FOWARDING." |
228 | 259 |
" Value must be a tuple of two elements (host, port).") |
229 |
if to_dest is None: |
|
230 |
continue |
|
231 | 260 |
if not isinstance(to_dest, tuple) or len(to_dest) != 2: |
232 | 261 |
raise faults.InternalServerError(msg) |
233 | 262 |
else: |
... | ... | |
307 | 336 |
|
308 | 337 |
log.debug('list_servers detail=%s', detail) |
309 | 338 |
user_vms = VirtualMachine.objects.filter(userid=request.user_uniq) |
339 |
if detail: |
|
340 |
user_vms = user_vms.prefetch_related("nics__ips") |
|
310 | 341 |
|
311 | 342 |
user_vms = utils.filter_modified_since(request, objects=user_vms) |
312 | 343 |
|
... | ... | |
388 | 419 |
# overLimit (413) |
389 | 420 |
|
390 | 421 |
log.debug('get_server_details %s', server_id) |
391 |
vm = util.get_vm(server_id, request.user_uniq) |
|
422 |
vm = util.get_vm(server_id, request.user_uniq, |
|
423 |
prefetch_related="nics__ips") |
|
392 | 424 |
server = vm_to_dict(vm, detail=True) |
393 | 425 |
return render_server(request, server) |
394 | 426 |
|
... | ... | |
492 | 524 |
# overLimit (413) |
493 | 525 |
|
494 | 526 |
log.debug('list_addresses %s', server_id) |
495 |
vm = util.get_vm(server_id, request.user_uniq) |
|
496 |
attachments = [nic_to_dict(nic) for nic in vm.nics.filter(state="ACTIVE")] |
|
527 |
vm = util.get_vm(server_id, request.user_uniq, prefetch_related="nic__ips") |
|
528 |
attachments = [nic_to_attachments(nic) |
|
529 |
for nic in vm.nics.filter(state="ACTIVE")] |
|
497 | 530 |
addresses = attachments_to_addresses(attachments) |
498 | 531 |
|
499 | 532 |
if request.serialization == 'xml': |
... | ... | |
518 | 551 |
machine = util.get_vm(server_id, request.user_uniq) |
519 | 552 |
network = util.get_network(network_id, request.user_uniq) |
520 | 553 |
nics = machine.nics.filter(network=network, state="ACTIVE") |
521 |
addresses = attachments_to_addresses(map(nic_to_dict, nics))
|
|
554 |
addresses = attachments_to_addresses(map(nic_to_attachments, nics))
|
|
522 | 555 |
|
523 | 556 |
if request.serialization == 'xml': |
524 | 557 |
data = render_to_string('address.xml', {'addresses': addresses}) |
Also available in: Unified diff