diff --git a/hosting/models.py b/hosting/models.py index fe40ff3f..bceaaacf 100644 --- a/hosting/models.py +++ b/hosting/models.py @@ -176,13 +176,30 @@ class VirtualMachinePlan(AssignPermissionsMixin, models.Model): self.save(update_fields=['status']) @classmethod - def get_vm(self, email, vm_id): + def create_opennebula_vm(self, user, specs): + + # Init opennebula manager using given user + opennebula_client = OpenNebulaManager( + user.email, + user.password[0:20], + create_user=True + ) + + # Create a vm in opennebula using given specs + vm = opennebula_client.create_vm(specs) + return vm + + @classmethod + def get_vm(self, user, vm_id): # Get opennebula client - opennebula_client = OpenNebulaManager() + opennebula_client = OpenNebulaManager( + email=user.email, + password=user.password[:20], + ) # Get vm given the id vm = opennebula_client.get_vm( - email, + user.email, vm_id ) @@ -192,13 +209,16 @@ class VirtualMachinePlan(AssignPermissionsMixin, models.Model): return vm_data @classmethod - def get_vms(self, email): + def get_vms(self, user): # Get opennebula client - opennebula_client = OpenNebulaManager() + opennebula_client = OpenNebulaManager( + email=user.email, + password=user.password[:20], + ) # Get vm pool - vm_pool = opennebula_client.get_vms(email) + vm_pool = opennebula_client.get_vms(user.email) # Reset total price self.total_price = 0 diff --git a/hosting/opennebula_functions.py b/hosting/opennebula_functions.py index b0d0e13b..1d241d59 100644 --- a/hosting/opennebula_functions.py +++ b/hosting/opennebula_functions.py @@ -35,10 +35,34 @@ class OpenNebulaManager: '11': 'CLONING_FAILURE', } - def __init__(self): - self.client = oca.Client("{0}:{1}".format( + def __init__(self, email=None, password=None, create_user=True): + + # Get oneadmin client + self.oneadmin_client = self._get_opennebula_client( settings.OPENNEBULA_USERNAME, - settings.OPENNEBULA_PASSWORD), + settings.OPENNEBULA_PASSWORD + ) + + if not create_user: + return + + # 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, @@ -46,6 +70,25 @@ class OpenNebulaManager: 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 + return oca.User.allocate(self.oneadmin_client, email, password) + logger.debug( + "User {0} does not exist. Created the user. User id = {1}", + email, + 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)) @@ -77,6 +120,56 @@ class OpenNebulaManager: return vm_data + 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 = """ + {memory} + {vcpu} + {cpu} + + {disk_type} + {size} + + + """ + 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') + ) + ) + + self.oneadmin_client.call( + oca.VirtualMachine.METHODS['chown'], + vm_id, + self.opennebula_user.id, + self.opennebula_user.group_ids[0] + ) + # oca.VirtualMachine.chown( + # vm_id, + + # ) + + 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 get_vm(self, email, vm_id): # Get vm's vms = self.get_vms(email) @@ -85,7 +178,7 @@ class OpenNebulaManager: return vms.get_by_id(int(vm_id)) def get_vms(self, email): - client = self.client + client = self.oneadmin_client # Get open nebula user id for given email user_pool = oca.UserPool(client) @@ -99,7 +192,7 @@ class OpenNebulaManager: vm_pool.info() # TODO: this is just to test with oneadmin user, remove this - user_id = 0 + # user_id = 0 vm_pool.info(filter=user_id) return vm_pool diff --git a/hosting/views.py b/hosting/views.py index 913cb794..8989732f 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -27,7 +27,7 @@ from utils.mailer import BaseEmail from .models import VirtualMachineType, VirtualMachinePlan, HostingOrder, UserHostingKey from .forms import HostingUserSignupForm, HostingUserLoginForm, UserHostingKeyForm from .mixins import ProcessVMSelectionMixin -from .opennebula_functions import HostingManageVMAdmin +from .opennebula_functions import HostingManageVMAdmin, OpenNebulaManager class DjangoHostingView(ProcessVMSelectionMixin, View): @@ -340,19 +340,14 @@ class PaymentVMView(LoginRequiredMixin, FormView): # If the Stripe payment was successed, set order status approved order.set_approved() - # Create VM using oppenebula functions - # _request = namedtuple('request', 'POST user') - # _request.user = request.user - # user = namedtuple('user', 'email') - # email - # _request.POST = { - # 'vm_template': vm_template - # } + # Create a vm using logged user + oppennebula_vm_id = VirtualMachinePlan.create_opennebula_vm( + self.request.user, + specs + ) - hosting_admin = HostingManageVMAdmin.__new__(HostingManageVMAdmin) - hosting_admin.init_opennebula_client(request) - oppennebula_vm_id = hosting_admin.create_vm_view(vm_type.get_specs()) plan.oppenebula_id = oppennebula_vm_id + plan.save() # Send notification to ungleich as soon as VM has been booked context = { @@ -415,14 +410,14 @@ class VirtualMachinesPlanListView(LoginRequiredMixin, ListView): def get_context_data(self, **kwargs): context = super(VirtualMachinesPlanListView, self).get_context_data(**kwargs) context.update({ - 'vms_opennebula': VirtualMachinePlan.get_vms(self.request.user.email) + 'vms_opennebula': VirtualMachinePlan.get_vms(self.request.user) }) return context def get_queryset(self): # hosting_admin = HostingManageVMAdmin.__new__(HostingManageVMAdmin) # print(hosting_admin.show_vms_view(self.request)) - print(VirtualMachinePlan.get_vms(self.request.user.email)) + # print(VirtualMachinePlan.get_vms(self.request.user.)) user = self.request.user self.queryset = VirtualMachinePlan.objects.active(user) return super(VirtualMachinesPlanListView, self).get_queryset() @@ -502,10 +497,10 @@ class VirtualMachineView(PermissionRequiredMixin, LoginRequiredMixin, View): # return final_url def get(self, request, *args, **kwargs): - vm_id = self.kwargs.get('pk', 24) + vm_id = self.kwargs.get('pk') try: opennebula_vm = VirtualMachinePlan.get_vm( - self.request.user.email, + self.request.user, vm_id ) except Exception as error: