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

Refactor some code to API create_server method

parent 686bd605
......@@ -31,8 +31,6 @@
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
from base64 import b64decode
from django.conf import settings
from django.conf.urls.defaults import patterns
from django.db import transaction
......@@ -48,7 +46,6 @@ from synnefo.logic.backend import create_instance, delete_instance
from synnefo.logic.utils import get_rsapi_state
from synnefo.logic.rapi import GanetiApiError
from synnefo.logic.backend_allocator import BackendAllocator
from random import choice
from logging import getLogger
......@@ -258,6 +255,7 @@ def create_server(request):
try:
req = util.get_request_dict(request)
log.info('create_server %s', req)
user_id = request.user_uniq
try:
server = req['server']
......@@ -274,40 +272,17 @@ def create_server(request):
if len(personality) > settings.MAX_PERSONALITY:
raise faults.OverLimit("Maximum number of personalities exceeded")
for p in personality:
# Verify that personalities are well-formed
try:
assert isinstance(p, dict)
keys = set(p.keys())
allowed = set(['contents', 'group', 'mode', 'owner', 'path'])
assert keys.issubset(allowed)
contents = p['contents']
if len(contents) > settings.MAX_PERSONALITY_SIZE:
# No need to decode if contents already exceed limit
raise faults.OverLimit("Maximum size of personality exceeded")
if len(b64decode(contents)) > settings.MAX_PERSONALITY_SIZE:
raise faults.OverLimit("Maximum size of personality exceeded")
except AssertionError:
raise faults.BadRequest("Malformed personality in request")
image = {}
img = util.get_image(image_id, request.user_uniq)
properties = img.get('properties', {})
image['backend_id'] = img['location']
image['format'] = img['disk_format']
image['metadata'] = dict((key.upper(), val) \
for key, val in properties.items())
# Ensure that request if for active flavor
flavor = util.get_flavor(flavor_id, include_deleted=False)
util.verify_personality(personality)
image = util.get_image_dict(image_id, user_id)
flavor = util.get_flavor(flavor_id)
password = util.random_password()
count = VirtualMachine.objects.filter(userid=request.user_uniq,
count = VirtualMachine.objects.filter(userid=user_id,
deleted=False).count()
# get user limit
vms_limit_for_user = \
settings.VMS_USER_QUOTA.get(request.user_uniq,
settings.VMS_USER_QUOTA.get(user_id,
settings.MAX_VMS_PER_USER)
if count >= vms_limit_for_user:
......@@ -326,19 +301,10 @@ def create_server(request):
transaction.commit()
try:
if settings.PUBLIC_USE_POOL:
(network, address) = util.allocate_public_address(backend)
if address is None:
log.error("Public networks of backend %s are full", backend)
msg = "Failed to allocate public IP for new VM"
raise faults.ServiceUnavailable(msg)
nic = {'ip': address, 'network': network.backend_id}
else:
network = choice(list(util.backend_public_networks(backend)))
nic = {'ip': 'pool', 'network': network.backend_id}
(network, address) = util.get_public_ip(backend)
nic = {'ip': address, 'network': network.backend_id}
except:
transaction.rollback()
raise
else:
transaction.commit()
......@@ -348,19 +314,20 @@ def create_server(request):
vm = VirtualMachine.objects.create(
name=name,
backend=backend,
userid=request.user_uniq,
userid=user_id,
imageid=image_id,
flavor=flavor,
action="CREATE")
try:
jobID = create_instance(vm, nic, flavor, image, password, personality)
jobID = create_instance(vm, nic, flavor, image, password,
personality)
except GanetiApiError:
vm.delete()
raise
log.info("User %s created VM %s, NIC %s, Backend %s, JobID %s",
request.user_uniq, vm, nic, backend, str(jobID))
user_id, vm, nic, backend, str(jobID))
vm.backendjobid = jobID
vm.save()
......
......@@ -33,7 +33,7 @@
import datetime
from base64 import b64encode
from base64 import b64encode, b64decode
from datetime import timedelta, tzinfo
from functools import wraps
from hashlib import sha256
......@@ -57,7 +57,7 @@ from django.db.models import Q
from synnefo.api.faults import (Fault, BadRequest, BuildInProgress,
ItemNotFound, ServiceUnavailable, Unauthorized,
BadMediaType, Forbidden)
BadMediaType, Forbidden, OverLimit)
from synnefo.db.models import (Flavor, VirtualMachine, VirtualMachineMetadata,
Network, BackendNetwork, NetworkInterface,
BridgePoolTable, MacPrefixPoolTable)
......@@ -200,6 +200,17 @@ def get_image(image_id, user_id):
backend.close()
def get_image_dict(image_id, user_id):
image = {}
img = get_image(image_id, user_id)
properties = img.get('properties', {})
image['backend_id'] = img['location']
image['format'] = img['disk_format']
image['metadata'] = dict((key.upper(), val) \
for key, val in properties.items())
return image
def get_flavor(flavor_id, include_deleted=False):
"""Return a Flavor instance or raise ItemNotFound."""
......@@ -242,6 +253,29 @@ def allocate_public_address(backend):
return (None, None)
def get_public_ip(backend):
"""Reserve an IP from a public network.
This method should run inside a transaction.
"""
address = None
if settings.PUBLIC_ROUTED_USE_POOL:
(network, address) = allocate_public_address(backend)
else:
for net in list(backend_public_networks(backend)):
pool = net.get_pool()
if not pool.empty():
address = 'pool'
network = net
break
if address is None:
log.error("Public networks of backend %s are full", backend)
raise OverLimit("Can not allocate IP for new machine."
" Public networks are full.")
return (network, address)
def backend_public_networks(backend):
"""Return available public networks of the backend.
......@@ -445,3 +479,21 @@ def net_resources(net_type):
raise BadRequest('Unknown network type')
return link, mac_prefix
def verify_personality(personality):
for p in personality:
# Verify that personalities are well-formed
try:
assert isinstance(p, dict)
keys = set(p.keys())
allowed = set(['contents', 'group', 'mode', 'owner', 'path'])
assert keys.issubset(allowed)
contents = p['contents']
if len(contents) > settings.MAX_PERSONALITY_SIZE:
# No need to decode if contents already exceed limit
raise OverLimit("Maximum size of personality exceeded")
if len(b64decode(contents)) > settings.MAX_PERSONALITY_SIZE:
raise OverLimit("Maximum size of personality exceeded")
except AssertionError:
raise BadRequest("Malformed personality in request")
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