diff --git a/dynamicweb/settings/base.py b/dynamicweb/settings/base.py index 2f272e1a..c6c71ad5 100644 --- a/dynamicweb/settings/base.py +++ b/dynamicweb/settings/base.py @@ -6,10 +6,8 @@ Copyright 2015 ungleich. # Build paths inside the project like this: os.path.join(BASE_DIR, ...) import os -from django.utils.translation import ugettext_lazy as _ - -# dotenv import dotenv +from django.utils.translation import ugettext_lazy as _ gettext = lambda s: s @@ -492,10 +490,7 @@ OPENNEBULA_PASSWORD = 'opennebula' OPENNEBULA_PROTOCOL = 'http' # The ip address or the domain name of the opennebula infrastructure -# OPENNEBULA_DOMAIN = '192.168.182.173' -# OPENNEBULA_DOMAIN = '192.168.122.225' -# OPENNEBULA_DOMAIN = '192.168.182.176' -OPENNEBULA_DOMAIN = '192.168.42.35' +OPENNEBULA_DOMAIN = '192.168.182.124' # The port to connect in order to send an xmlrpc request. The default # port is 2633 @@ -503,4 +498,4 @@ OPENNEBULA_PORT = '2633' # The endpoint to which the XML RPC request needs to be sent to. The # default value is /RPC2 -OPENNEBULA_ENDPOINT = '/RPC2' \ No newline at end of file +OPENNEBULA_ENDPOINT = '/RPC2' diff --git a/hosting/admin.py b/hosting/admin.py index 1019054b..1172112e 100644 --- a/hosting/admin.py +++ b/hosting/admin.py @@ -1,13 +1,12 @@ from django.contrib import admin -from django.utils.html import format_html from django.core.urlresolvers import reverse +from django.utils.html import format_html from utils.mailer import BaseEmail -from django.contrib.auth.signals import user_logged_in - from .forms import HostingOrderAdminForm from .models import VirtualMachineType, VirtualMachinePlan, HostingOrder, ManageVM -from .opennebula_functions import HostingManageVMAdmin, user_logged_in_callback +from .opennebula_functions import HostingManageVMAdmin + class HostingOrderAdmin(admin.ModelAdmin): # fields = ('slug', 'imdb_link', 'start', 'finish', 'added_by') @@ -97,6 +96,4 @@ class VirtualMachinePlanAdmin(admin.ModelAdmin): admin.site.register(HostingOrder, HostingOrderAdmin) admin.site.register(VirtualMachineType) admin.site.register(VirtualMachinePlan, VirtualMachinePlanAdmin) - -user_logged_in.connect(user_logged_in_callback) -admin.site.register(ManageVM, HostingManageVMAdmin) \ No newline at end of file +admin.site.register(ManageVM, HostingManageVMAdmin) diff --git a/hosting/models.py b/hosting/models.py index bdcb673a..c24d45d7 100644 --- a/hosting/models.py +++ b/hosting/models.py @@ -1,15 +1,13 @@ import os -from django.db import models -from django.utils.translation import ugettext_lazy as _ -from django.utils.functional import cached_property - from Crypto.PublicKey import RSA +from django.db import models +from django.utils.functional import cached_property from stored_messages.settings import stored_messages_settings from membership.models import StripeCustomer -from utils.models import BillingAddress from utils.mixins import AssignPermissionsMixin +from utils.models import BillingAddress from .managers import VMPlansManager @@ -225,7 +223,6 @@ class HostingOrder(AssignPermissionsMixin, models.Model): class ManageVM(models.Model): - #name = models.TextField(blank=True) def has_add_permission(self, request): return False diff --git a/hosting/opennebula_functions.py b/hosting/opennebula_functions.py index 59df6173..5707f128 100644 --- a/hosting/opennebula_functions.py +++ b/hosting/opennebula_functions.py @@ -1,16 +1,18 @@ import logging +import random import socket import string import oca -import random 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 # Get an instance of a logger logger = logging.getLogger(__name__) @@ -18,6 +20,7 @@ logger = logging.getLogger(__name__) class HostingManageVMAdmin(admin.ModelAdmin): client = None + oneadmin_client = None def get_urls(self): urls = super().get_urls() @@ -34,8 +37,27 @@ class HostingManageVMAdmin(admin.ModelAdmin): # Function to initialize opennebula client based on the logged in # user - def init_opennebula_client(self, opennebula_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 + )) + print("{0}:{1}".format(settings.OPENNEBULA_USERNAME, + settings.OPENNEBULA_PASSWORD)) + print("{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 opennebula_user_password = get_random_password() self.client = oca.Client("{0}:{1}".format(opennebula_user, opennebula_user_password), "{protocol}://{domain}:{port}{endpoint}".format( @@ -49,26 +71,24 @@ class HostingManageVMAdmin(admin.ModelAdmin): def show_vms(self, request): vm_pool = None try: - self.init_opennebula_client(request.user) + 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: - messages.add_message(request, messages.ERROR, "OpenNebulaException occurred.") + 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, str("OS error: {0}".format(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, ) - return TemplateResponse(request, "hosting/managevms.html", context) # Creating VM by using method allocate(client, template) def create_vm(self, request): - message = '' # 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') @@ -82,24 +102,13 @@ class HostingManageVMAdmin(admin.ModelAdmin): # 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 = """ - - - {memory} - - - {vcpu} - - - {cpu} - + vm_string_formatter = """ + {memory} + {vcpu} + {cpu} - - {disk_type} - - - {size} - + {disk_type} + {size} """ @@ -110,113 +119,110 @@ class HostingManageVMAdmin(admin.ModelAdmin): cpu=0.1 * vm_template_int, disk_type='fs', size=10000 * vm_template_int)) - message = "Created with id = " + str(vm_id) + 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.") + _("Please select an appropriate value for vm template.")) except socket.timeout as socket_err: - messages.add_message(request, messages.ERROR, "Socket timeout error.") + 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.") + 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, str("OS error: {0}".format(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.") + _("Please select an appropriate value for vm template.")) logger.error("ValueError : {0}".format(value_err)) return redirect('admin:showvms') - # Retrives virtual machine pool information - def get_vms(self): - vm_pool = oca.VirtualMachinePool(self.client) - vm_pool.info() - return vm_pool - # Delete VM from the pool and DB by using method finalize() def delete_vm(self, request, vmid): - # get the desired vm from the pool 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 == -1: - messages.add_message(request, messages.ERROR, "Did not find a vm with id = " + str(vm_id)) + if vm is None: + messages.add_message(request, messages.ERROR, _("Did not find a vm with id = {0}".format(vm_id))) else: - print("Deleting vm_id = " + str(vm_id) + " state = " + vm.str_state) + 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 " + vm.str_state + " state vm with id = " + str(vm_id)) + _("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 " + vm.str_state + " state vm with id = " + str( - vm_id)) + _("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 == -1: - messages.add_message(request, messages.ERROR, "Did not find a vm with id = " + str(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 = " + str(vm_id)) + 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 == -1: - messages.add_message(request, messages.ERROR, "Did not find a vm with id = " + str(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 = " + str(vm_id)) + 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): - vms = self.get_vms() - for vm in vms: - if vm.id == vmid: - return vm - return -1 + vm_pool = self.get_vm_pool() + return vm_pool.get_by_id(vmid) - -# callback for creating opennebula users on user login -def user_logged_in_callback(sender, request, user, **kwargs): - client = oca.Client(settings.OPENNEBULA_USERNAME + ':' + settings.OPENNEBULA_PASSWORD, - settings.OPENNEBULA_PROTOCOL + '://' + settings.OPENNEBULA_DOMAIN + ':' + settings.OPENNEBULA_PORT + settings.OPENNEBULA_ENDPOINT) - # 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. - if find_opennebula_user_by_name(str(user.email), client) == -1: - user_id = client.call('user.allocate', str(user.email), get_random_password(), 'dummy') - print("User " + str(user.email) + " does not exist. Created the user. User id = " + str(user_id)) - - -# Finds if an OpenNebula user with user_name exists. Returns the -# OpenNebula user if it exists, -1 otherwise. -def find_opennebula_user_by_name(user_name, client): - pool = oca.UserPool(client) - pool.info() - for user in pool: - if user.name == user_name: - return user - return -1 + 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: + user_id = self.oneadmin_client.call('user.allocate', request.user.email, get_random_password(), + 'dummy') + 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)) # Returns random password that is needed by OpenNebula