Merge branch 'opennebula_api' of github.com:ungleich/dynamicweb into opennebula_api

This commit is contained in:
Levi 2017-05-13 00:31:33 -05:00
commit d8c8804cc4
7 changed files with 158 additions and 657 deletions

View file

@ -7,7 +7,6 @@ import oca
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils.functional import cached_property from django.utils.functional import cached_property
from hosting.opennebula_functions import OpenNebulaManager
from django.conf import settings from django.conf import settings
@ -18,8 +17,6 @@ from membership.models import StripeCustomer, CustomUser
from utils.models import BillingAddress from utils.models import BillingAddress
from utils.mixins import AssignPermissionsMixin from utils.mixins import AssignPermissionsMixin
from .managers import VMPlansManager from .managers import VMPlansManager
from oca.exceptions import OpenNebulaException
from oca.pool import WrongNameError
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)

View file

@ -1,567 +0,0 @@
import logging
import random
import socket
import string
import oca
from django.conf import settings
from django.conf.urls import url
from django.contrib import admin
from django.contrib import messages
from django.shortcuts import redirect
from django.template.response import TemplateResponse
from django.utils.translation import ugettext_lazy as _
from oca.exceptions import OpenNebulaException
from oca.pool import WrongNameError
from django import forms
# Get an instance of a logger
logger = logging.getLogger(__name__)
class OpenNebulaManager:
VM_STATE = {
'0': 'INIT',
'1': 'PENDING',
'2': 'HOLD',
'3': 'ACTIVE',
'4': 'STOPPED',
'5': 'SUSPENDED',
'6': 'DONE',
'8': 'POWEROFF',
'9': 'UNDEPLOYED',
'10': 'CLONING',
'11': 'CLONING_FAILURE',
}
def __init__(self, email=None, password=None):
# Get oneadmin client
self.oneadmin_client = self._get_opennebula_client(
settings.OPENNEBULA_USERNAME,
settings.OPENNEBULA_PASSWORD
)
# Get or create oppenebula user using given credentials
self.opennebula_user = self._get_or_create_user(
email,
password
)
# If opennebula user was created/obtained, get his client
if self.opennebula_user:
self.client = self._get_opennebula_client(
email,
password
)
def _get_opennebula_client(self, username, password):
return oca.Client("{0}:{1}".format(
username,
password),
"{protocol}://{domain}:{port}{endpoint}".format(
protocol=settings.OPENNEBULA_PROTOCOL,
domain=settings.OPENNEBULA_DOMAIN,
port=settings.OPENNEBULA_PORT,
endpoint=settings.OPENNEBULA_ENDPOINT
))
def _get_or_create_user(self, email, password):
try:
user_pool = oca.UserPool(self.oneadmin_client)
user_pool.info()
opennebula_user = user_pool.get_by_name(email)
return opennebula_user
except WrongNameError as wrong_name_err:
# TODO: Store this password so that we can use it later to
# connect to opennebula
opennebula_user = self.oneadmin_client.call(oca.User.METHODS['allocate'], email,
password, 'core')
logger.debug(
"User {0} does not exist. Created the user. User id = {1}",
email,
opennebula_user
)
return opennebula_user
except OpenNebulaException as err:
logger.error("Error : {0}".format(err))
@classmethod
def get_vm_state(self, state):
return self.VM_STATE.get(str(state))
@classmethod
def parse_vm(self, vm):
name = vm.name
cores = int(vm.template.vcpu)
memory = int(vm.template.memory) / 1024
# Check if vm has more than one disk
if 'DISK' in vm.template.multiple:
disk_size = 0
for disk in vm.template.disks:
disk_size += int(disk.size) / 1024
else:
disk_size = int(vm.template.disk.size) / 1024
#TODO: Replace with vm plan
price = 0.6 * disk_size + 2 * memory + 5 * cores
vm_data = {}
vm_data['name'] = name
vm_data['price'] = price
vm_data['disk_size'] = disk_size
vm_data['cores'] = cores
vm_data['memory'] = memory
vm_data['deploy_id'] = vm.deploy_id
vm_data['id'] = vm.id
vm_data['state'] = self.get_vm_state(vm.state)
return vm_data
def change_user_password(self, new_password):
self.oneadmin_client.call(
oca.User.METHODS['passwd'],
self.opennebula_user.id,
new_password
)
def create_vm(self, specs):
vm_id = None
try:
# We do have the vm_template param set. Get and parse it
# and check it to be in the desired range.
# We have 8 possible VM templates for the moment which are 1x, 2x, 4x ...
# the basic template of 10GB disk, 1GB ram, 1 vcpu, 0.1 cpu
vm_string_formatter = """<VM>
<MEMORY>{memory}</MEMORY>
<VCPU>{vcpu}</VCPU>
<CPU>{cpu}</CPU>
<DISK>
<TYPE>{disk_type}</TYPE>
<SIZE>{size}</SIZE>
</DISK>
<CONTEXT>
<SSH_PUBLIC_KEY>{ssh_key}</SSH_PUBLIC_KEY>
</CONTEXT>
</VM>
"""
vm_id = oca.VirtualMachine.allocate(
self.oneadmin_client,
vm_string_formatter.format(
memory=1024 * specs.get('memory'),
vcpu=specs.get('cores'),
cpu=0.1 * specs.get('cores'),
disk_type='fs',
size=10000 * specs.get('disk_size'),
ssh_key=specs.get('ssh_key')
)
)
self.oneadmin_client.call(
oca.VirtualMachine.METHODS['chown'],
vm_id,
self.opennebula_user.id,
self.opennebula_user.group_ids[0]
)
except socket.timeout as socket_err:
logger.error("Socket timeout error: {0}".format(socket_err))
except OpenNebulaException as opennebula_err:
logger.error("OpenNebulaException error: {0}".format(opennebula_err))
except OSError as os_err:
logger.error("OSError : {0}".format(os_err))
except ValueError as value_err:
logger.error("ValueError : {0}".format(value_err))
return vm_id
def terminate_vm(self, vm_id):
TERMINATE_ACTION = 'terminate'
vm_terminated = False
try:
self.oneadmin_client.call(
oca.VirtualMachine.METHODS['action'],
TERMINATE_ACTION,
int(vm_id),
)
vm_terminated = True
except socket.timeout as socket_err:
logger.error("Socket timeout error: {0}".format(socket_err))
except OpenNebulaException as opennebula_err:
logger.error("OpenNebulaException error: {0}".format(opennebula_err))
except OSError as os_err:
logger.error("OSError : {0}".format(os_err))
except ValueError as value_err:
logger.error("ValueError : {0}".format(value_err))
return vm_terminated
def get_vm_templates(self):
template_pool = oca.VmTemplatePool(self.oneadmin_client)
template_pool.info()
return template_pool
def get_vm(self, email, vm_id):
# Get vm's
vms = self.get_vms(email)
# Filter vm by given id
return vms.get_by_id(int(vm_id))
def get_vms(self, email):
client = self.oneadmin_client
# Get open nebula user id for given email
user_pool = oca.UserPool(client)
user_pool.info()
# TODO: handle potential name error
user_id = user_pool.get_by_name(email).id
# Get vm_pool for given user_id
vm_pool = oca.VirtualMachinePool(client)
vm_pool.info()
# TODO: this is just to test with oneadmin user, remove this
# user_id = 0
vm_pool.info(filter=user_id)
return vm_pool
class HostingManageVMAdmin(admin.ModelAdmin):
client = None
oneadmin_client = None
def get_urls(self):
urls = super().get_urls()
my_urls = [
url(r'^$', self.admin_site.admin_view(self.show_vms, cacheable=True), name='showvms'),
url(r'^create_vm/$', self.admin_site.admin_view(self.create_vm, cacheable=True), name='createvm'),
url(r'^delete_vm/(?P<vmid>\d+)/$', self.admin_site.admin_view(self.delete_vm, cacheable=True),
name='deletevm'),
url(r'^stop_vm/(?P<vmid>\d+)/$', self.admin_site.admin_view(self.stop_vm, cacheable=True), name='stopvm'),
url(r'^start_vm/(?P<vmid>\d+)/$', self.admin_site.admin_view(self.start_vm, cacheable=True),
name='startvm'),
]
return my_urls + urls
# Function to initialize opennebula client based on the logged in
# user
def init_opennebula_client(self, request):
if self.oneadmin_client is None:
self.oneadmin_client = oca.Client("{0}:{1}".format(settings.OPENNEBULA_USERNAME,
settings.OPENNEBULA_PASSWORD),
"{protocol}://{domain}:{port}{endpoint}".format(
protocol=settings.OPENNEBULA_PROTOCOL,
domain=settings.OPENNEBULA_DOMAIN,
port=settings.OPENNEBULA_PORT,
endpoint=settings.OPENNEBULA_ENDPOINT
))
logger.debug("{0}:{1}".format(settings.OPENNEBULA_USERNAME,
settings.OPENNEBULA_PASSWORD))
logger.debug("{protocol}://{domain}:{port}{endpoint}".format(
protocol=settings.OPENNEBULA_PROTOCOL,
domain=settings.OPENNEBULA_DOMAIN,
port=settings.OPENNEBULA_PORT,
endpoint=settings.OPENNEBULA_ENDPOINT
))
self.create_opennebula_user(request)
if self.client is None:
opennebula_user = request.user.email
# TODO: get the password stored in django
opennebula_user_password ='19737450'
self.client = oca.Client("{0}:{1}".format(opennebula_user, opennebula_user_password),
"{protocol}://{domain}:{port}{endpoint}".format(
protocol=settings.OPENNEBULA_PROTOCOL,
domain=settings.OPENNEBULA_DOMAIN,
port=settings.OPENNEBULA_PORT,
endpoint=settings.OPENNEBULA_ENDPOINT
))
# Function that shows the VMs of the current user
def show_vms(self, request):
vm_pool = None
try:
self.init_opennebula_client(request)
vm_pool = oca.VirtualMachinePool(self.client)
vm_pool.info()
except socket.timeout:
messages.add_message(request, messages.ERROR, _("Socket timeout error."))
except OpenNebulaException as opennebula_err:
messages.add_message(request, messages.ERROR, _("OpenNebulaException occurred. {0}".format(opennebula_err)))
except OSError as err:
messages.add_message(request, messages.ERROR, "OS error: {0}".format(err))
context = dict(
# Include common variables for rendering the admin template.
self.admin_site.each_context(request),
vms=vm_pool,
form=HostingManageVMForm
)
return TemplateResponse(request, "hosting/managevms.html", context)
# Function that shows the VMs of the current user
def show_vms_view(self, request):
"""
Implemented by Levi for the API
"""
vm_pool = None
try:
self.init_opennebula_client(request)
vm_pool = oca.VirtualMachinePool(self.client)
vm_pool.info()
except socket.timeout as socket_err:
logger.error("Socket timeout error.".format(socket_err))
except OpenNebulaException as opennebula_err:
logger.error("OpenNebulaException error: {0}".format(opennebula_err))
except OSError as os_err:
logger.error("OSError : {0}".format(os_err))
except ValueError as value_err:
logger.error("ValueError : {0}".format(value_err))
context = dict(
# Include common variables for rendering the admin template.
# self.admin_site.each_context(request),
vms=vm_pool,
)
return context
def create_vm_view(self, specs):
vm_id = None
try:
# We do have the vm_template param set. Get and parse it
# and check it to be in the desired range.
# We have 8 possible VM templates for the moment which are 1x, 2x, 4x ...
# the basic template of 10GB disk, 1GB ram, 1 vcpu, 0.1 cpu
vm_string_formatter = """<VM>
<MEMORY>{memory}</MEMORY>
<VCPU>{vcpu}</VCPU>
<CPU>{cpu}</CPU>
<DISK>
<TYPE>{disk_type}</TYPE>
<SIZE>{size}</SIZE>
</DISK>
</VM>
"""
vm_id = oca.VirtualMachine.allocate(
self.client,
vm_string_formatter.format(
memory=1024 * specs.get('memory'),
vcpu=specs.get('cores'),
cpu=0.1 * specs.get('cores'),
disk_type='fs',
size=10000 * specs.get('disk_size')
)
)
# message = _("Created with id = " + str(vm_id))
# messages.add_message(request, messages.SUCCESS, message)
except socket.timeout as socket_err:
logger.error("Socket timeout error: {0}".format(socket_err))
except OpenNebulaException as opennebula_err:
logger.error("OpenNebulaException error: {0}".format(opennebula_err))
except OSError as os_err:
logger.error("OSError : {0}".format(os_err))
except ValueError as value_err:
logger.error("ValueError : {0}".format(value_err))
return vm_id
# Creating VM by using method allocate(client, template)
def create_vm(self, request):
# check if the request contains the template parameter, if it is
# not set warn the user of setting this.
vm_template = request.POST.get('vm_template')
if vm_template == 'select':
messages.add_message(request, messages.ERROR, "Please select a vm template")
else:
try:
# We do have the vm_template param set. Get and parse it
# and check it to be in the desired range.
# We have 8 possible VM templates for the moment which are 1x, 2x, 4x ...
# the basic template of 10GB disk, 1GB ram, 1 vcpu, 0.1 cpu
vm_template_int = int(vm_template)
if 1 <= vm_template_int <= 8:
vm_string_formatter = """<VM>
<CONTEXT>
<SSH_PUBLIC_KEY>
{ssh_key}
</SSH_PUBLIC_KEY>
</CONTEXT>
<MEMORY>{memory}</MEMORY>
<VCPU>{vcpu}</VCPU>
<CPU>{cpu}</CPU>
<DISK>
<TYPE>{disk_type}</TYPE>
<SIZE>{size}</SIZE>
<DEV_PREFIX>{dev_prefix}</DEV_PREFIX>
</DISK>
</VM>
"""
vm_id = oca.VirtualMachine.allocate(self.client,
vm_string_formatter.format(
ssh_key='', # public key of the user
memory=1024 * vm_template_int, # memory in MB
vcpu=vm_template_int, # vpcu
cpu=0.1 * vm_template_int, # cpu
disk_type='fs',
size=10000 * vm_template_int,
dev_prefix='vd')) # We need KVM virtual disk
message = _("Created with id = " + str(vm_id))
messages.add_message(request, messages.SUCCESS, message)
else:
messages.add_message(request, messages.ERROR,
_("Please select an appropriate value for vm template."))
except socket.timeout as socket_err:
messages.add_message(request, messages.ERROR, _("Socket timeout error."))
logger.error("Socket timeout error: {0}".format(socket_err))
except OpenNebulaException as opennebula_err:
messages.add_message(request, messages.ERROR,
_("OpenNebulaException occurred. {0}".format(opennebula_err)))
logger.error("OpenNebulaException error: {0}".format(opennebula_err))
except OSError as os_err:
messages.add_message(request, messages.ERROR, _("OS error: {0}".format(os_err)))
logger.error("OSError : {0}".format(os_err))
except ValueError as value_err:
messages.add_message(request, messages.ERROR,
_("Please select an appropriate value for vm template."))
logger.error("ValueError : {0}".format(value_err))
return redirect('admin:showvms')
# Delete VM from the pool and DB by using method finalize()
def delete_vm(self, request, vmid):
vm_id = int(vmid)
# get the desired vm from the pool
logger.debug("Deleting vm with id {0}".format(vm_id))
vm = self.get_vm_by_id(vm_id)
if vm is None:
messages.add_message(request, messages.ERROR, _("Did not find a vm with id = {0}".format(vm_id)))
else:
logger.debug("Deleting vm_id = " + str(vm_id) + " state = " + vm.str_state)
if vm.str_state == 'PENDING' or vm.str_state == 'POWEROFF' or vm.str_state == 'ACTIVE':
vm.delete()
messages.add_message(request, messages.SUCCESS,
_("Deleted from {0} state vm with id = {1}".format(vm.str_state, str(vm_id))))
else:
vm.finalize()
messages.add_message(request, messages.SUCCESS,
_("Deleted (using finalize()) from {0} state vm with id = {1}".format(vm.str_state,
str(vm_id))))
return redirect('admin:showvms')
def stop_vm(self, request, vmid):
vm_id = int(vmid)
vm = self.get_vm_by_id(vm_id)
if vm is None:
messages.add_message(request, messages.ERROR, _("Did not find a vm with id = {0}", vm_id))
else:
vm.stop()
messages.add_message(request, messages.SUCCESS, _("Stopped the vm with id = {0}", vm_id))
return redirect('admin:showvms')
def start_vm(self, request, vmid):
vm_id = int(vmid)
vm = self.get_vm_by_id(vm_id)
if vm is None:
messages.add_message(request, messages.ERROR, _("Did not find a vm with id = {0}", vm_id))
else:
vm.resume()
messages.add_message(request, messages.SUCCESS, _("Started the vm with id = {0}", vm_id))
return redirect('admin:showvms')
# Retrives virtual machine pool information
def get_vm_pool(self):
vm_pool = oca.VirtualMachinePool(self.client)
vm_pool.info()
return vm_pool
def get_vm_by_id(self, vmid):
vm_pool = self.get_vm_pool()
return vm_pool.get_by_id(vmid)
def create_opennebula_user(self, request):
# Notes:
# 1. python-oca library's oca.User.allocate(client, user, pass)
# method does not work with python-oca version oca-4.15.0a1-py3.5
# This is because the call is missing a fourth parameter
# auth_driver.
# To overcome this issue, we make a direct call to xml-rpc method
# 'user.allocate' passing this fourth parameter.
#
# 2. We have a dummy authentication driver in opennebula and we
# use this so as to avoid opennebula authentication. However, we
# need to supply a dummy password. Without this, we can not
# create an OpenNebula user. We use dummy string 'a' as password
# for all users.
#
# 3. We user the user's email as the user name.
# 4. If the user's email is not registered with OpenNebula,
# WrongNameError is raised. We create an OpenNebula user in
# such case.
try:
user_pool = oca.UserPool(self.oneadmin_client)
user_pool.info()
opennebula_user = user_pool.get_by_name(request.user.email)
logger.debug("User {0} exists. User id = {1}".format(request.user.email, opennebula_user.id))
except WrongNameError as wrong_name_err:
# TODO: Store this password so that we can use it later to
# connect to opennebula
password = get_random_password()
oca.User.allocate(self.oneadmin_client, request.user.email, password)
logger.debug("User {0} does not exist. Created the user. User id = {1}", request.user.email, user_id)
except OpenNebulaException as err:
messages.add_message(request, messages.ERROR,
"Error : {0}".format(err))
logger.error("Error : {0}".format(err))
def set_field_html_name(cls, new_name):
"""
This creates wrapper around the normal widget rendering,
allowing for a custom field name (new_name).
"""
old_render = cls.widget.render
def _widget_render_wrapper(name, value, attrs=None):
return old_render(new_name, value, attrs)
cls.widget.render = _widget_render_wrapper
class HostingManageVMForm(forms.Form):
vm_templates = []
VM_CHOICES = (('1', 'disk = 10GB, vcpu=1, ram=1GB'),
('2', 'disk = 20GB, vcpu=2, ram=2GB'),
('3', 'disk = 40GB, vcpu=4, ram=4GB'),
('4', 'disk = 80GB, vcpu=8, ram=8GB'),
('5', 'disk = 160GB, vcpu=16, ram=16GB'),
('6', 'disk = 320GB, vcpu=32, ram=32GB'),
('7', 'disk = 640GB, vcpu=64, ram=64GB'),
('8', 'disk = 1280GB, vcpu=128, ram=128GB'))
#for i in range(0,8):
# factor = pow(2, i)
# vm_templates.append(VMTemplate(i, VM_CHOICES[i], 10000 * factor, factor , 0.1 * factor, 1024 * factor))
field = forms.ChoiceField(label="Choose a VM Template ", choices=VM_CHOICES, widget=forms.Select(attrs={"id": "vm_template"}))
set_field_html_name(field, 'vm_template')
class VMTemplate:
"""A simple representation of a VM template.
:param template_id: The id of the template
:param label: A string representation describing the template. Used as the label in view
:param disk: VM disk space in MB
:param vcpu: Virtual cpu for the VM
:param cpu: CPU for the VM
:param ram: The RAM for the VM
"""
def __init__(self, template_id, label, disk, vcpu, cpu, ram):
self.template_id = template_id
self.label = label
self.disk = disk
self.vcpu = vcpu
self.cpu = cpu
# Returns random password that is needed by OpenNebula
def get_random_password():
return ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(20))

View file

@ -24,16 +24,16 @@
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
<!-- <div class="form-group"> <div class="form-group">
Select VM Configuration: Select VM Configuration:
<select name="configuration"> <select name="vm_image_id">
{% for config in configuration_options %} {% for image in images %}
<option value="{{config.0}}">{{config.1}} </option> <option value="{{image.id}}">{{image.name}} </option>
{% endfor %} {% endfor %}
</select> </select>
</div> --> </div>
<div class="form-group"> <div class="form-group">
<button class="btn btn-success" >{% trans "Start VM"%} </button> <button class="btn btn-success" >{% trans "Start VM"%} </button>
</div> </div>

View file

@ -31,7 +31,9 @@ from .mixins import ProcessVMSelectionMixin
from opennebula_api.models import OpenNebulaManager from opennebula_api.models import OpenNebulaManager
from opennebula_api.serializers import VirtualMachineSerializer,\ from opennebula_api.serializers import VirtualMachineSerializer,\
VirtualMachineTemplateSerializer VirtualMachineTemplateSerializer,\
ImageSerializer
from oca.exceptions import OpenNebulaException from oca.exceptions import OpenNebulaException
from oca.pool import WrongNameError from oca.pool import WrongNameError
@ -408,6 +410,7 @@ class PaymentVMView(LoginRequiredMixin, FormView):
specifications = request.session.get('template') specifications = request.session.get('template')
vm_template_id = specifications.get('id', 1) vm_template_id = specifications.get('id', 1)
vm_image_id = request.session.get('image').get('id', 1)
final_price = specifications.get('price', 1) final_price = specifications.get('price', 1)
@ -443,10 +446,7 @@ class PaymentVMView(LoginRequiredMixin, FormView):
# Create OpenNebulaManager # Create OpenNebulaManager
manager = OpenNebulaManager(email=owner.email, manager = OpenNebulaManager(email=owner.email,
password=owner.password, password=owner.password)
create_user=True)
template = manager.get_template(vm_template_id)
# Get user ssh key # Get user ssh key
try: try:
user_key = UserHostingKey.objects.get( user_key = UserHostingKey.objects.get(
@ -458,8 +458,9 @@ class PaymentVMView(LoginRequiredMixin, FormView):
# Create a vm using logged user # Create a vm using logged user
vm_id = manager.create_vm( vm_id = manager.create_vm(
vm_template_id, template_id=vm_template_id,
ssh_key=user_key.public_key ssh_key=user_key.public_key,
image_id=vm_image_id,
) )
# Create a Hosting Order # Create a Hosting Order
@ -525,8 +526,7 @@ class OrdersHostingDetailView(PermissionRequiredMixin, LoginRequiredMixin, Detai
obj = self.get_object() obj = self.get_object()
owner = self.request.user owner = self.request.user
manager = OpenNebulaManager(email=owner.email, manager = OpenNebulaManager(email=owner.email,
password=owner.password, password=owner.password)
create_user=True)
vm = manager.get_vm(obj.vm_id) vm = manager.get_vm(obj.vm_id)
context['vm'] = VirtualMachineSerializer(vm).data context['vm'] = VirtualMachineSerializer(vm).data
return context return context
@ -562,8 +562,7 @@ class VirtualMachinesPlanListView(LoginRequiredMixin, ListView):
def get_queryset(self): def get_queryset(self):
owner = self.request.user owner = self.request.user
manager = OpenNebulaManager(email=owner.email, manager = OpenNebulaManager(email=owner.email,
password=owner.password, password=owner.password)
create_user=True)
queryset = manager.get_vms() queryset = manager.get_vms()
serializer = VirtualMachineSerializer(queryset, many=True) serializer = VirtualMachineSerializer(queryset, many=True)
return serializer.data return serializer.data
@ -586,21 +585,24 @@ class CreateVirtualMachinesView(LoginRequiredMixin, View):
) )
return HttpResponseRedirect(reverse('hosting:key_pair')) return HttpResponseRedirect(reverse('hosting:key_pair'))
#TODO: Replace with OpenNebulaManager.get_apps manager = OpenNebulaManager()
templates = OpenNebulaManager().get_templates() templates = manager.get_templates()
data = VirtualMachineTemplateSerializer(templates, many=True).data images = manager.get_images()
context = { context = {
'templates': data, 'templates': VirtualMachineTemplateSerializer(templates, many=True).data,
'images' : ImageSerializer(images, many=True).data
} }
# context = {}
return render(request, self.template_name, context) return render(request, self.template_name, context)
def post(self, request): def post(self, request):
template_id = int(request.POST.get('vm_template_id')) manager = OpenNebulaManager()
template = OpenNebulaManager().get_template(template_id) template_id = request.POST.get('vm_template_id')
data = VirtualMachineTemplateSerializer(template).data template = manager.get_template(template_id)
request.session['template'] = data image_id = request.POST.get('vm_image_id')
image = manager.get_image(image_id)
request.session['template'] = VirtualMachineTemplateSerializer(template).data
request.session['image'] = ImageSerializer(image).data
return redirect(reverse('hosting:payment')) return redirect(reverse('hosting:payment'))
@ -613,8 +615,7 @@ class VirtualMachineView(LoginRequiredMixin, View):
vm = None vm = None
manager = OpenNebulaManager( manager = OpenNebulaManager(
email=owner.email, email=owner.email,
password=owner.password, password=owner.password
create_user=True
) )
vm_id = self.kwargs.get('pk') vm_id = self.kwargs.get('pk')
try: try:
@ -644,8 +645,7 @@ class VirtualMachineView(LoginRequiredMixin, View):
manager = OpenNebulaManager( manager = OpenNebulaManager(
email=owner.email, email=owner.email,
password=owner.password, password=owner.password
create_user=True
) )
terminated = manager.delete_vm( terminated = manager.delete_vm(
@ -711,8 +711,7 @@ class HostingBillDetailView(PermissionRequiredMixin, LoginRequiredMixin, DetailV
owner = self.request.user owner = self.request.user
manager = OpenNebulaManager(email=owner.email, manager = OpenNebulaManager(email=owner.email,
password=owner.password, password=owner.password)
create_user=True)
# Get vms # Get vms
queryset = manager.get_vms() queryset = manager.get_vms()
vms = VirtualMachineSerializer(queryset, many=True).data vms = VirtualMachineSerializer(queryset, many=True).data

View file

@ -13,7 +13,7 @@ logger = logging.getLogger(__name__)
class OpenNebulaManager(): class OpenNebulaManager():
"""This class represents an opennebula manager.""" """This class represents an opennebula manager."""
def __init__(self, email=None, password=None, create_user=True): def __init__(self, email=None, password=None):
# Get oneadmin client # Get oneadmin client
self.oneadmin_client = self._get_opennebula_client( self.oneadmin_client = self._get_opennebula_client(
@ -21,21 +21,19 @@ class OpenNebulaManager():
settings.OPENNEBULA_PASSWORD settings.OPENNEBULA_PASSWORD
) )
if not create_user or email is None:
return
# Get or create oppenebula user using given credentials # Get or create oppenebula user using given credentials
self.opennebula_user = self._get_or_create_user( try:
email, self.opennebula_user = self._get_or_create_user(
password email,
) password
)
# If opennebula user was created/obtained, get his client # If opennebula user was created/obtained, get his client
if self.opennebula_user:
self.client = self._get_opennebula_client( self.client = self._get_opennebula_client(
email, email,
password password
) )
except:
pass
def _get_opennebula_client(self, username, password): def _get_opennebula_client(self, username, password):
return oca.Client("{0}:{1}".format( return oca.Client("{0}:{1}".format(
@ -56,10 +54,14 @@ class OpenNebulaManager():
except WrongNameError as wrong_name_err: except WrongNameError as wrong_name_err:
opennebula_user = self.oneadmin_client.call(oca.User.METHODS['allocate'], email, opennebula_user = self.oneadmin_client.call(oca.User.METHODS['allocate'], email,
password, 'core') password, 'core')
logger.debug(
"User {0} does not exist. Created the user. User id = {1}",
email,
opennebula_user
)
return opennebula_user return opennebula_user
#TODO: Replace with logger
except ConnectionRefusedError: except ConnectionRefusedError:
print('Could not connect to host: {host} via protocol {protocol}'.format( logger.info('Could not connect to host: {host} via protocol {protocol}'.format(
host=settings.OPENNEBULA_DOMAIN, host=settings.OPENNEBULA_DOMAIN,
protocol=settings.OPENNEBULA_PROTOCOL) protocol=settings.OPENNEBULA_PROTOCOL)
) )
@ -68,9 +70,8 @@ class OpenNebulaManager():
try: try:
user_pool = oca.UserPool(self.oneadmin_client) user_pool = oca.UserPool(self.oneadmin_client)
user_pool.info() user_pool.info()
#TODO: Replace with logger
except ConnectionRefusedError: except ConnectionRefusedError:
print('Could not connect to host: {host} via protocol {protocol}'.format( logger.info('Could not connect to host: {host} via protocol {protocol}'.format(
host=settings.OPENNEBULA_DOMAIN, host=settings.OPENNEBULA_DOMAIN,
protocol=settings.OPENNEBULA_PROTOCOL) protocol=settings.OPENNEBULA_PROTOCOL)
) )
@ -82,13 +83,12 @@ class OpenNebulaManager():
vm_pool = oca.VirtualMachinePool(self.client) vm_pool = oca.VirtualMachinePool(self.client)
vm_pool.info() vm_pool.info()
except AttributeError: except AttributeError:
print('Could not connect via client, using oneadmin instead') logger.info('Could not connect via client, using oneadmin instead')
vm_pool = oca.VirtualMachinePool(self.oneadmin_client) vm_pool = oca.VirtualMachinePool(self.oneadmin_client)
vm_pool.info(filter=-2) vm_pool.info(filter=-2)
#TODO: Replace with logger
except ConnectionRefusedError: except ConnectionRefusedError:
print('Could not connect to host: {host} via protocol {protocol}'.format( logger.info('Could not connect to host: {host} via protocol {protocol}'.format(
host=settings.OPENNEBULA_DOMAIN, host=settings.OPENNEBULA_DOMAIN,
protocol=settings.OPENNEBULA_PROTOCOL) protocol=settings.OPENNEBULA_PROTOCOL)
) )
@ -96,23 +96,49 @@ class OpenNebulaManager():
return vm_pool return vm_pool
def get_vms(self): def get_vms(self):
return self._get_vm_pool() try:
return self._get_vm_pool()
except ConnectionRefusedError:
return []
def get_vm(self, vm_id): def get_vm(self, vm_id):
vm_pool = self._get_vm_pool() vm_id = int(vm_id)
return vm_pool.get_by_id(int(vm_id)) try:
vm_pool = self._get_vm_pool()
return vm_pool.get_by_id(vm_id)
except:
return None
#TODO: get app with id def create_vm(self, template_id, image_id=None, ssh_key=None):
def create_vm(self, template_id, app_id=None, ssh_key=None): extra_template_formater = """<CONTEXT>
extra_template = "<CONTEXT><SSH_PUBLIC_KEY>{ssh_key}</SSH_PUBLIC_KEY></CONTEXT>".format( <SSH_PUBLIC_KEY>{ssh_key}</SSH_PUBLIC_KEY>
ssh_key=ssh_key </CONTEXT>
) <DISK>
vm_id = self.oneadmin_client.call( <IMAGE_ID>{image_id}</IMAGE_ID>
oca.VmTemplate.METHODS['instantiate'], </DISK>
template_id, """
'',
False, template = self.get_template(template_id)
extra_template vm_id = template.instantiate(name ='', pending=False, extra_template='')
image = self.get_image(image_id)
image_name = "{image_name}{template_name}{vm_id}".format(
image_name=image.name,
template_name=template.name,
vm_id = vm_id,
)
image_id = image.clone(name=image_name)
self.oneadmin_client.call(
oca.VmTemplate.METHODS['update'],
vm_id,
extra_template_formater.format(
ssh_key=ssh_key,
image_id=image_id
),
# 0 = Replace / 1 = Merge
1,
) )
try: try:
self.oneadmin_client.call( self.oneadmin_client.call(
@ -122,7 +148,7 @@ class OpenNebulaManager():
self.opennebula_user.group_ids[0] self.opennebula_user.group_ids[0]
) )
except AttributeError: except AttributeError:
print('Could not change owner, opennebula_user is not set.') logger.info('Could not change owner for vm with id: {}.'.format(vm_id))
return vm_id return vm_id
def delete_vm(self, vm_id): def delete_vm(self, vm_id):
@ -137,16 +163,12 @@ class OpenNebulaManager():
vm_terminated = True vm_terminated = True
except socket.timeout as socket_err: except socket.timeout as socket_err:
logger.info("Socket timeout error: {0}".format(socket_err)) logger.info("Socket timeout error: {0}".format(socket_err))
print("Socket timeout error: {0}".format(socket_err))
except OpenNebulaException as opennebula_err: except OpenNebulaException as opennebula_err:
logger.info("OpenNebulaException error: {0}".format(opennebula_err)) logger.info("OpenNebulaException error: {0}".format(opennebula_err))
print("OpenNebulaException error: {0}".format(opennebula_err))
except OSError as os_err: except OSError as os_err:
logger.info("OSError : {0}".format(os_err)) logger.info("OSError : {0}".format(os_err))
print("OSError : {0}".format(os_err))
except ValueError as value_err: except ValueError as value_err:
logger.info("ValueError : {0}".format(value_err)) logger.info("ValueError : {0}".format(value_err))
print("ValueError : {0}".format(value_err))
return vm_terminated return vm_terminated
@ -156,7 +178,7 @@ class OpenNebulaManager():
template_pool.info() template_pool.info()
#TODO: Replace with logger #TODO: Replace with logger
except ConnectionRefusedError: except ConnectionRefusedError:
print('Could not connect to host: {host} via protocol {protocol}'.format( logger.info('Could not connect to host: {host} via protocol {protocol}'.format(
host=settings.OPENNEBULA_DOMAIN, host=settings.OPENNEBULA_DOMAIN,
protocol=settings.OPENNEBULA_PROTOCOL) protocol=settings.OPENNEBULA_PROTOCOL)
) )
@ -164,15 +186,23 @@ class OpenNebulaManager():
return template_pool return template_pool
def get_templates(self): def get_templates(self):
public_templates = [ try:
template public_templates = [
for template in self._get_template_pool() template
if 'public-' in template.name for template in self._get_template_pool()
] if 'public-' in template.name
return public_templates ]
return public_templates
except ConnectionRefusedError:
return []
def get_template(self, template_id): def get_template(self, template_id):
template_pool = self._get_template_pool() template_id = int(template_id)
return template_pool.get_by_id(template_id) try:
template_pool = self._get_template_pool()
return template_pool.get_by_id(template_id)
except:
return None
@ -226,3 +256,44 @@ class OpenNebulaManager():
def delete_template(self, template_id): def delete_template(self, template_id):
self.oneadmin_client.call(oca.VmTemplate.METHODS['delete'], template_id, False) self.oneadmin_client.call(oca.VmTemplate.METHODS['delete'], template_id, False)
def change_user_password(self, new_password):
self.oneadmin_client.call(
oca.User.METHODS['passwd'],
self.opennebula_user.id,
new_password
)
def _get_image_pool(self):
try:
image_pool = oca.ImagePool(self.oneadmin_client)
image_pool.info()
#TODO: Replace with logger
except ConnectionRefusedError:
logger.info('Could not connect to host: {host} via protocol {protocol}'.format(
host=settings.OPENNEBULA_DOMAIN,
protocol=settings.OPENNEBULA_PROTOCOL)
)
raise ConnectionRefusedError
return image_pool
def get_images(self):
try:
public_images = [
image
for image in self._get_image_pool()
if 'public-' in image.name
]
return public_images
except ConnectionRefusedError:
return []
pass
def get_image(self, image_id):
image_id = int(image_id)
try:
image_pool = self._get_image_pool()
return image_pool.get_by_id(image_id)
except:
return None

View file

@ -31,7 +31,7 @@ class VirtualMachineTemplateSerializer(serializers.Serializer):
core_price = template.pop('cpu_cost') core_price = template.pop('cpu_cost')
memory_price = template.pop('memory_cost') memory_price = template.pop('memory_cost')
disk_size_price = template.pop('disk_cost') disk_size_price = template.pop('disk_cost')
manager = OpenNebulaManager(create_user = False) manager = OpenNebulaManager()
try: try:
opennebula_id = manager.create_template(name=name, cores=cores, opennebula_id = manager.create_template(name=name, cores=cores,
@ -92,7 +92,7 @@ class VirtualMachineSerializer(serializers.Serializer):
try: try:
manager = OpenNebulaManager(email=owner.email, manager = OpenNebulaManager(email=owner.email,
password=owner.password, password=owner.password,
create_user = True) )
opennebula_id = manager.create_vm(template_id) opennebula_id = manager.create_vm(template_id)
except OpenNebulaException as err: except OpenNebulaException as err:
raise serializers.ValidationError("OpenNebulaException occured. {0}".format(err)) raise serializers.ValidationError("OpenNebulaException occured. {0}".format(err))
@ -117,3 +117,8 @@ class VirtualMachineSerializer(serializers.Serializer):
price += int(disk.size)/1024 * float(template.disk_cost) price += int(disk.size)/1024 * float(template.disk_cost)
return price return price
class ImageSerializer(serializers.Serializer):
"""Serializer to map the image instance into JSON format."""
id = serializers.IntegerField(read_only=True)
name = serializers.CharField()

View file

@ -47,8 +47,7 @@ class VmCreateView(generics.ListCreateAPIView):
def get_queryset(self): def get_queryset(self):
owner = self.request.user owner = self.request.user
manager = OpenNebulaManager(email=owner.email, manager = OpenNebulaManager(email=owner.email,
password=owner.password, password=owner.password)
create_user=True)
return manager.get_vms() return manager.get_vms()
def perform_create(self, serializer): def perform_create(self, serializer):
@ -64,21 +63,18 @@ class VmDetailsView(generics.RetrieveUpdateDestroyAPIView):
def get_queryset(self): def get_queryset(self):
owner = self.request.user owner = self.request.user
manager = OpenNebulaManager(email=owner.email, manager = OpenNebulaManager(email=owner.email,
password=owner.password, password=owner.password)
create_user=True)
return manager.get_vms() return manager.get_vms()
def get_object(self): def get_object(self):
owner = self.request.user owner = self.request.user
manager = OpenNebulaManager(email=owner.email, manager = OpenNebulaManager(email=owner.email,
password=owner.password, password=owner.password)
create_user=True)
return manager.get_vm(self.kwargs.get('pk')) return manager.get_vm(self.kwargs.get('pk'))
def perform_destroy(self, instance): def perform_destroy(self, instance):
owner = self.request.user owner = self.request.user
manager = OpenNebulaManager(email=owner.email, manager = OpenNebulaManager(email=owner.email,
password=owner.password, password=owner.password)
create_user = True)
manager.delete_vm(instance.id) manager.delete_vm(instance.id)