From 6d4e9d8a83ab5a87b1c09e56464eb213f3cc9244 Mon Sep 17 00:00:00 2001 From: "M.Ravi" Date: Sun, 7 May 2017 05:31:39 +0530 Subject: [PATCH 1/6] Refactored code to introduce different VM templates --- hosting/opennebula_functions.py | 58 ++++++++++++++++++++++++ hosting/templates/hosting/managevms.html | 10 ++-- 2 files changed, 61 insertions(+), 7 deletions(-) diff --git a/hosting/opennebula_functions.py b/hosting/opennebula_functions.py index f71d7249..7759096f 100644 --- a/hosting/opennebula_functions.py +++ b/hosting/opennebula_functions.py @@ -14,6 +14,7 @@ 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__) @@ -84,6 +85,7 @@ class HostingManageVMAdmin(admin.ModelAdmin): # 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) @@ -232,6 +234,62 @@ class HostingManageVMAdmin(admin.ModelAdmin): "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 ManageVMView(View): + template_name = "hosting/managevms.html" + context_object_name = "managevms" + model = HostingManageVMAdmin + + def get(self, *args, **kwargs): + form = HostingManageVMsForm() + context = { + 'vms': model.get_vm_pool(), + 'form': form, + } + return TemplateResponse(request, template_name, context) + + + +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(): diff --git a/hosting/templates/hosting/managevms.html b/hosting/templates/hosting/managevms.html index d1b76ac2..54270316 100644 --- a/hosting/templates/hosting/managevms.html +++ b/hosting/templates/hosting/managevms.html @@ -2,13 +2,9 @@ {% block content %}
- {% csrf_token %} - - + {% csrf_token %} + {{ form }} +
{% if vms %}
From 1ebc3b8be403e97beadfa1347751e4658da5f40e Mon Sep 17 00:00:00 2001 From: Levi Date: Sun, 7 May 2017 17:46:03 -0500 Subject: [PATCH 2/6] testing --- hosting/opennebula_functions.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hosting/opennebula_functions.py b/hosting/opennebula_functions.py index 7657b457..ef12a9c1 100644 --- a/hosting/opennebula_functions.py +++ b/hosting/opennebula_functions.py @@ -38,6 +38,7 @@ class HostingManageVMAdmin(admin.ModelAdmin): # Function to initialize opennebula client based on the logged in # user def init_opennebula_client(self, request): + import pdb;pdb.set_trace() if self.oneadmin_client is None: self.oneadmin_client = oca.Client("{0}:{1}".format(settings.OPENNEBULA_USERNAME, settings.OPENNEBULA_PASSWORD), @@ -58,7 +59,7 @@ class HostingManageVMAdmin(admin.ModelAdmin): self.create_opennebula_user(request) if self.client is None: opennebula_user = request.user.email - opennebula_user_password = get_random_password() + 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, From 233642a6b12c3af5c6bb9c4e2b5b96f3fc5e5312 Mon Sep 17 00:00:00 2001 From: Levi Date: Sun, 7 May 2017 17:47:41 -0500 Subject: [PATCH 3/6] removed pdb --- hosting/opennebula_functions.py | 1 - 1 file changed, 1 deletion(-) diff --git a/hosting/opennebula_functions.py b/hosting/opennebula_functions.py index ef12a9c1..93919a29 100644 --- a/hosting/opennebula_functions.py +++ b/hosting/opennebula_functions.py @@ -38,7 +38,6 @@ class HostingManageVMAdmin(admin.ModelAdmin): # Function to initialize opennebula client based on the logged in # user def init_opennebula_client(self, request): - import pdb;pdb.set_trace() if self.oneadmin_client is None: self.oneadmin_client = oca.Client("{0}:{1}".format(settings.OPENNEBULA_USERNAME, settings.OPENNEBULA_PASSWORD), From d72c1c810d3db8d7e2cfef8654cb894f5ff05a1a Mon Sep 17 00:00:00 2001 From: Levi Date: Sun, 7 May 2017 18:57:44 -0500 Subject: [PATCH 4/6] added get vms --- hosting/models.py | 58 +++++++++++++++++++++++++++++++++++++++++++++++ hosting/views.py | 5 ++-- 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/hosting/models.py b/hosting/models.py index 1232dda3..8a9daaa1 100644 --- a/hosting/models.py +++ b/hosting/models.py @@ -1,9 +1,12 @@ import os +import oca from django.db import models from django.utils.translation import ugettext_lazy as _ from django.utils.functional import cached_property +from django.conf import settings + from Crypto.PublicKey import RSA from stored_messages.settings import stored_messages_settings @@ -168,6 +171,61 @@ class VirtualMachinePlan(AssignPermissionsMixin, models.Model): self.status = self.CANCELED_STATUS self.save(update_fields=['status']) + @classmethod + def get_vms(self, email): + # Get User + user_email = email + + # Connect to open nebula server + # TODO: handle potential connection error + 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 + )) + # 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(user_email).id + + # Get vm_pool for given user_id + vm_pool = oca.VirtualMachinePool(client) + vm_pool.info(filter=user_id) + + # Reset total price + self.total_price = 0 + vms = [] + # Add vm in vm_pool to context + for vm in vm_pool: + 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 = {} + vm['name'] = name + vm['price'] = price + vm['disk_size'] = disk_size + vm['cores'] = cores + vm['memory'] = memory + vms.append(vm) + # self.total_price += price + # self.save() + return vms + class HostingOrder(AssignPermissionsMixin, models.Model): diff --git a/hosting/views.py b/hosting/views.py index e0f96426..6104f7e8 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -412,8 +412,9 @@ class VirtualMachinesPlanListView(LoginRequiredMixin, ListView): ordering = '-id' def get_queryset(self): - hosting_admin = HostingManageVMAdmin.__new__(HostingManageVMAdmin) - print(hosting_admin.show_vms_view(self.request)) + # hosting_admin = HostingManageVMAdmin.__new__(HostingManageVMAdmin) + # print(hosting_admin.show_vms_view(self.request)) + print(VirtualMachinePlan.get_vms(self.request.user.email)) user = self.request.user self.queryset = VirtualMachinePlan.objects.active(user) return super(VirtualMachinesPlanListView, self).get_queryset() From a1eea9162ed6e0c32737d226327d14d9b1c4cc1f Mon Sep 17 00:00:00 2001 From: "M.Ravi" Date: Mon, 8 May 2017 11:36:46 +0530 Subject: [PATCH 5/6] Added logger methods for print. --- hosting/opennebula_functions.py | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/hosting/opennebula_functions.py b/hosting/opennebula_functions.py index 7759096f..ed6444e4 100644 --- a/hosting/opennebula_functions.py +++ b/hosting/opennebula_functions.py @@ -48,9 +48,9 @@ class HostingManageVMAdmin(admin.ModelAdmin): port=settings.OPENNEBULA_PORT, endpoint=settings.OPENNEBULA_ENDPOINT )) - print("{0}:{1}".format(settings.OPENNEBULA_USERNAME, + logger.debug("{0}:{1}".format(settings.OPENNEBULA_USERNAME, settings.OPENNEBULA_PASSWORD)) - print("{protocol}://{domain}:{port}{endpoint}".format( + logger.debug("{protocol}://{domain}:{port}{endpoint}".format( protocol=settings.OPENNEBULA_PROTOCOL, domain=settings.OPENNEBULA_DOMAIN, port=settings.OPENNEBULA_PORT, @@ -59,6 +59,7 @@ class HostingManageVMAdmin(admin.ModelAdmin): 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 = get_random_password() self.client = oca.Client("{0}:{1}".format(opennebula_user, opennebula_user_password), "{protocol}://{domain}:{port}{endpoint}".format( @@ -226,8 +227,10 @@ class HostingManageVMAdmin(admin.ModelAdmin): 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: - user_id = self.oneadmin_client.call('user.allocate', request.user.email, get_random_password(), - 'dummy') + # 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, @@ -259,18 +262,6 @@ class HostingManageVMForm(forms.Form): # 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 ManageVMView(View): - template_name = "hosting/managevms.html" - context_object_name = "managevms" - model = HostingManageVMAdmin - - def get(self, *args, **kwargs): - form = HostingManageVMsForm() - context = { - 'vms': model.get_vm_pool(), - 'form': form, - } - return TemplateResponse(request, template_name, context) From 621376c5b4eb43aa970cf9335e94b9cb294c7ce1 Mon Sep 17 00:00:00 2001 From: "M.Ravi" Date: Mon, 8 May 2017 16:23:03 +0530 Subject: [PATCH 6/6] Added functionality to create opennebula user if it does not exist --- hosting/models.py | 42 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/hosting/models.py b/hosting/models.py index 8a9daaa1..35a95331 100644 --- a/hosting/models.py +++ b/hosting/models.py @@ -14,7 +14,10 @@ from membership.models import StripeCustomer, CustomUser from utils.models import BillingAddress from utils.mixins import AssignPermissionsMixin from .managers import VMPlansManager +from oca.pool import WrongNameError +import logging +logger = logging.getLogger(__name__) class VirtualMachineType(models.Model): @@ -178,7 +181,7 @@ class VirtualMachinePlan(AssignPermissionsMixin, models.Model): # Connect to open nebula server # TODO: handle potential connection error - client = oca.Client("{0}:{1}".format( + oneadmin_client = oca.Client("{0}:{1}".format( settings.OPENNEBULA_USERNAME, settings.OPENNEBULA_PASSWORD), "{protocol}://{domain}:{port}{endpoint}".format( @@ -188,10 +191,32 @@ class VirtualMachinePlan(AssignPermissionsMixin, models.Model): endpoint=settings.OPENNEBULA_ENDPOINT )) # Get open nebula user id for given email - user_pool = oca.UserPool(client) + user_pool = oca.UserPool(oneadmin_client) user_pool.info() - # TODO: handle potential name error - user_id = user_pool.get_by_name(user_email).id + try: + user = user_pool.get_by_name(user_email) + user_id = user.id + logger.debug("User {user} exists.".format(user=user_email)) + except WrongNameError as wrong_name_err: + # User does not exist. So, we create this user in OpenNebula + password = get_user_opennebula_password() + # We use the core authenticator driver for the new user + user_id = oneadmin_client.call('user.allocate', + user_email, password, + 'core') + logger.debug("User {0} does not exist. Created the user. User id = {1}", user_email, user_id) + + # We should now have an OpenNebula user corresponding to user_email + # It is now ok to now perform opennebula functions with this user's client + client = oca.Client("{0}:{1}".format( + user_email, + get_user_opennebula_password()), + "{protocol}://{domain}:{port}{endpoint}".format( + protocol=settings.OPENNEBULA_PROTOCOL, + domain=settings.OPENNEBULA_DOMAIN, + port=settings.OPENNEBULA_PORT, + endpoint=settings.OPENNEBULA_ENDPOINT + )) # Get vm_pool for given user_id vm_pool = oca.VirtualMachinePool(client) @@ -308,3 +333,12 @@ class ManageVM(models.Model): class Meta: managed = False + +def get_user_opennebula_password(): + ''' + TODO: Implement the way we obtain the user's opennebula password + ''' + pw = os.environ.get('OPENNEBULA_USER_PW') + if pw is None: + raise Exception("Define OPENNEBULA_USER_PW env variable") + return pw