Commit e687b8c4 authored by Vangelis Koukis's avatar Vangelis Koukis
Browse files

Merge branches api-current and ui-0.4, minor fixes

Merge branches api-current and ui-0.4:
    * Fix merge conflicts
    * Fix minor bug in reconciliation mgmt command
    * Add comments in settings.py.dist
    * minor PEP8 fixes
parent 5e674ac7
......@@ -12,8 +12,7 @@ from django.utils import simplejson as json
from synnefo.api.faults import BadRequest, ServiceUnavailable
from synnefo.api.util import random_password, get_vm
from synnefo.util.vapclient import request_forwarding as request_vnc_forwarding
from synnefo.logic.backend import (reboot_instance, startup_instance, shutdown_instance,
get_instance_console)
from synnefo.logic import backend
from synnefo.logic.utils import get_rsapi_state
......@@ -76,7 +75,7 @@ def reboot(request, vm, args):
reboot_type = args.get('type', '')
if reboot_type not in ('SOFT', 'HARD'):
raise BadRequest('Malformed Request.')
reboot_instance(vm, reboot_type.lower())
backend.reboot_instance(vm, reboot_type.lower())
return HttpResponse(status=202)
@server_action('start')
......@@ -87,7 +86,7 @@ def start(request, vm, args):
if args:
raise BadRequest('Malformed Request.')
startup_instance(vm)
backend.startup_instance(vm)
return HttpResponse(status=202)
@server_action('shutdown')
......@@ -98,7 +97,7 @@ def shutdown(request, vm, args):
if args:
raise BadRequest('Malformed Request.')
shutdown_instance(vm)
backend.shutdown_instance(vm)
return HttpResponse(status=202)
@server_action('rebuild')
......@@ -196,10 +195,11 @@ def get_console(request, vm, args):
if settings.TEST:
console_data = {'kind': 'vnc', 'host': 'ganeti_node', 'port': 1000}
else:
console_data = get_instance_console(vm)
console_data = backend.get_instance_console(vm)
if console_data['kind'] != 'vnc':
raise ServiceUnavailable('Could not create a console of requested type.')
message = 'Could not create a console of requested type.'
raise ServiceUnavailable(message)
# Let vncauthproxy decide on the source port.
# The alternative: static allocation, e.g.
......@@ -251,7 +251,8 @@ def add(request, net, args):
if not server_id:
raise BadRequest('Malformed Request.')
vm = get_vm(server_id, request.user)
net.machines.add(vm)
backend.connect_to_network(vm, net)
vm.save()
net.save()
return HttpResponse(status=202)
......@@ -270,6 +271,7 @@ def remove(request, net, args):
if not server_id:
raise BadRequest('Malformed Request.')
vm = get_vm(server_id, request.user)
net.machines.remove(vm)
backend.disconnect_from_network(vm, net)
vm.save()
net.save()
return HttpResponse(status=202)
......@@ -28,5 +28,8 @@ class ItemNotFound(Fault):
class BuildInProgress(Fault):
code = 409
class OverLimit(Fault):
code = 413
class ServiceUnavailable(Fault):
code = 503
......@@ -264,8 +264,6 @@
"charged": "2011-02-06 00:00:00",
"sourceimage": 1,
"hostid": "HAL-9000",
"ipfour": "192.168.2.1",
"ipsix": "::1",
"flavor": 1,
"operstate": "STOPPED"
}
......@@ -281,8 +279,6 @@
"charged": "2011-02-10 00:00:00",
"sourceimage": 1,
"hostid": "HAL-9000",
"ipfour": "192.168.2.2",
"ipsix": "::2",
"flavor": 1,
"operstate": "BUILD"
}
......@@ -298,8 +294,6 @@
"charged": "2011-02-10 00:00:00",
"sourceimage": 1,
"hostid": "HAL-9000",
"ipfour": "192.168.2.3",
"ipsix": "::3",
"flavor": 1,
"operstate": "STARTED"
}
......@@ -315,8 +309,6 @@
"charged": "2011-02-10 00:00:00",
"sourceimage": 1,
"hostid": "HAL-9000",
"ipfour": "192.168.2.4",
"ipsix": "::4",
"flavor": 1,
"operstate": "STARTED"
}
......
......@@ -7,7 +7,7 @@ from django.http import HttpResponse
from django.template.loader import render_to_string
from django.utils import simplejson as json
from synnefo.api.util import get_flavor, api_method
from synnefo.api import util
from synnefo.db.models import Flavor
......@@ -27,7 +27,7 @@ def flavor_to_dict(flavor, detail=True):
return d
@api_method('GET')
@util.api_method('GET')
def list_flavors(request, detail=False):
# Normal Response Codes: 200, 203
# Error Response Codes: computeFault (400, 500),
......@@ -40,13 +40,15 @@ def list_flavors(request, detail=False):
flavors = [flavor_to_dict(flavor, detail) for flavor in all_flavors]
if request.serialization == 'xml':
data = render_to_string('list_flavors.xml', {'flavors': flavors, 'detail': detail})
data = render_to_string('list_flavors.xml', {
'flavors': flavors,
'detail': detail})
else:
data = json.dumps({'flavors': {'values': flavors}})
return HttpResponse(data, status=200)
@api_method('GET')
@util.api_method('GET')
def get_flavor_details(request, flavor_id):
# Normal Response Codes: 200, 203
# Error Response Codes: computeFault (400, 500),
......@@ -56,7 +58,7 @@ def get_flavor_details(request, flavor_id):
# itemNotFound (404),
# overLimit (413)
flavor = get_flavor(flavor_id)
flavor = util.get_flavor(flavor_id)
flavordict = flavor_to_dict(flavor, detail=True)
if request.serialization == 'xml':
......
......@@ -2,17 +2,16 @@
# Copyright (c) 2010 Greek Research and Technology Network
#
from synnefo.api.common import method_not_allowed
from synnefo.api.faults import BadRequest
from synnefo.api.util import (isoformat, isoparse, get_vm, get_image, get_image_meta,
get_request_dict, render_metadata, render_meta, api_method)
from synnefo.db.models import Image, ImageMetadata
from django.conf.urls.defaults import patterns
from django.http import HttpResponse
from django.template.loader import render_to_string
from django.utils import simplejson as json
from synnefo.api import util
from synnefo.api.common import method_not_allowed
from synnefo.api.faults import BadRequest
from synnefo.db.models import Image, ImageMetadata
urlpatterns = patterns('synnefo.api.images',
(r'^(?:/|.json|.xml)?$', 'demux'),
......@@ -60,8 +59,8 @@ def metadata_item_demux(request, image_id, key):
def image_to_dict(image, detail=True):
d = {'id': image.id, 'name': image.name}
if detail:
d['updated'] = isoformat(image.updated)
d['created'] = isoformat(image.created)
d['updated'] = util.isoformat(image.updated)
d['created'] = util.isoformat(image.created)
d['status'] = image.state
d['progress'] = 100 if image.state == 'ACTIVE' else 0
if image.sourcevm:
......@@ -81,7 +80,7 @@ def metadata_to_dict(image):
return dict((meta.meta_key, meta.meta_value) for meta in image_meta)
@api_method('GET')
@util.api_method('GET')
def list_images(request, detail=False):
# Normal Response Codes: 200, 203
# Error Response Codes: computeFault (400, 500),
......@@ -90,10 +89,11 @@ def list_images(request, detail=False):
# badRequest (400),
# overLimit (413)
since = isoparse(request.GET.get('changes-since'))
since = util.isoparse(request.GET.get('changes-since'))
if since:
avail_images = Image.objects.filter(owner=request.user, updated__gte=since)
avail_images = Image.objects.filter(owner=request.user,
updated__gte=since)
if not avail_images:
return HttpResponse(status=304)
else:
......@@ -102,13 +102,15 @@ def list_images(request, detail=False):
images = [image_to_dict(image, detail) for image in avail_images]
if request.serialization == 'xml':
data = render_to_string('list_images.xml', {'images': images, 'detail': detail})
data = render_to_string('list_images.xml', {
'images': images,
'detail': detail})
else:
data = json.dumps({'images': {'values': images}})
return HttpResponse(data, status=200)
@api_method('POST')
@util.api_method('POST')
def create_image(request):
# Normal Response Code: 202
# Error Response Codes: computeFault (400, 500),
......@@ -123,7 +125,7 @@ def create_image(request):
# backupOrResizeInProgress (409),
# overLimit (413)
req = get_request_dict(request)
req = util.get_request_dict(request)
try:
d = req['image']
......@@ -133,7 +135,7 @@ def create_image(request):
raise BadRequest('Malformed request.')
owner = request.user
vm = get_vm(server_id, owner)
vm = util.get_vm(server_id, owner)
image = Image.objects.create(name=name, owner=owner, sourcevm=vm)
imagedict = image_to_dict(image)
......@@ -144,7 +146,7 @@ def create_image(request):
return HttpResponse(data, status=202)
@api_method('GET')
@util.api_method('GET')
def get_image_details(request, image_id):
# Normal Response Codes: 200, 203
# Error Response Codes: computeFault (400, 500),
......@@ -154,7 +156,7 @@ def get_image_details(request, image_id):
# itemNotFound (404),
# overLimit (413)
image = get_image(image_id, request.user)
image = util.get_image(image_id, request.user)
imagedict = image_to_dict(image)
if request.serialization == 'xml':
......@@ -164,7 +166,7 @@ def get_image_details(request, image_id):
return HttpResponse(data, status=200)
@api_method('DELETE')
@util.api_method('DELETE')
def delete_image(request, image_id):
# Normal Response Code: 204
# Error Response Codes: computeFault (400, 500),
......@@ -173,11 +175,11 @@ def delete_image(request, image_id):
# itemNotFound (404),
# overLimit (413)
image = get_image(image_id, request.user)
image = util.get_image(image_id, request.user)
image.delete()
return HttpResponse(status=204)
@api_method('GET')
@util.api_method('GET')
def list_metadata(request, image_id):
# Normal Response Codes: 200, 203
# Error Response Codes: computeFault (400, 500),
......@@ -186,11 +188,11 @@ def list_metadata(request, image_id):
# badRequest (400),
# overLimit (413)
image = get_image(image_id, request.user)
image = util.get_image(image_id, request.user)
metadata = metadata_to_dict(image)
return render_metadata(request, metadata, use_values=True, status=200)
return util.render_metadata(request, metadata, use_values=True, status=200)
@api_method('POST')
@util.api_method('POST')
def update_metadata(request, image_id):
# Normal Response Code: 201
# Error Response Codes: computeFault (400, 500),
......@@ -201,8 +203,8 @@ def update_metadata(request, image_id):
# badMediaType(415),
# overLimit (413)
image = get_image(image_id, request.user)
req = get_request_dict(request)
image = util.get_image(image_id, request.user)
req = util.get_request_dict(request)
try:
metadata = req['metadata']
assert isinstance(metadata, dict)
......@@ -219,10 +221,13 @@ def update_metadata(request, image_id):
updated[key] = val
except ImageMetadata.DoesNotExist:
pass # Ignore non-existent metadata
if updated:
image.save()
return util.render_metadata(request, updated, status=201)
return render_metadata(request, updated, status=201)
@api_method('GET')
@util.api_method('GET')
def get_metadata_item(request, image_id, key):
# Normal Response Codes: 200, 203
# Error Response Codes: computeFault (400, 500),
......@@ -232,11 +237,11 @@ def get_metadata_item(request, image_id, key):
# badRequest (400),
# overLimit (413)
image = get_image(image_id, request.user)
meta = get_image_meta(image, key)
return render_meta(request, meta, status=200)
image = util.get_image(image_id, request.user)
meta = util.get_image_meta(image, key)
return util.render_meta(request, meta, status=200)
@api_method('PUT')
@util.api_method('PUT')
def create_metadata_item(request, image_id, key):
# Normal Response Code: 201
# Error Response Codes: computeFault (400, 500),
......@@ -248,8 +253,8 @@ def create_metadata_item(request, image_id, key):
# badMediaType(415),
# overLimit (413)
image = get_image(image_id, request.user)
req = get_request_dict(request)
image = util.get_image(image_id, request.user)
req = util.get_request_dict(request)
try:
metadict = req['meta']
assert isinstance(metadict, dict)
......@@ -257,13 +262,17 @@ def create_metadata_item(request, image_id, key):
assert key in metadict
except (KeyError, AssertionError):
raise BadRequest('Malformed request.')
meta, created = ImageMetadata.objects.get_or_create(meta_key=key, image=image)
meta, created = ImageMetadata.objects.get_or_create(
meta_key=key,
image=image)
meta.meta_value = metadict[key]
meta.save()
return render_meta(request, meta, status=201)
image.save()
return util.render_meta(request, meta, status=201)
@api_method('DELETE')
@util.api_method('DELETE')
def delete_metadata_item(request, image_id, key):
# Normal Response Code: 204
# Error Response Codes: computeFault (400, 500),
......@@ -275,7 +284,8 @@ def delete_metadata_item(request, image_id, key):
# badMediaType(415),
# overLimit (413),
image = get_image(image_id, request.user)
meta = get_image_meta(image, key)
image = util.get_image(image_id, request.user)
meta = util.get_image_meta(image, key)
meta.delete()
image.save()
return HttpResponse(status=204)
from synnefo.api.actions import network_actions
from synnefo.api.common import method_not_allowed
from synnefo.api.faults import BadRequest, Unauthorized
from synnefo.api.util import (isoformat, isoparse, get_network,
get_request_dict, api_method)
from synnefo.db.models import Network
from django.conf.urls.defaults import patterns
from django.db.models import Q
from django.http import HttpResponse
from django.template.loader import render_to_string
from django.utils import simplejson as json
from synnefo.api import util
from synnefo.api.actions import network_actions
from synnefo.api.common import method_not_allowed
from synnefo.api.faults import BadRequest, OverLimit, Unauthorized
from synnefo.db.models import Network
from synnefo.logic import backend
urlpatterns = patterns('synnefo.api.networks',
(r'^(?:/|.json|.xml)?$', 'demux'),
......@@ -38,9 +40,13 @@ def network_demux(request, network_id):
def network_to_dict(network, detail=True):
d = {'id': network.id, 'name': network.name}
network_id = str(network.id) if not network.public else 'public'
d = {'id': network_id, 'name': network.name}
if detail:
d['updated'] = util.isoformat(network.updated)
d['created'] = util.isoformat(network.created)
d['servers'] = {'values': [vm.id for vm in network.machines.all()]}
d['status'] = network.state
return d
def render_network(request, networkdict, status=200):
......@@ -51,7 +57,7 @@ def render_network(request, networkdict, status=200):
return HttpResponse(data, status=status)
@api_method('GET')
@util.api_method('GET')
def list_networks(request, detail=False):
# Normal Response Codes: 200, 203
# Error Response Codes: computeFault (400, 500),
......@@ -59,26 +65,30 @@ def list_networks(request, detail=False):
# unauthorized (401),
# badRequest (400),
# overLimit (413)
since = isoparse(request.GET.get('changes-since'))
owner = request.user
since = util.isoparse(request.GET.get('changes-since'))
user_networks = Network.objects.filter(Q(owner=owner) | Q(public=True))
if since:
user_networks = Network.objects.filter(owner=request.user, updated__gte=since)
user_networks = user_networks.filter(updated__gte=since)
if not user_networks:
return HttpResponse(status=304)
else:
user_networks = Network.objects.filter(owner=request.user)
user_networks = user_networks.filter(state='ACTIVE')
networks = [network_to_dict(network, detail) for network in user_networks]
if request.serialization == 'xml':
data = render_to_string('list_networks.xml', {'networks': networks, 'detail': detail})
data = render_to_string('list_networks.xml', {
'networks': networks,
'detail': detail})
else:
data = json.dumps({'networks': {'values': networks}})
return HttpResponse(data, status=200)
@api_method('POST')
@util.api_method('POST')
def create_network(request):
# Normal Response Code: 202
# Error Response Codes: computeFault (400, 500),
......@@ -88,19 +98,22 @@ def create_network(request):
# badRequest (400),
# overLimit (413)
req = get_request_dict(request)
req = util.get_request_dict(request)
try:
d = req['network']
name = d['name']
except (KeyError, ValueError):
raise BadRequest('Malformed request.')
network = Network.objects.create(name=name, owner=request.user)
network = backend.create_network(name, request.user)
if not network:
raise OverLimit('Maximum number of networks reached.')
networkdict = network_to_dict(network)
return render_network(request, networkdict, status=202)
@api_method('GET')
@util.api_method('GET')
def get_network_details(request, network_id):
# Normal Response Codes: 200, 203
# Error Response Codes: computeFault (400, 500),
......@@ -110,11 +123,11 @@ def get_network_details(request, network_id):
# itemNotFound (404),
# overLimit (413)
net = get_network(network_id, request.user)
net = util.get_network(network_id, request.user)
netdict = network_to_dict(net)
return render_network(request, netdict)
@api_method('PUT')
@util.api_method('PUT')
def update_network_name(request, network_id):
# Normal Response Code: 204
# Error Response Codes: computeFault (400, 500),
......@@ -125,19 +138,21 @@ def update_network_name(request, network_id):
# itemNotFound (404),
# overLimit (413)
req = get_request_dict(request)
req = util.get_request_dict(request)
try:
name = req['network']['name']
except (TypeError, KeyError):
raise BadRequest('Malformed request.')
net = get_network(network_id, request.user)
net = util.get_network(network_id, request.user)
if net.public:
raise Unauthorized('Can not rename the public network.')
net.name = name
net.save()
return HttpResponse(status=204)
@api_method('DELETE')
@util.api_method('DELETE')
def delete_network(request, network_id):
# Normal Response Code: 204
# Error Response Codes: computeFault (400, 500),
......@@ -146,15 +161,20 @@ def delete_network(request, network_id):
# itemNotFound (404),
# unauthorized (401),
# overLimit (413)
net = get_network(network_id, request.user)
net.delete()
net = util.get_network(network_id, request.user)
if net.public:
raise Unauthorized('Can not delete the public network.')
backend.delete_network(net)
return HttpResponse(status=204)
@api_method('POST')
@util.api_method('POST')
def network_action(request, network_id):
net = get_network(network_id, request.user)
req = get_request_dict(request)
net = util.get_network(network_id, request.user)
if net.public:
raise Unauthorized('Can not modify the public network.')
req = util.get_request_dict(request)
if len(req) != 1:
raise BadRequest('Malformed request.')
......
......@@ -9,12 +9,10 @@ from django.http import HttpResponse
from django.template.loader import render_to_string
from django.utils import simplejson as json
from synnefo.api import util
from synnefo.api.actions import server_actions
from synnefo.api.common import method_not_allowed
from synnefo.api.faults import BadRequest, ItemNotFound, ServiceUnavailable
from synnefo.api.util import (isoformat, isoparse, random_password,
get_vm, get_vm_meta, get_image, get_flavor,
get_request_dict, render_metadata, render_meta, api_method)
from synnefo.db.models import VirtualMachine, VirtualMachineMetadata
from synnefo.logic.backend import create_instance, delete_instance
from synnefo.logic.utils import get_rsapi_state
......@@ -70,9 +68,19 @@ def metadata_item_demux(request, server_id, key):
return method_not_allowed(request)
def address_to_dict(ipfour, ipsix):
return {'id': 'public',
'values': [{'version': 4, 'addr': ipfour}, {'version': 6, 'addr': ipsix}]}
def nic_to_dict(nic):
network = nic.network
network_id = str(network.id) if not network.public else 'public'
d = {'id': network_id, 'name': network.name, 'mac': nic.mac}
if nic.firewall_profile:
d['firewallProfile'] = nic.firewall_profile
if nic.ipv4 or nic.ipv6:
d['values'] = []
if nic.ipv4:
d['values'].append({'version': 4, 'addr': nic.ipv4})
if nic.ipv6:
d['values'].append({'version': 6, 'addr': nic.ipv6})
return d
def metadata_to_dict(vm):
vm_meta = vm.virtualmachinemetadata_set.all()
......@@ -84,8 +92,8 @@ def vm_to_dict(vm, detail=False):
d['status'] = get_rsapi_state(vm)
d['progress'] = 100 if get_rsapi_state(vm) == 'ACTIVE' else 0
d['hostId'] = vm.hostid
d['updated'] = isoformat(vm.updated)
d['created'] = isoformat(vm.created)
d['updated'] = util.isoformat(vm.updated)
d['created'] = util.isoformat(vm.created)
d['flavorRef'] = vm.flavor.id
d['imageRef'] = vm.sourceimage.id
......@@ -93,21 +101,23 @@ def vm_to_dict(vm, detail=False):
if metadata:
d['metadata'] = {'values': metadata}
addresses = [address_to_dict(vm.ipfour, vm.ipsix)]
addresses.extend({'id': str(network.id), 'values': []} for network in vm.network_set.all())
d['addresses'] = {'values': addresses}
addresses = [nic_to_dict(nic) for nic in vm.nics.all()]
if addresses:
d['addresses'] = {'values': addresses}
return d