Merge branch 'opennebula-integration' into vm_bill
This commit is contained in:
		
				commit
				
					
						3078536bd7
					
				
			
		
					 4 changed files with 150 additions and 14 deletions
				
			
		|  | @ -7,6 +7,8 @@ from django.utils.translation import ugettext_lazy as _ | ||||||
| from django.utils.functional import cached_property | from django.utils.functional import cached_property | ||||||
| from django.conf import settings | from django.conf import settings | ||||||
| 
 | 
 | ||||||
|  | from django.conf import settings | ||||||
|  | 
 | ||||||
| from Crypto.PublicKey import RSA | from Crypto.PublicKey import RSA | ||||||
| from stored_messages.settings import stored_messages_settings | from stored_messages.settings import stored_messages_settings | ||||||
| 
 | 
 | ||||||
|  | @ -17,6 +19,8 @@ from .managers import VMPlansManager | ||||||
| from oca.exceptions import OpenNebulaException | from oca.exceptions import OpenNebulaException | ||||||
| from oca.pool import WrongNameError | from oca.pool import WrongNameError | ||||||
| 
 | 
 | ||||||
|  | import logging | ||||||
|  | logger = logging.getLogger(__name__) | ||||||
| 
 | 
 | ||||||
| class VirtualMachineType(models.Model): | class VirtualMachineType(models.Model): | ||||||
| 
 | 
 | ||||||
|  | @ -173,6 +177,83 @@ class VirtualMachinePlan(AssignPermissionsMixin, models.Model): | ||||||
|         self.status = self.CANCELED_STATUS |         self.status = self.CANCELED_STATUS | ||||||
|         self.save(update_fields=['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 | ||||||
|  |         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 | ||||||
|  |         )) | ||||||
|  |         # Get open nebula user id for given email | ||||||
|  |         user_pool = oca.UserPool(oneadmin_client) | ||||||
|  |         user_pool.info() | ||||||
|  |         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) | ||||||
|  |         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): | class HostingOrder(AssignPermissionsMixin, models.Model): | ||||||
| 
 | 
 | ||||||
|  | @ -336,3 +417,12 @@ class HostingBill(AssignPermissionsMixin, models.Model): | ||||||
|         return vms |         return vms | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |          | ||||||
|  | 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 | ||||||
|  |  | ||||||
|  | @ -14,6 +14,7 @@ from django.utils.translation import ugettext_lazy as _ | ||||||
| from oca.exceptions import OpenNebulaException | from oca.exceptions import OpenNebulaException | ||||||
| from oca.pool import WrongNameError | from oca.pool import WrongNameError | ||||||
| 
 | 
 | ||||||
|  | from django import forms | ||||||
| # Get an instance of a logger | # Get an instance of a logger | ||||||
| logger = logging.getLogger(__name__) | logger = logging.getLogger(__name__) | ||||||
| 
 | 
 | ||||||
