From cfaf2010642d18fef2edafdb4b70d71936b09acd Mon Sep 17 00:00:00 2001 From: Modulos Date: Sat, 13 May 2017 05:50:56 +0200 Subject: [PATCH 1/3] Handle ConnectionException, add change_user_password --- hosting/views.py | 18 ++++------ opennebula_api/models.py | 78 +++++++++++++++++++++++----------------- 2 files changed, 51 insertions(+), 45 deletions(-) diff --git a/hosting/views.py b/hosting/views.py index b292ce45..e09380ab 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -427,8 +427,7 @@ class PaymentVMView(LoginRequiredMixin, FormView): # Create OpenNebulaManager manager = OpenNebulaManager(email=owner.email, - password=owner.password, - create_user=True) + password=owner.password) template = manager.get_template(vm_template_id) # Get user ssh key @@ -509,8 +508,7 @@ class OrdersHostingDetailView(PermissionRequiredMixin, LoginRequiredMixin, Detai obj = self.get_object() owner = self.request.user manager = OpenNebulaManager(email=owner.email, - password=owner.password, - create_user=True) + password=owner.password) vm = manager.get_vm(obj.vm_id) context['vm'] = VirtualMachineSerializer(vm).data return context @@ -546,8 +544,7 @@ class VirtualMachinesPlanListView(LoginRequiredMixin, ListView): def get_queryset(self): owner = self.request.user manager = OpenNebulaManager(email=owner.email, - password=owner.password, - create_user=True) + password=owner.password) queryset = manager.get_vms() serializer = VirtualMachineSerializer(queryset, many=True) return serializer.data @@ -597,8 +594,7 @@ class VirtualMachineView(LoginRequiredMixin, View): vm = None manager = OpenNebulaManager( email=owner.email, - password=owner.password, - create_user=True + password=owner.password ) vm_id = self.kwargs.get('pk') try: @@ -628,8 +624,7 @@ class VirtualMachineView(LoginRequiredMixin, View): manager = OpenNebulaManager( email=owner.email, - password=owner.password, - create_user=True + password=owner.password ) terminated = manager.delete_vm( @@ -695,8 +690,7 @@ class HostingBillDetailView(PermissionRequiredMixin, LoginRequiredMixin, DetailV owner = self.request.user manager = OpenNebulaManager(email=owner.email, - password=owner.password, - create_user=True) + password=owner.password) # Get vms queryset = manager.get_vms() vms = VirtualMachineSerializer(queryset, many=True).data diff --git a/opennebula_api/models.py b/opennebula_api/models.py index 8c7743b4..d9c5b7cf 100644 --- a/opennebula_api/models.py +++ b/opennebula_api/models.py @@ -13,7 +13,7 @@ logger = logging.getLogger(__name__) class OpenNebulaManager(): """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 self.oneadmin_client = self._get_opennebula_client( @@ -21,21 +21,19 @@ class OpenNebulaManager(): settings.OPENNEBULA_PASSWORD ) - if not create_user or email is None: - 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: + try: + self.opennebula_user = self._get_or_create_user( + email, + password + ) + # If opennebula user was created/obtained, get his client self.client = self._get_opennebula_client( email, password ) + except: + pass def _get_opennebula_client(self, username, password): return oca.Client("{0}:{1}".format( @@ -56,10 +54,14 @@ class OpenNebulaManager(): except WrongNameError as wrong_name_err: 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 - #TODO: Replace with logger 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, protocol=settings.OPENNEBULA_PROTOCOL) ) @@ -68,9 +70,8 @@ class OpenNebulaManager(): try: user_pool = oca.UserPool(self.oneadmin_client) user_pool.info() - #TODO: Replace with logger 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, protocol=settings.OPENNEBULA_PROTOCOL) ) @@ -82,13 +83,12 @@ class OpenNebulaManager(): vm_pool = oca.VirtualMachinePool(self.client) vm_pool.info() 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.info(filter=-2) - #TODO: Replace with logger 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, protocol=settings.OPENNEBULA_PROTOCOL) ) @@ -96,11 +96,17 @@ class OpenNebulaManager(): return vm_pool def get_vms(self): - return self._get_vm_pool() + try: + return self._get_vm_pool() + except ConnectionRefusedError: + return [] def get_vm(self, vm_id): - vm_pool = self._get_vm_pool() - return vm_pool.get_by_id(int(vm_id)) + try: + vm_pool = self._get_vm_pool() + return vm_pool.get_by_id(int(vm_id)) + except: + return None #TODO: get app with id def create_vm(self, template_id, app_id=None, ssh_key=None): @@ -122,7 +128,7 @@ class OpenNebulaManager(): self.opennebula_user.group_ids[0] ) 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 def delete_vm(self, vm_id): @@ -137,16 +143,12 @@ class OpenNebulaManager(): vm_terminated = True except socket.timeout as socket_err: logger.info("Socket timeout error: {0}".format(socket_err)) - print("Socket timeout error: {0}".format(socket_err)) except OpenNebulaException as opennebula_err: logger.info("OpenNebulaException error: {0}".format(opennebula_err)) - print("OpenNebulaException error: {0}".format(opennebula_err)) except OSError as os_err: logger.info("OSError : {0}".format(os_err)) - print("OSError : {0}".format(os_err)) except ValueError as value_err: logger.info("ValueError : {0}".format(value_err)) - print("ValueError : {0}".format(value_err)) return vm_terminated @@ -156,7 +158,7 @@ class OpenNebulaManager(): template_pool.info() #TODO: Replace with logger 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, protocol=settings.OPENNEBULA_PROTOCOL) ) @@ -164,12 +166,16 @@ class OpenNebulaManager(): return template_pool def get_templates(self): - public_templates = [ - template - for template in self._get_template_pool() - if 'public-' in template.name - ] - return public_templates + try: + public_templates = [ + template + for template in self._get_template_pool() + if 'public-' in template.name + ] + return public_templates + except ConnectionRefusedError: + return [] + def get_template(self, template_id): template_pool = self._get_template_pool() return template_pool.get_by_id(template_id) @@ -226,3 +232,9 @@ class OpenNebulaManager(): def delete_template(self, template_id): 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 + ) From c816d280ee0743881ff6ac113474be816d2460ff Mon Sep 17 00:00:00 2001 From: Modulos Date: Sat, 13 May 2017 05:52:27 +0200 Subject: [PATCH 2/3] Remove opennebula_functions.py --- hosting/opennebula_functions.py | 567 -------------------------------- 1 file changed, 567 deletions(-) delete mode 100644 hosting/opennebula_functions.py diff --git a/hosting/opennebula_functions.py b/hosting/opennebula_functions.py deleted file mode 100644 index aca5424d..00000000 --- a/hosting/opennebula_functions.py +++ /dev/null @@ -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 = """ - {memory} - {vcpu} - {cpu} - - {disk_type} - {size} - - - {ssh_key} - - - """ - 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\d+)/$', self.admin_site.admin_view(self.delete_vm, cacheable=True), - name='deletevm'), - url(r'^stop_vm/(?P\d+)/$', self.admin_site.admin_view(self.stop_vm, cacheable=True), name='stopvm'), - url(r'^start_vm/(?P\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 = """ - {memory} - {vcpu} - {cpu} - - {disk_type} - {size} - - - """ - 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 = """ - - - {ssh_key} - - - {memory} - {vcpu} - {cpu} - - {disk_type} - {size} - {dev_prefix} - - - """ - 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)) From 75d93b2aadf478dcd6555088aa6e4cdbee323723 Mon Sep 17 00:00:00 2001 From: Modulos Date: Sat, 13 May 2017 06:59:57 +0200 Subject: [PATCH 3/3] Add images as configuration --- hosting/models.py | 3 - .../hosting/create_virtual_machine.html | 10 +-- hosting/views.py | 33 ++++--- opennebula_api/models.py | 87 ++++++++++++++++--- opennebula_api/serializers.py | 9 +- opennebula_api/views.py | 12 +-- 6 files changed, 108 insertions(+), 46 deletions(-) diff --git a/hosting/models.py b/hosting/models.py index 188f1733..6be6c246 100644 --- a/hosting/models.py +++ b/hosting/models.py @@ -7,7 +7,6 @@ import oca from django.db import models from django.utils.translation import ugettext_lazy as _ from django.utils.functional import cached_property -from hosting.opennebula_functions import OpenNebulaManager from django.conf import settings @@ -18,8 +17,6 @@ from membership.models import StripeCustomer, CustomUser from utils.models import BillingAddress from utils.mixins import AssignPermissionsMixin from .managers import VMPlansManager -from oca.exceptions import OpenNebulaException -from oca.pool import WrongNameError logger = logging.getLogger(__name__) diff --git a/hosting/templates/hosting/create_virtual_machine.html b/hosting/templates/hosting/create_virtual_machine.html index 3a68421e..405b2988 100644 --- a/hosting/templates/hosting/create_virtual_machine.html +++ b/hosting/templates/hosting/create_virtual_machine.html @@ -24,16 +24,16 @@ {% endfor %} - +
diff --git a/hosting/views.py b/hosting/views.py index e09380ab..0025a40d 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -31,7 +31,9 @@ from .mixins import ProcessVMSelectionMixin from opennebula_api.models import OpenNebulaManager from opennebula_api.serializers import VirtualMachineSerializer,\ - VirtualMachineTemplateSerializer + VirtualMachineTemplateSerializer,\ + ImageSerializer + from oca.exceptions import OpenNebulaException from oca.pool import WrongNameError @@ -392,6 +394,7 @@ class PaymentVMView(LoginRequiredMixin, FormView): specifications = request.session.get('template') vm_template_id = specifications.get('id', 1) + vm_image_id = request.session.get('image').get('id', 1) final_price = specifications.get('price', 1) @@ -428,8 +431,6 @@ class PaymentVMView(LoginRequiredMixin, FormView): # Create OpenNebulaManager manager = OpenNebulaManager(email=owner.email, password=owner.password) - template = manager.get_template(vm_template_id) - # Get user ssh key try: user_key = UserHostingKey.objects.get( @@ -441,8 +442,9 @@ class PaymentVMView(LoginRequiredMixin, FormView): # Create a vm using logged user vm_id = manager.create_vm( - vm_template_id, - ssh_key=user_key.public_key + template_id=vm_template_id, + ssh_key=user_key.public_key, + image_id=vm_image_id, ) # Create a Hosting Order @@ -567,21 +569,24 @@ class CreateVirtualMachinesView(LoginRequiredMixin, View): ) return HttpResponseRedirect(reverse('hosting:key_pair')) - #TODO: Replace with OpenNebulaManager.get_apps - templates = OpenNebulaManager().get_templates() - data = VirtualMachineTemplateSerializer(templates, many=True).data + manager = OpenNebulaManager() + templates = manager.get_templates() + images = manager.get_images() context = { - 'templates': data, + 'templates': VirtualMachineTemplateSerializer(templates, many=True).data, + 'images' : ImageSerializer(images, many=True).data } - # context = {} return render(request, self.template_name, context) def post(self, request): - template_id = int(request.POST.get('vm_template_id')) - template = OpenNebulaManager().get_template(template_id) - data = VirtualMachineTemplateSerializer(template).data - request.session['template'] = data + manager = OpenNebulaManager() + template_id = request.POST.get('vm_template_id') + template = manager.get_template(template_id) + 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')) diff --git a/opennebula_api/models.py b/opennebula_api/models.py index d9c5b7cf..f543d0ec 100644 --- a/opennebula_api/models.py +++ b/opennebula_api/models.py @@ -102,23 +102,43 @@ class OpenNebulaManager(): return [] def get_vm(self, vm_id): + vm_id = int(vm_id) try: vm_pool = self._get_vm_pool() - return vm_pool.get_by_id(int(vm_id)) + return vm_pool.get_by_id(vm_id) except: return None - #TODO: get app with id - def create_vm(self, template_id, app_id=None, ssh_key=None): - extra_template = "{ssh_key}".format( - ssh_key=ssh_key - ) - vm_id = self.oneadmin_client.call( - oca.VmTemplate.METHODS['instantiate'], - template_id, - '', - False, - extra_template + def create_vm(self, template_id, image_id=None, ssh_key=None): + extra_template_formater = """ + {ssh_key} + + + {image_id} + + """ + + template = self.get_template(template_id) + 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: self.oneadmin_client.call( @@ -177,8 +197,12 @@ class OpenNebulaManager(): return [] def get_template(self, template_id): - template_pool = self._get_template_pool() - return template_pool.get_by_id(template_id) + template_id = int(template_id) + try: + template_pool = self._get_template_pool() + return template_pool.get_by_id(template_id) + except: + return None @@ -238,3 +262,38 @@ class OpenNebulaManager(): 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 + diff --git a/opennebula_api/serializers.py b/opennebula_api/serializers.py index b73682e6..86da2f0b 100644 --- a/opennebula_api/serializers.py +++ b/opennebula_api/serializers.py @@ -31,7 +31,7 @@ class VirtualMachineTemplateSerializer(serializers.Serializer): core_price = template.pop('cpu_cost') memory_price = template.pop('memory_cost') disk_size_price = template.pop('disk_cost') - manager = OpenNebulaManager(create_user = False) + manager = OpenNebulaManager() try: opennebula_id = manager.create_template(name=name, cores=cores, @@ -92,7 +92,7 @@ class VirtualMachineSerializer(serializers.Serializer): try: manager = OpenNebulaManager(email=owner.email, password=owner.password, - create_user = True) + ) opennebula_id = manager.create_vm(template_id) except OpenNebulaException as 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) return price +class ImageSerializer(serializers.Serializer): + """Serializer to map the image instance into JSON format.""" + id = serializers.IntegerField(read_only=True) + name = serializers.CharField() + diff --git a/opennebula_api/views.py b/opennebula_api/views.py index 20a28968..170c9716 100644 --- a/opennebula_api/views.py +++ b/opennebula_api/views.py @@ -47,8 +47,7 @@ class VmCreateView(generics.ListCreateAPIView): def get_queryset(self): owner = self.request.user manager = OpenNebulaManager(email=owner.email, - password=owner.password, - create_user=True) + password=owner.password) return manager.get_vms() def perform_create(self, serializer): @@ -64,21 +63,18 @@ class VmDetailsView(generics.RetrieveUpdateDestroyAPIView): def get_queryset(self): owner = self.request.user manager = OpenNebulaManager(email=owner.email, - password=owner.password, - create_user=True) + password=owner.password) return manager.get_vms() def get_object(self): owner = self.request.user manager = OpenNebulaManager(email=owner.email, - password=owner.password, - create_user=True) + password=owner.password) return manager.get_vm(self.kwargs.get('pk')) def perform_destroy(self, instance): owner = self.request.user manager = OpenNebulaManager(email=owner.email, - password=owner.password, - create_user = True) + password=owner.password) manager.delete_vm(instance.id)