|  | @ -47,9 +48,9 @@ class HostingManageVMAdmin(admin.ModelAdmin): | ||||||
|                                                   port=settings.OPENNEBULA_PORT, |                                                   port=settings.OPENNEBULA_PORT, | ||||||
|                                                   endpoint=settings.OPENNEBULA_ENDPOINT |                                                   endpoint=settings.OPENNEBULA_ENDPOINT | ||||||
|                                               )) |                                               )) | ||||||
|             print("{0}:{1}".format(settings.OPENNEBULA_USERNAME, |             logger.debug("{0}:{1}".format(settings.OPENNEBULA_USERNAME, | ||||||
|                                    settings.OPENNEBULA_PASSWORD)) |                                    settings.OPENNEBULA_PASSWORD)) | ||||||
|             print("{protocol}://{domain}:{port}{endpoint}".format( |             logger.debug("{protocol}://{domain}:{port}{endpoint}".format( | ||||||
|                 protocol=settings.OPENNEBULA_PROTOCOL, |                 protocol=settings.OPENNEBULA_PROTOCOL, | ||||||
|                 domain=settings.OPENNEBULA_DOMAIN, |                 domain=settings.OPENNEBULA_DOMAIN, | ||||||
|                 port=settings.OPENNEBULA_PORT, |                 port=settings.OPENNEBULA_PORT, | ||||||
|  | @ -58,7 +59,8 @@ class HostingManageVMAdmin(admin.ModelAdmin): | ||||||
|             self.create_opennebula_user(request) |             self.create_opennebula_user(request) | ||||||
|         if self.client is None: |         if self.client is None: | ||||||
|             opennebula_user = request.user.email |             opennebula_user = request.user.email | ||||||
|             opennebula_user_password = get_random_password() |             # TODO: get the password stored in django | ||||||
|  |             opennebula_user_password ='19737450' | ||||||
|             self.client = oca.Client("{0}:{1}".format(opennebula_user, opennebula_user_password), |             self.client = oca.Client("{0}:{1}".format(opennebula_user, opennebula_user_password), | ||||||
|                                      "{protocol}://{domain}:{port}{endpoint}".format( |                                      "{protocol}://{domain}:{port}{endpoint}".format( | ||||||
|                                          protocol=settings.OPENNEBULA_PROTOCOL, |                                          protocol=settings.OPENNEBULA_PROTOCOL, | ||||||
|  | @ -84,6 +86,7 @@ class HostingManageVMAdmin(admin.ModelAdmin): | ||||||
|             # Include common variables for rendering the admin template. |             # Include common variables for rendering the admin template. | ||||||
|             self.admin_site.each_context(request), |             self.admin_site.each_context(request), | ||||||
|             vms=vm_pool, |             vms=vm_pool, | ||||||
|  |             form=HostingManageVMForm | ||||||
|         ) |         ) | ||||||
|         return TemplateResponse(request, "hosting/managevms.html", context) |         return TemplateResponse(request, "hosting/managevms.html", context) | ||||||
| 
 | 
 | ||||||
|  | @ -292,14 +295,60 @@ class HostingManageVMAdmin(admin.ModelAdmin): | ||||||
|             opennebula_user = user_pool.get_by_name(request.user.email) |             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)) |             logger.debug("User {0} exists. User id = {1}".format(request.user.email, opennebula_user.id)) | ||||||
|         except WrongNameError as wrong_name_err: |         except WrongNameError as wrong_name_err: | ||||||
|             user_id = self.oneadmin_client.call('user.allocate', request.user.email, get_random_password(), |             # TODO: Store this password so that we can use it later to  | ||||||
|                                                 'dummy') |             # 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) |             logger.debug("User {0} does not exist. Created the user. User id = {1}", request.user.email, user_id) | ||||||
|         except OpenNebulaException as err: |         except OpenNebulaException as err: | ||||||
|             messages.add_message(request, messages.ERROR, |             messages.add_message(request, messages.ERROR, | ||||||
|                                  "Error : {0}".format(err)) |                                  "Error : {0}".format(err)) | ||||||
|             logger.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 | # Returns random password that is needed by OpenNebula | ||||||
| def get_random_password(): | def get_random_password(): | ||||||
|  |  | ||||||
|  | @ -2,13 +2,9 @@ | ||||||
| {% block content %} | {% block content %} | ||||||
| 
 | 
 | ||||||
| <form action="{% url 'admin:createvm' %}" method="post"> | <form action="{% url 'admin:createvm' %}" method="post"> | ||||||
| 	{% csrf_token %} |     {% csrf_token %} | ||||||
| 	<select id="vm_template" name="vm_template"> |     {{ form }} | ||||||
| 		<option value="select">Select a template</option> |     <input type="submit" name="create_vm" value="Create VM" /> | ||||||
| 		<option value="1">disk = 10GB, vcpu=0.1, ram=1GB</option> |  | ||||||
| 		<option value="2">disk = 20GB, vcpu=0.2, ram=2GB</option> |  | ||||||
| 	</select> |  | ||||||
| 	<input type="submit" name="create_vm" value="Create VM" /> |  | ||||||
| </form> | </form> | ||||||
| {% if vms %} | {% if vms %} | ||||||
| <section> | <section> | ||||||
|  |  | ||||||
|  | @ -415,8 +415,9 @@ class VirtualMachinesPlanListView(LoginRequiredMixin, ListView): | ||||||
|     ordering = '-id' |     ordering = '-id' | ||||||
| 
 | 
 | ||||||
|     def get_queryset(self): |     def get_queryset(self): | ||||||
|         hosting_admin = HostingManageVMAdmin.__new__(HostingManageVMAdmin) |         # hosting_admin = HostingManageVMAdmin.__new__(HostingManageVMAdmin) | ||||||
|         print(hosting_admin.show_vms_view(self.request)) |         # print(hosting_admin.show_vms_view(self.request)) | ||||||
|  |         print(VirtualMachinePlan.get_vms(self.request.user.email)) | ||||||
|         user = self.request.user |         user = self.request.user | ||||||
|         self.queryset = VirtualMachinePlan.objects.active(user) |         self.queryset = VirtualMachinePlan.objects.active(user) | ||||||
|         return super(VirtualMachinesPlanListView, self).get_queryset() |         return super(VirtualMachinesPlanListView, self).get_queryset() | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue